Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
R
re6stnet
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
zhifan huang
re6stnet
Commits
d7a4d73f
Commit
d7a4d73f
authored
Jul 01, 2018
by
Julien Muchembled
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New option to prevent tunnelling accross borders of listed countries
parent
6b45d7ea
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
147 additions
and
27 deletions
+147
-27
debian/control
debian/control
+1
-1
debian/init.d
debian/init.d
+3
-0
debian/rules
debian/rules
+1
-1
re6st/cache.py
re6st/cache.py
+41
-12
re6st/cli/registry.py
re6st/cli/registry.py
+3
-1
re6st/registry.py
re6st/registry.py
+6
-4
re6st/tunnel.py
re6st/tunnel.py
+88
-7
re6st/version.py
re6st/version.py
+1
-1
setup.py
setup.py
+3
-0
No files found.
debian/control
View file @
d7a4d73f
...
...
@@ -10,7 +10,7 @@ Package: re6stnet
Architecture: all
Depends: ${misc:Depends}, ${python:Depends}, python-pkg-resources, python-openssl (>= 0.13), openvpn (>= 2.3), babeld (= 1.6.2-nxd1), iproute2 | iproute, openssl
Recommends: ${python:Recommends}, logrotate
Suggests: ndisc6
Suggests:
${python:Suggests},
ndisc6
Conflicts: re6st-node
Replaces: re6st-node
Description: resilient, scalable, IPv6 network application
debian/init.d
View file @
d7a4d73f
...
...
@@ -31,6 +31,9 @@ SCRIPTNAME=/etc/init.d/$NAME
#
do_start
()
{
if
[
-
r
$
CONFDIR
/
GeoLite2
-
Country
.
mmdb
]
then
export
GEOIP2_MMDB
=$
CONFDIR
/
GeoLite2
-
Country
.
mmdb
fi
#
Return
#
0
if
daemon
has
been
started
#
1
if
daemon
was
already
running
...
...
debian/rules
View file @
d7a4d73f
...
...
@@ -15,7 +15,7 @@ include debian/common.mk
override_dh_python2
:
sed
-i
/^miniupnpc
$$
/d
`
find
$(TMP)
/usr
-name
requires.txt
`
dh_python2
--recommends
=
miniupnpc
dh_python2
--recommends
=
miniupnpc
--suggests
=
geoip2
override_dh_auto_clean
:
make clean
...
...
re6st/cache.py
View file @
d7a4d73f
import
json
,
logging
,
os
,
sqlite3
,
socket
,
subprocess
,
sys
,
time
,
zlib
from
itertools
import
chain
from
.registry
import
RegistryClient
from
.
import
utils
,
version
,
x509
class
Cache
(
object
):
crl
=
()
def
__init__
(
self
,
db_path
,
registry
,
cert
,
db_size
=
200
):
self
.
_prefix
=
cert
.
prefix
self
.
_db_size
=
db_size
...
...
@@ -25,7 +24,8 @@ class Cache(object):
peer TEXT PRIMARY KEY NOT NULL,
try INTEGER NOT NULL DEFAULT 0)"""
)
q
(
"CREATE INDEX volatile.stat_try ON stat(try)"
)
q
(
"INSERT INTO volatile.stat (peer) SELECT prefix FROM peer"
)
q
(
"INSERT INTO volatile.stat (peer)"
" SELECT prefix FROM peer WHERE prefix"
)
self
.
_db
.
commit
()
self
.
_loadConfig
(
self
.
_selectConfig
(
q
))
try
:
...
...
@@ -71,10 +71,16 @@ class Cache(object):
def
_loadConfig
(
self
,
config
):
cls
=
self
.
__class__
logging
.
debug
(
"Loading network parameters:"
)
self
.
crl
=
self
.
same_country
=
()
for
k
,
v
in
config
:
if
k
==
'crl'
:
v
=
set
(
json
.
loads
(
v
))
elif
hasattr
(
cls
,
k
):
if
k
==
'crl'
:
# BBB
k
=
'crl:json'
if
k
.
endswith
(
':json'
):
k
=
k
[:
-
5
]
v
=
json
.
loads
(
v
)
if
k
==
'crl'
:
v
=
set
(
v
)
if
hasattr
(
cls
,
k
):
continue
setattr
(
self
,
k
,
v
)
logging
.
debug
(
"- %s: %r"
,
k
,
v
)
...
...
@@ -83,13 +89,20 @@ class Cache(object):
logging
.
info
(
"Getting new network parameters from registry..."
)
try
:
# TODO: When possible, the registry should be queried via the re6st.
config
=
json
.
loads
(
zlib
.
decompress
(
x
=
json
.
loads
(
zlib
.
decompress
(
self
.
_registry
.
getNetworkConfig
(
self
.
_prefix
)))
base64
=
config
.
pop
(
''
,
())
config
=
dict
((
str
(
k
),
v
.
decode
(
'base64'
)
if
k
in
base64
else
str
(
v
)
if
type
(
v
)
is
unicode
else
v
)
for
k
,
v
in
config
.
iteritems
())
config
[
'crl'
]
=
json
.
dumps
(
config
[
'crl'
])
base64
=
x
.
pop
(
''
,
())
config
=
{}
for
k
,
v
in
x
.
iteritems
():
k
=
str
(
k
)
if
k
in
base64
:
v
=
v
.
decode
(
'base64'
)
elif
type
(
v
)
is
unicode
:
v
=
str
(
v
)
elif
isinstance
(
v
,
(
list
,
dict
)):
k
+=
':json'
v
=
json
.
dumps
(
v
)
config
[
k
]
=
v
except
socket
.
error
,
e
:
logging
.
warning
(
e
)
return
...
...
@@ -186,6 +199,22 @@ class Cache(object):
(
prefix
,)).
fetchone
()
return
r
and
r
[
0
]
@
property
def
my_address
(
self
):
for
x
,
in
self
.
_db
.
execute
(
"SELECT address FROM peer WHERE NOT prefix"
):
return
x
return
''
@
my_address
.
setter
def
my_address
(
self
,
*
args
):
with
self
.
_db
as
db
:
db
.
execute
(
"INSERT OR REPLACE INTO peer VALUES ('', ?)"
,
args
)
@
my_address
.
deleter
def
my_address
(
self
):
with
self
.
_db
as
db
:
db
.
execute
(
"DELETE FROM peer WHERE NOT prefix"
)
# Exclude our own address from results in case it is there, which may
# happen if a node change its certificate without clearing the cache.
# IOW, one should probably always put our own address there.
...
...
re6st/cli/registry.py
View file @
d7a4d73f
...
...
@@ -5,7 +5,7 @@ from SocketServer import ThreadingTCPServer
from
urlparse
import
parse_qsl
if
're6st'
not
in
sys
.
modules
:
sys
.
path
[
0
]
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
sys
.
path
[
0
]))
from
re6st
import
ctl
,
registry
,
utils
,
version
from
re6st
import
registry
,
utils
,
version
# To generate server ca and key with serial for 2001:db8:42::/48
# openssl req -nodes -new -x509 -key ca.key -set_serial 0x120010db80042 -days 3650 -out ca.crt
...
...
@@ -132,6 +132,8 @@ def main():
help
=
"Interval in seconds between two tunnel refresh: the worst"
" tunnel is closed if the number of client tunnels has reached"
" its maximum number (client-count)."
)
_
(
'--same-country'
,
action
=
'append'
,
metavar
=
"CODE"
,
help
=
"prevent tunnelling accross borders of listed countries"
)
config
=
parser
.
parse_args
()
...
...
re6st/registry.py
View file @
d7a4d73f
...
...
@@ -76,11 +76,11 @@ class RegistryServer(object):
"email TEXT NOT NULL"
,
"prefix_len INTEGER NOT NULL"
,
"date INTEGER NOT NULL"
)
if
utils
.
sqliteCreateTable
(
self
.
db
,
"cert"
,
utils
.
sqliteCreateTable
(
self
.
db
,
"cert"
,
"prefix TEXT PRIMARY KEY NOT NULL"
,
"email TEXT"
,
"cert TEXT"
)
:
self
.
db
.
execute
(
"INSERT
INTO cert VALUES ('',null,null)"
)
"cert TEXT"
)
self
.
db
.
execute
(
"INSERT OR IGNORE
INTO cert VALUES ('',null,null)"
)
utils
.
sqliteCreateTable
(
self
.
db
,
"crl"
,
"serial INTEGER PRIMARY KEY NOT NULL"
,
# Expiration date of revoked certificate.
...
...
@@ -122,6 +122,8 @@ class RegistryServer(object):
}
if
self
.
config
.
ipv4
:
kw
[
'ipv4'
],
kw
[
'ipv4_sublen'
]
=
self
.
config
.
ipv4
if
self
.
config
.
same_country
:
kw
[
'same_country'
]
=
self
.
config
.
same_country
for
x
in
(
'client_count'
,
'encrypt'
,
'hello'
,
'max_clients'
,
'min_protocol'
,
'tunnel_refresh'
):
kw
[
x
]
=
getattr
(
self
.
config
,
x
)
...
...
@@ -138,7 +140,7 @@ class RegistryServer(object):
# Example to avoid all nodes to restart at the same time:
# kw['delay_restart'] = 600 * random.random()
kw
[
'version'
]
=
self
.
version
.
encode
(
'base64'
)
self
.
network_config
=
zlib
.
compress
(
json
.
dumps
(
kw
))
self
.
network_config
=
zlib
.
compress
(
json
.
dumps
(
kw
)
,
9
)
# The 3 first bits code the number of bytes.
def
encodeVersion
(
self
,
version
):
...
...
re6st/tunnel.py
View file @
d7a4d73f
import
errno
,
json
,
logging
,
os
,
random
import
s
ocket
,
subprocess
,
struct
,
time
,
weakref
import
errno
,
json
,
logging
,
os
,
random
,
socket
import
s
ubprocess
,
struct
,
sys
,
time
,
weakref
from
collections
import
defaultdict
,
deque
from
bisect
import
bisect
,
insort
from
OpenSSL
import
crypto
...
...
@@ -7,6 +7,27 @@ from . import ctl, plib, rina, utils, version, x509
PORT
=
326
family_dict
=
{
socket
.
AF_INET
:
'IPv4'
,
socket
.
AF_INET6
:
'IPv6'
,
}
proto_dict
=
{
'tcp4'
:
(
socket
.
AF_INET
,
socket
.
SOL_TCP
),
'udp4'
:
(
socket
.
AF_INET
,
socket
.
SOL_UDP
),
'tcp6'
:
(
socket
.
AF_INET6
,
socket
.
SOL_TCP
),
'udp6'
:
(
socket
.
AF_INET6
,
socket
.
SOL_UDP
),
}
proto_dict
[
'tcp'
]
=
proto_dict
[
'tcp4'
]
proto_dict
[
'udp'
]
=
proto_dict
[
'udp4'
]
def
resolve
(
ip
,
port
,
proto
):
try
:
family
,
proto
=
proto_dict
[
proto
]
except
KeyError
:
return
None
,
()
return
family
,
(
x
[
-
1
][
0
]
for
x
in
socket
.
getaddrinfo
(
ip
,
port
,
family
,
0
,
proto
))
class
MultiGatewayManager
(
dict
):
...
...
@@ -172,6 +193,7 @@ class BaseTunnelManager(object):
NEED_RESTART
=
frozenset
((
'babel_default'
,
'encrypt'
,
'hello'
,
'ipv4'
,
'ipv4_sublen'
))
_geoiplookup
=
None
_forward
=
None
_next_rina
=
True
...
...
@@ -188,6 +210,31 @@ class BaseTunnelManager(object):
address_dict
=
defaultdict
(
list
)
for
family
,
address
in
address
:
address_dict
[
family
]
+=
address
if
any
(
address_dict
.
itervalues
()):
del
cache
.
my_address
else
:
for
address
in
utils
.
parse_address
(
cache
.
my_address
):
try
:
proto
=
proto_dict
[
address
[
2
]]
except
KeyError
:
continue
address_dict
[
proto
[
0
]].
append
(
address
)
db
=
os
.
getenv
(
'GEOIP2_MMDB'
)
if
db
:
from
geoip2
import
database
,
errors
country
=
database
.
Reader
(
db
).
country
def
geoiplookup
(
ip
):
try
:
return
country
(
ip
).
country
.
iso_code
except
errors
.
AddressNotFoundError
:
return
self
.
_geoiplookup
=
geoiplookup
self
.
_country
=
{}
for
address
in
address_dict
.
itervalues
():
self
.
_updateCountry
(
address
)
elif
cache
.
same_country
:
sys
.
exit
(
"Can not respect 'same_country' network configuration"
" (GEOIP2_MMDB not set)"
)
self
.
_address
=
dict
((
family
,
utils
.
dump_address
(
address
))
for
family
,
address
in
address_dict
.
iteritems
()
if
address
)
...
...
@@ -589,11 +636,23 @@ class BaseTunnelManager(object):
'
\
7
%s (%s)'
%
(
msg
,
os
.
uname
()[
2
]))
break
def
_updateCountry
(
self
,
address
):
for
address
in
address
:
family
,
ip
=
resolve
(
*
address
)
for
ip
in
ip
:
country
=
self
.
_geoiplookup
(
ip
)
if
country
:
if
self
.
_country
.
get
(
family
)
!=
country
:
self
.
_country
[
family
]
=
country
logging
.
info
(
'%s country: %s'
,
family_dict
[
family
],
country
)
return
class
TunnelManager
(
BaseTunnelManager
):
NEED_RESTART
=
BaseTunnelManager
.
NEED_RESTART
.
union
((
'client_count'
,
'max_clients'
,
'tunnel_refresh'
))
'client_count'
,
'max_clients'
,
'
same_country'
,
'
tunnel_refresh'
))
def
__init__
(
self
,
control_socket
,
cache
,
cert
,
openvpn_args
,
timeout
,
client_count
,
iface_list
,
address
,
ip_changed
,
...
...
@@ -780,16 +839,35 @@ class TunnelManager(BaseTunnelManager):
if
prefix
in
self
.
_served
or
prefix
in
self
.
_connection_dict
:
return
False
assert
prefix
!=
self
.
_prefix
,
self
.
__dict__
address
=
[
x
for
x
in
utils
.
parse_address
(
address
)
if
x
[
2
]
not
in
self
.
_disable_proto
]
address_list
=
[]
same_country
=
self
.
cache
.
same_country
for
x
in
utils
.
parse_address
(
address
):
if
x
[
2
]
in
self
.
_disable_proto
:
continue
if
same_country
:
family
,
ip
=
resolve
(
*
x
)
my_country
=
self
.
_country
.
get
(
family
)
if
my_country
:
for
ip
in
ip
:
country
=
self
.
_geoiplookup
(
ip
)
if
country
and
(
country
!=
my_country
if
my_country
in
same_country
else
country
in
same_country
):
logging
.
debug
(
'Do not tunnel to %s (%s -> %s)'
,
ip
,
my_country
,
country
)
else
:
address_list
.
append
((
ip
,
x
[
1
],
x
[
2
]))
continue
address_list
.
append
(
x
)
self
.
cache
.
connecting
(
prefix
,
1
)
if
not
address
:
if
not
address
_list
:
return
False
logging
.
info
(
'Establishing a connection with %u/%u'
,
int
(
prefix
,
2
),
len
(
prefix
))
with
utils
.
exit
:
iface
=
self
.
_getFreeInterface
(
prefix
)
self
.
_connection_dict
[
prefix
]
=
c
=
Connection
(
self
,
address
,
iface
,
prefix
)
self
.
_connection_dict
[
prefix
]
=
c
=
Connection
(
self
,
address_list
,
iface
,
prefix
)
if
self
.
_gateway_manager
is
not
None
:
for
ip
in
c
:
self
.
_gateway_manager
.
add
(
ip
,
True
)
...
...
@@ -917,6 +995,9 @@ class TunnelManager(BaseTunnelManager):
family
,
address
=
self
.
_ip_changed
(
ip
)
if
address
:
self
.
_address
[
family
]
=
utils
.
dump_address
(
address
)
if
self
.
_geoiplookup
:
self
.
_updateCountry
(
address
)
self
.
cache
.
my_address
=
';'
.
join
(
self
.
_address
.
itervalues
())
def
broadcastNewVersion
(
self
):
self
.
_babel_dump_new_version
()
...
...
re6st/version.py
View file @
d7a4d73f
...
...
@@ -32,7 +32,7 @@ if dirty:
# they are intended to the network admin.
# Only 'protocol' is important and it must be increased whenever they would be
# a wish to force an update of nodes.
protocol
=
3
protocol
=
4
min_protocol
=
1
if
__name__
==
"__main__"
:
...
...
setup.py
View file @
d7a4d73f
...
...
@@ -93,6 +93,9 @@ setup(
# BBB: use MANIFEST.in only so that egg_info works with very old setuptools
include_package_data
=
True
,
install_requires
=
[
'pyOpenSSL >= 0.13'
,
'miniupnpc'
],
extras_require
=
{
'geoip'
:
[
'geoip2'
],
},
#dependency_links = [
# "http://miniupnp.free.fr/files/download.php?file=miniupnpc-1.7.20120714.tar.gz#egg=miniupnpc-1.7",
# ],
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment