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
Xiaowu Zhang
re6stnet
Commits
b1e97826
Commit
b1e97826
authored
Aug 29, 2012
by
Julien Muchembled
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bugfixes
parent
b3cb14da
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
202 additions
and
199 deletions
+202
-199
docs/re6st-registry.rst
docs/re6st-registry.rst
+1
-0
docs/re6stnet.rst
docs/re6stnet.rst
+15
-11
re6st-registry
re6st-registry
+22
-25
re6st/db.py
re6st/db.py
+22
-18
re6st/plib.py
re6st/plib.py
+31
-17
re6st/tunnel.py
re6st/tunnel.py
+7
-14
re6st/upnpigd.py
re6st/upnpigd.py
+29
-38
re6st/utils.py
re6st/utils.py
+12
-1
re6stnet
re6stnet
+63
-75
No files found.
docs/re6st-registry.rst
View file @
b1e97826
...
...
@@ -33,6 +33,7 @@ request.
--port port
The port on which the server will listen
Default: 80
--db path
Path to the server Database file. A new DB file will be created
...
...
docs/re6stnet.rst
View file @
b1e97826
...
...
@@ -72,10 +72,10 @@ Generic options
file ( since it is an optioin, it must be alone on the line ).
--ip address port proto
Specify connection information to be advertised to other nodes.
address MUST be a ipv4 address since as of now openvpn does not
support ipv6 addresses.
Proto should be either udp or tcp-client
IP address advertised to other nodes. Special values:
- upnp: force autoconfiguration via UPnP
- any: ask peers our IP
Default: ask peers if UPnP fails
-l, ``--log`` `directory`
Path to the directory used for log files. Will create one file
...
...
@@ -103,6 +103,12 @@ Generic options
Babel options
~~~~~~~~~~~~~
--babel-pidfile
Specify a file to write our process id to (option -I of Babel).
--babel-verb
Babel verbosity (option -d of Babel).
-i, ``--interface`` `interface`
Give one interface name for each use of the argument. The interface
will be used to detect other nodes on the local network.
...
...
@@ -135,13 +141,11 @@ Tunnel & Peers options
Default : 3600 ( 1 hour )
--pp port proto
Port and protocol used by the openvpn server(s). Start one openvpn
server for each couple port/protocol specified.
Additionally, if no external configuration is given in the command
line, re6stnet will attempt to forward a port with upnp for each
couple port/proto given.
Protocols should be either udp or tcp-server.
Default : (1194, udp), (1194, tcp-server)
Port and protocol to be announced to other peers, ordered by
preference. For each protocol, start one openvpn server on the
first given port.
Protocols: udp, tcp
Default : --pp 1194 udp --pp 1194 tcp
--tunnel-refresh duration
Interval in seconds between two tunnel refresh. Refreshing tunnels
...
...
re6st-registry
View file @
b1e97826
#!/usr/bin/env python
import
argparse
,
random
,
select
,
smtplib
,
sqlite3
,
string
,
socket
import
random
,
select
,
smtplib
,
sqlite3
,
string
,
socket
import
subprocess
,
time
,
threading
,
traceback
,
errno
,
logging
,
os
,
xmlrpclib
from
SimpleXMLRPCServer
import
SimpleXMLRPCServer
,
SimpleXMLRPCRequestHandler
from
email.mime.text
import
MIMEText
...
...
@@ -15,18 +15,18 @@ SOL_IPV6 = 41
class
RequestHandler
(
SimpleXMLRPCRequestHandler
):
def
address_string
(
self
):
# Workaround for http://bugs.python.org/issue6085
return
self
.
client_address
[
0
]
def
_dispatch
(
self
,
method
,
params
):
logging
.
debug
(
'%s%r'
,
method
,
params
)
return
self
.
server
.
_dispatch
(
method
,
(
self
,)
+
params
)
class
SimpleXMLRPCServer4
(
SimpleXMLRPCServer
):
allow_reuse_address
=
True
def
address_string
(
self
):
# Workaround for http://bugs.python.org/issue6085
return
self
.
client_address
[
0
]
class
SimpleXMLRPCServer6
(
SimpleXMLRPCServer4
):
...
...
@@ -48,10 +48,10 @@ class main(object):
utils
.
setupLog
(
3
)
# Command line parsing
parser
=
argparse
.
ArgumentParser
(
parser
=
utils
.
ArgParser
(
fromfile_prefix_chars
=
'@'
,
description
=
'Peer discovery http server for re6stnet'
)
_
=
parser
.
add_argument
_
(
'--port'
,
required
=
True
,
type
=
int
,
help
=
'Port of the host server'
)
_
(
'--port'
,
type
=
int
,
default
=
80
,
help
=
'Port of the host server'
)
_
(
'--db'
,
required
=
True
,
help
=
'Path to database file'
)
_
(
'--ca'
,
required
=
True
,
...
...
@@ -76,21 +76,21 @@ class main(object):
address text not null,
date integer default (strftime('%s','now')))"""
)
self
.
db
.
execute
(
"CREATE INDEX IF NOT EXISTS peers_ping ON peers(date)"
)
self
.
db
.
execute
(
"""CREATE TABLE IF NOT EXISTS token
s
(
self
.
db
.
execute
(
"""CREATE TABLE IF NOT EXISTS token (
token text primary key not null,
email text not null,
prefix_len integer not null,
date integer not null)"""
)
try
:
self
.
db
.
execute
(
"""CREATE TABLE
vpn
(
self
.
db
.
execute
(
"""CREATE TABLE
cert
(
prefix text primary key not null,
email text,
cert text)"""
)
except
sqlite3
.
OperationalError
,
e
:
if
e
.
args
[
0
]
!=
'table
vpn
already exists'
:
if
e
.
args
[
0
]
!=
'table
cert
already exists'
:
raise
RuntimeError
else
:
self
.
db
.
execute
(
"INSERT INTO
vpn
VALUES ('',null,null)"
)
self
.
db
.
execute
(
"INSERT INTO
cert
VALUES ('',null,null)"
)
# Loading certificates
with
open
(
self
.
config
.
ca
)
as
f
:
...
...
@@ -124,7 +124,7 @@ class main(object):
token
=
''
.
join
(
random
.
sample
(
string
.
ascii_lowercase
,
8
))
# Updating database
try
:
self
.
db
.
execute
(
"INSERT INTO token
s
VALUES (?,?,?,?)"
,
(
token
,
email
,
16
,
int
(
time
.
time
())))
self
.
db
.
execute
(
"INSERT INTO token VALUES (?,?,?,?)"
,
(
token
,
email
,
16
,
int
(
time
.
time
())))
break
except
sqlite3
.
IntegrityError
:
pass
...
...
@@ -143,18 +143,18 @@ class main(object):
max_len
=
128
-
len
(
self
.
network
)
assert
0
<
prefix_len
<=
max_len
try
:
prefix
,
=
self
.
db
.
execute
(
"""SELECT prefix FROM
vpn
WHERE length(prefix) <= ? AND cert is null
prefix
,
=
self
.
db
.
execute
(
"""SELECT prefix FROM
cert
WHERE length(prefix) <= ? AND cert is null
ORDER BY length(prefix) DESC"""
,
(
prefix_len
,)).
next
()
except
StopIteration
:
logging
.
error
(
'There are no more free /%s prefix available'
%
(
prefix_len
,))
raise
while
len
(
prefix
)
<
prefix_len
:
self
.
db
.
execute
(
"UPDATE
vpn
SET prefix = ? WHERE prefix = ?"
,
(
prefix
+
'1'
,
prefix
))
self
.
db
.
execute
(
"UPDATE
cert
SET prefix = ? WHERE prefix = ?"
,
(
prefix
+
'1'
,
prefix
))
prefix
+=
'0'
self
.
db
.
execute
(
"INSERT INTO
vpn
VALUES (?,null,null)"
,
(
prefix
,))
self
.
db
.
execute
(
"INSERT INTO
cert
VALUES (?,null,null)"
,
(
prefix
,))
if
len
(
prefix
)
<
max_len
or
'1'
in
prefix
:
return
prefix
self
.
db
.
execute
(
"UPDATE
vpn
SET cert = 'reserved' WHERE prefix = ?"
,
(
prefix
,))
self
.
db
.
execute
(
"UPDATE
cert
SET cert = 'reserved' WHERE prefix = ?"
,
(
prefix
,))
return
self
.
_getPrefix
(
prefix_len
)
def
requestCertificate
(
self
,
handler
,
token
,
cert_req
):
...
...
@@ -162,11 +162,11 @@ class main(object):
req
=
crypto
.
load_certificate_request
(
crypto
.
FILETYPE_PEM
,
cert_req
)
with
self
.
db
:
try
:
token
,
email
,
prefix_len
,
_
=
self
.
db
.
execute
(
"SELECT * FROM token
s
WHERE token = ?"
,
(
token
,)).
next
()
token
,
email
,
prefix_len
,
_
=
self
.
db
.
execute
(
"SELECT * FROM token WHERE token = ?"
,
(
token
,)).
next
()
except
StopIteration
:
logging
.
exception
(
'Bad token (%s) in request'
%
(
token
,))
raise
self
.
db
.
execute
(
"DELETE FROM token
s
WHERE token = ?"
,
(
token
,))
self
.
db
.
execute
(
"DELETE FROM token WHERE token = ?"
,
(
token
,))
# Get a new prefix
prefix
=
self
.
_getPrefix
(
prefix_len
)
...
...
@@ -185,7 +185,7 @@ class main(object):
cert
=
crypto
.
dump_certificate
(
crypto
.
FILETYPE_PEM
,
cert
)
# Insert certificate into db
self
.
db
.
execute
(
"UPDATE
vpn
SET email = ?, cert = ? WHERE prefix = ?"
,
(
email
,
cert
,
prefix
))
self
.
db
.
execute
(
"UPDATE
cert
SET email = ?, cert = ? WHERE prefix = ?"
,
(
email
,
cert
,
prefix
))
return
cert
except
:
...
...
@@ -199,16 +199,14 @@ class main(object):
return
'http://[%s]:%u'
%
(
self
.
config
.
private
,
self
.
config
.
port
)
def
getBootstrapPeer
(
self
,
handler
,
client_prefix
):
cert
,
=
self
.
db
.
execute
(
"SELECT cert FROM
vpn
WHERE prefix = ?"
,
cert
,
=
self
.
db
.
execute
(
"SELECT cert FROM
cert
WHERE prefix = ?"
,
(
client_prefix
,)).
next
()
logging
.
trace
(
'Getting bootpeer info...'
)
try
:
prefix
,
address
=
self
.
db
.
execute
(
"""SELECT prefix, address FROM peers
WHERE prefix != ? ORDER BY random() LIMIT 1"""
,
(
client_prefix
,)).
next
()
except
StopIteration
:
logging
.
info
(
'No peer to send for bootstrap'
)
raise
logging
.
trace
(
'Gotten bootpeer info from db'
)
r
,
w
=
os
.
pipe
()
try
:
threading
.
Thread
(
target
=
os
.
write
,
args
=
(
w
,
cert
)).
start
()
...
...
@@ -221,12 +219,11 @@ class main(object):
os
.
close
(
w
)
def
declare
(
self
,
handler
,
address
):
print
"declaring new node"
client_address
,
_
,
_
,
_
=
handler
.
client_address
client_ip
=
utils
.
binFromIp
(
client_address
)
if
client_ip
.
startswith
(
self
.
network
):
prefix
=
client_ip
[
len
(
self
.
network
):]
prefix
,
=
self
.
db
.
execute
(
"SELECT prefix FROM
vpn
WHERE prefix <= ? ORDER BY prefix DESC LIMIT 1"
,
(
prefix
,)).
next
()
prefix
,
=
self
.
db
.
execute
(
"SELECT prefix FROM
cert
WHERE prefix <= ? ORDER BY prefix DESC LIMIT 1"
,
(
prefix
,)).
next
()
self
.
db
.
execute
(
"INSERT OR REPLACE INTO peers (prefix, address) VALUES (?,?)"
,
(
prefix
,
address
))
return
True
else
:
...
...
re6st/db.py
View file @
b1e97826
...
...
@@ -10,7 +10,7 @@ class PeerManager:
# internal ip = temp arg/attribute
def
__init__
(
self
,
db_path
,
registry
,
key_path
,
refresh_time
,
address
,
internal_ip
,
prefix
,
manual
,
pp
,
db_size
):
internal_ip
,
prefix
,
ip_changed
,
db_size
):
self
.
_refresh_time
=
refresh_time
self
.
address
=
address
self
.
_internal_ip
=
internal_ip
...
...
@@ -18,8 +18,7 @@ class PeerManager:
self
.
db_size
=
db_size
self
.
_registry
=
registry
self
.
_key_path
=
key_path
self
.
_pp
=
pp
self
.
_manual
=
manual
self
.
_ip_changed
=
ip_changed
self
.
tunnel_manager
=
None
self
.
sock
=
socket
.
socket
(
socket
.
AF_INET6
,
socket
.
SOCK_DGRAM
)
...
...
@@ -53,7 +52,15 @@ class PeerManager:
a
,
=
self
.
_db
.
execute
(
"SELECT value FROM config WHERE name='registry'"
).
next
()
except
StopIteration
:
proxy
=
xmlrpclib
.
ServerProxy
(
registry
)
a
=
proxy
.
getPrivateAddress
()
retry
=
1
while
True
:
try
:
a
=
proxy
.
getPrivateAddress
()
break
except
socket
.
error
,
e
:
logging
.
warning
(
e
)
time
.
sleep
(
retry
)
retry
=
min
(
60
,
retry
*
2
)
self
.
_db
.
execute
(
"INSERT INTO config VALUES ('registry',?)"
,
(
a
,))
self
.
_proxy
=
xmlrpclib
.
ServerProxy
(
a
)
logging
.
debug
(
'Database prepared'
)
...
...
@@ -97,7 +104,7 @@ class PeerManager:
self
.
next_refresh
=
time
.
time
()
+
self
.
_refresh_time
logging
.
debug
(
'Info sent'
)
else
:
logging
.
warning
(
"
Warning : couldn'
t send ip, unknown external config. retrying in 30s"
)
logging
.
warning
(
"
Could no
t send ip, unknown external config. retrying in 30s"
)
def
getUnusedPeers
(
self
,
peer_count
):
for
populate
in
self
.
_bootstrap
,
bool
:
...
...
@@ -107,7 +114,7 @@ class PeerManager:
if
peer_list
:
return
peer_list
populate
()
logging
.
warning
(
'Can
not find any new peers
'
)
logging
.
warning
(
'Can
not find any new peer
'
)
return
[]
def
_bootstrap
(
self
):
...
...
@@ -152,22 +159,19 @@ class PeerManager:
self
.
whitelist
(
utils
.
binFromSubnet
(
arg
))
logging
.
info
(
'%s has disconnected'
%
(
arg
,))
elif
script_type
==
'route-up'
:
if
not
self
.
_manual
:
external_ip
=
arg
new_address
=
list
([
external_ip
,
port
,
proto
]
for
port
,
proto
,
_
in
self
.
_pp
)
if
self
.
address
!=
new_address
:
self
.
address
=
new_address
logging
.
info
(
'Received new external ip : %s'
%
(
external_ip
,))
if
self
.
_ip_changed
:
address
=
self
.
_ip_changed
(
arg
)
if
self
.
address
!=
address
:
self
.
address
=
address
logging
.
info
(
'Received new external ip : %s'
,
arg
)
try
:
self
.
_declare
()
except
socket
.
error
,
e
:
logging
.
debug
(
'socket.error : %s'
%
e
)
logging
.
info
(
"""Connection to server failed while declaring external infos"""
)
logging
.
info
(
"Connection to server failed while"
" declaring external infos (%s)"
,
e
)
else
:
logging
.
debug
(
'Unknow message recieved from the openvpn pipe : %s'
%
msg
)
logging
.
info
(
"Unknown message received from the openvpn pipe: %s"
,
msg
)
def
readSocket
(
self
):
msg
=
self
.
socket_file
.
readline
()
...
...
re6st/plib.py
View file @
b1e97826
import
errno
import
os
import
subprocess
import
logging
import
utils
verbose
=
0
here
=
os
.
path
.
realpath
(
os
.
path
.
dirname
(
__file__
))
ovpn_server
=
os
.
path
.
join
(
here
,
'ovpn-server'
)
ovpn_client
=
os
.
path
.
join
(
here
,
'ovpn-client'
)
def
openvpn
(
hello_interval
,
encrypt
,
*
args
,
**
kw
):
def
openvpn
(
iface
,
hello_interval
,
encrypt
,
*
args
,
**
kw
):
args
=
[
'openvpn'
,
'--dev-type'
,
'tap'
,
'--dev'
,
iface
,
'--persist-tun'
,
'--persist-key'
,
'--script-security'
,
'2'
,
'--user'
,
'nobody'
,
'--ping-exit'
,
str
(
4
*
hello_interval
),
'--group'
,
'nogroup'
,
#'--user', 'nobody',
'--group', 'nogroup',
]
+
list
(
args
)
if
not
encrypt
:
args
.
extend
([
'--cipher'
,
'none'
])
logging
.
trace
(
'%s'
%
(
args
,))
return
subprocess
.
Popen
(
args
,
**
kw
)
logging
.
trace
(
'%r'
,
args
)
fd
=
os
.
open
(
os
.
path
.
join
(
log
,
'%s.log'
%
iface
),
os
.
O_WRONLY
|
os
.
O_CREAT
|
os
.
O_APPEND
)
try
:
return
subprocess
.
Popen
(
args
,
stdout
=
fd
,
stderr
=
subprocess
.
STDOUT
,
**
kw
)
finally
:
os
.
close
(
fd
)
def
server
(
server_ip
,
ip_length
,
max_clients
,
dh_path
,
pipe_fd
,
port
,
proto
,
hello_interval
,
encrypt
,
*
args
,
**
kw
):
def
server
(
iface
,
server_ip
,
ip_length
,
max_clients
,
dh_path
,
pipe_fd
,
port
,
proto
,
hello_interval
,
encrypt
,
*
args
,
**
kw
):
logging
.
debug
(
'Starting server...'
)
if
server_ip
!=
''
:
if
server_ip
:
script_up
=
'%s %s/%u'
%
(
ovpn_server
,
server_ip
,
64
)
else
:
script_up
=
'%s none'
%
(
ovpn_server
)
return
openvpn
(
hello_interval
,
encrypt
,
return
openvpn
(
iface
,
hello_interval
,
encrypt
,
'--tls-server'
,
'--mode'
,
'server'
,
'--up'
,
script_up
,
...
...
@@ -40,11 +45,11 @@ def server(server_ip, ip_length, max_clients, dh_path, pipe_fd, port, proto, hel
'--dh'
,
dh_path
,
'--max-clients'
,
str
(
max_clients
),
'--port'
,
str
(
port
),
'--proto'
,
proto
,
'--proto'
,
'tcp-server'
if
proto
==
'tcp'
else
proto
,
*
args
,
**
kw
)
def
client
(
server_address
,
pipe_fd
,
hello_interval
,
encrypt
,
*
args
,
**
kw
):
def
client
(
iface
,
server_address
,
pipe_fd
,
hello_interval
,
encrypt
,
*
args
,
**
kw
):
logging
.
debug
(
'Starting client...'
)
remote
=
[
'--nobind'
,
'--client'
,
...
...
@@ -52,18 +57,17 @@ def client(server_address, pipe_fd, hello_interval, encrypt, *args, **kw):
'--route-up'
,
ovpn_client
+
' '
+
str
(
pipe_fd
)]
try
:
for
ip
,
port
,
proto
in
utils
.
address_list
(
server_address
):
if
proto
==
'tcp-server'
:
proto
=
'tcp-client'
remote
+=
'--remote'
,
ip
,
port
,
proto
remote
+=
'--remote'
,
ip
,
port
,
\
'tcp-client'
if
proto
==
'tcp'
else
proto
except
ValueError
,
e
:
logging
.
warning
(
'Error "%s" in unpacking address %s for openvpn client'
%
(
e
,
server_address
,))
remote
+=
args
return
openvpn
(
hello_interval
,
encrypt
,
*
remote
,
**
kw
)
return
openvpn
(
iface
,
hello_interval
,
encrypt
,
*
remote
,
**
kw
)
def
router
(
network
,
subnet
,
subnet_size
,
interface_list
,
wireless
,
hello_interval
,
state_path
,
**
kw
):
wireless
,
hello_interval
,
verbose
,
pidfile
,
state_path
,
**
kw
):
logging
.
info
(
'Starting babel...'
)
args
=
[
'babeld'
,
'-C'
,
'redistribute local ip %s/%s le %s'
%
(
subnet
,
subnet_size
,
subnet_size
),
...
...
@@ -86,8 +90,18 @@ def router(network, subnet, subnet_size, interface_list,
'-S'
,
state_path
,
'-s'
,
]
if
pidfile
:
args
+=
'-I'
,
pidfile
# WKRD: babeld fails to start if pidfile already exists
else
:
pidfile
=
'/var/run/babeld.pid'
try
:
os
.
remove
(
pidfile
)
except
OSError
,
e
:
if
e
.
errno
!=
errno
.
ENOENT
:
raise
if
wireless
:
args
.
append
(
'-w'
)
args
=
args
+
interface_list
logging
.
trace
(
'%
s'
%
args
)
logging
.
trace
(
'%
r'
,
args
)
return
subprocess
.
Popen
(
args
,
**
kw
)
re6st/tunnel.py
View file @
b1e97826
...
...
@@ -6,19 +6,13 @@ import utils
# Be carfull the refresh interval should let the routes be established
log
=
None
class
Connection
:
def
__init__
(
self
,
address
,
write_pipe
,
hello
,
iface
,
prefix
,
encrypt
,
ovpn_args
):
self
.
process
=
plib
.
client
(
address
,
write_pipe
,
hello
,
encrypt
,
'--dev'
,
iface
,
*
ovpn_args
,
stdout
=
os
.
open
(
os
.
path
.
join
(
log
,
're6stnet.client.%s.log'
%
(
prefix
,)),
os
.
O_WRONLY
|
os
.
O_CREAT
|
os
.
O_TRUNC
),
stderr
=
subprocess
.
STDOUT
)
self
.
process
=
plib
.
client
(
iface
,
address
,
write_pipe
,
hello
,
encrypt
,
*
ovpn_args
)
self
.
iface
=
iface
self
.
routes
=
0
self
.
_prefix
=
prefix
...
...
@@ -61,10 +55,9 @@ class TunnelManager:
for
i
in
xrange
(
1
,
self
.
_client_count
+
1
))
def
refresh
(
self
):
logging
.
info
(
'Checking the
tunnels...'
)
logging
.
debug
(
'Checking
tunnels...'
)
self
.
_cleanDeads
()
if
self
.
_next_tunnel_refresh
<
time
.
time
():
logging
.
info
(
'Refreshing the tunnels...'
)
self
.
_countRoutes
()
self
.
_removeSomeTunnels
()
self
.
_next_tunnel_refresh
=
time
.
time
()
+
self
.
_refresh_time
...
...
@@ -84,12 +77,12 @@ class TunnelManager:
self
.
_client_count
+
self
.
_refresh_count
)]:
self
.
_kill
(
prefix
)
def
_kill
(
self
,
prefix
):
def
_kill
(
self
,
prefix
,
kill
=
False
):
logging
.
info
(
'Killing the connection with %s/%u...'
%
(
hex
(
int
(
prefix
,
2
))[
2
:],
len
(
prefix
)))
connection
=
self
.
_connection_dict
.
pop
(
prefix
)
try
:
connection
.
process
.
terminate
()
getattr
(
connection
.
process
,
'kill'
if
kill
else
'terminate'
)
()
except
OSError
:
# If the process is already exited
pass
...
...
@@ -144,7 +137,7 @@ class TunnelManager:
if
iface
in
self
.
_iface_list
and
self
.
_net_len
<
subnet_size
<
128
:
prefix
=
ip
[
self
.
_net_len
:
subnet_size
]
logging
.
debug
(
'A route to %s has been discovered on the LAN'
%
(
hex
(
int
(
prefix
),
2
)[
2
:])
)
%
hex
(
int
(
prefix
,
2
))[
2
:]
)
self
.
_peer_db
.
blacklist
(
prefix
,
0
)
possiblePeers
.
add
(
line
[
0
])
...
...
@@ -163,7 +156,7 @@ class TunnelManager:
def
killAll
(
self
):
for
prefix
in
self
.
_connection_dict
.
keys
():
self
.
_kill
(
prefix
)
self
.
_kill
(
prefix
,
True
)
def
checkIncomingTunnel
(
self
,
prefix
):
if
prefix
in
self
.
_connection_dict
:
...
...
re6st/upnpigd.py
View file @
b1e97826
...
...
@@ -3,57 +3,48 @@ import logging
import
time
class
NoUPnPDevice
(
Exception
):
def
__init__
(
self
):
pass
def
__str__
(
self
):
return
'No upnp device found'
class
Forwarder
:
def
__init__
(
self
):
self
.
_u
=
miniupnpc
.
UPnP
()
self
.
_u
.
discoverdelay
=
200
self
.
_rules
=
[]
self
.
_u
.
discover
()
try
:
self
.
_u
.
selectigd
()
except
:
raise
NoUPnPDevice
self
.
_u
.
selectigd
()
self
.
_external_ip
=
self
.
_u
.
externalipaddress
()
self
.
next_refresh
=
time
.
time
()
def
A
ddRule
(
self
,
local_port
,
proto
):
def
a
ddRule
(
self
,
local_port
,
proto
):
# Init parameters
external_port
=
1000
if
proto
==
'udp'
:
upnp_proto
=
'UDP'
elif
proto
==
'tcp-server'
:
upnp_proto
=
'TCP'
else
:
logging
.
info
(
'Unknown protocol : %s'
%
proto
)
raise
RuntimeError
external_port
=
1023
desc
=
're6stnet openvpn %s server'
%
proto
proto
=
proto
.
upper
()
lanaddr
=
self
.
_u
.
lanaddr
# Choose a free port
while
True
:
while
self
.
_u
.
getspecificportmapping
(
external_port
,
upnp_proto
)
!=
None
:
external_port
+=
1
if
external_port
==
65536
:
return
None
# Make the redirection
if
self
.
_u
.
addportmapping
(
external_port
,
upnp_proto
,
self
.
_u
.
lanaddr
,
int
(
local_port
),
're6stnet openvpn server'
,
''
):
logging
.
debug
(
'Forwarding %s:%s to %s:%s'
%
(
self
.
_external_ip
,
external_port
,
self
.
_u
.
lanaddr
,
local_port
))
self
.
_rules
.
append
((
external_port
,
int
(
local_port
),
upnp_proto
))
return
(
self
.
_external_ip
,
str
(
external_port
),
proto
)
external_port
+=
1
if
external_port
>
65535
:
raise
Exception
(
'Failed to redirect %u/%s via UPnP'
%
(
local_port
,
proto
))
try
:
if
not
self
.
_u
.
getspecificportmapping
(
external_port
,
proto
):
args
=
external_port
,
proto
,
lanaddr
,
local_port
,
desc
,
''
self
.
_u
.
addportmapping
(
*
args
)
break
except
Exception
,
e
:
if
str
(
e
)
!=
'ConflictInMappingEntry'
:
raise
logging
.
debug
(
'Forwarding %s:%s to %s:%s'
,
self
.
_external_ip
,
external_port
,
self
.
_u
.
lanaddr
,
local_port
)
self
.
_rules
.
append
(
args
)
return
self
.
_external_ip
,
external_port
def
refresh
(
self
):
logging
.
debug
(
'Refreshing port forwarding'
)
for
external_port
,
local_port
,
proto
in
self
.
_rules
:
self
.
_u
.
addportmapping
(
external_port
,
proto
,
self
.
_u
.
lanaddr
,
local_port
,
're6stnet openvpn server'
,
''
)
for
args
in
self
.
_rules
:
self
.
_u
.
addportmapping
(
*
args
)
self
.
next_refresh
=
time
.
time
()
+
500
def
clear
(
self
):
for
args
in
self
.
_rules
:
self
.
_u
.
deleteportmapping
(
args
[
0
],
args
[
1
])
del
self
.
rules
[:]
re6st/utils.py
View file @
b1e97826
...
...
@@ -6,11 +6,22 @@ logging_levels = logging.WARNING, logging.INFO, logging.DEBUG, 5
def
setupLog
(
log_level
):
logging
.
basicConfig
(
level
=
logging_levels
[
log_level
],
format
=
'%(asctime)s
:
%(message)s'
,
format
=
'%(asctime)s
%(levelname)-9s
%(message)s'
,
datefmt
=
'%d-%m-%Y %H:%M:%S'
)
logging
.
addLevelName
(
5
,
'TRACE'
)
logging
.
trace
=
lambda
*
args
,
**
kw
:
logging
.
log
(
5
,
*
args
,
**
kw
)
class
ArgParser
(
argparse
.
ArgumentParser
):
def
convert_arg_line_to_args
(
self
,
arg_line
):
arg_line
=
arg_line
.
split
(
'#'
)[
0
].
rstrip
()
if
arg_line
:
if
arg_line
.
startswith
(
'@'
):
yield
arg_line
return
for
arg
in
(
'--'
+
arg_line
.
lstrip
(
'--'
)).
split
():
if
arg
.
strip
():
yield
arg
def
binFromIp
(
ip
):
ip1
,
ip2
=
struct
.
unpack
(
'>QQ'
,
socket
.
inet_pton
(
socket
.
AF_INET6
,
ip
))
...
...
re6stnet
View file @
b1e97826
#!/usr/bin/env python
import
os
,
sys
,
select
,
time
,
socket
import
argparse
,
subprocess
,
sqlite3
,
logging
,
traceback
from
argparse
import
ArgumentParser
from
re6st
import
plib
,
utils
,
db
,
upnpigd
,
tunnel
class
ArgParser
(
ArgumentParser
):
def
convert_arg_line_to_args
(
self
,
arg_line
):
arg_line
=
arg_line
.
split
(
'#'
)[
0
].
rstrip
()
if
arg_line
:
if
arg_line
.
startswith
(
'@'
):
yield
arg_line
return
for
arg
in
(
'--'
+
arg_line
.
lstrip
(
'--'
)).
split
():
if
arg
.
strip
():
yield
arg
import
atexit
,
os
,
sys
,
select
,
socket
,
time
import
argparse
,
signal
,
subprocess
,
sqlite3
,
logging
,
traceback
from
re6st
import
plib
,
utils
,
db
,
tunnel
def
ovpnArgs
(
optional_args
,
ca_path
,
cert_path
,
key_path
):
# Treat openvpn arguments
...
...
@@ -32,13 +17,13 @@ def ovpnArgs(optional_args, ca_path, cert_path, key_path):
def
getConfig
():
parser
=
ArgParser
(
fromfile_prefix_chars
=
'@'
,
parser
=
utils
.
ArgParser
(
fromfile_prefix_chars
=
'@'
,
description
=
'Resilient virtual private network application'
)
_
=
parser
.
add_argument
# General Configuration options
_
(
'--ip'
,
default
=
None
,
dest
=
'address'
,
action
=
'append'
,
nargs
=
3
,
help
=
'I
p address, port and protocol advertised to other vpn
nodes'
)
_
(
'--ip'
,
help
=
'I
P address advertised to other
nodes'
)
_
(
'--registry'
,
required
=
True
,
help
=
"HTTP URL of the discovery peer server,"
" with public host (default port: 80)"
)
...
...
@@ -49,11 +34,15 @@ def getConfig():
_
(
'-s'
,
'--state'
,
default
=
'/var/lib/re6stnet'
,
help
=
'Path to re6stnet state directory'
)
_
(
'-v'
,
'--verbose'
,
default
=
0
,
type
=
int
,
help
=
'
Defines the verbose level
'
)
help
=
'
Log level of re6st itself
'
)
_
(
'-i'
,
'--interface'
,
action
=
'append'
,
dest
=
'iface_list'
,
default
=
[],
help
=
'Extra interface for LAN discovery'
)
# Routing algorithm options
_
(
'--babel-pidfile'
,
help
=
'Specify a file to write our process id to'
)
_
(
'--babel-verb'
,
default
=
0
,
help
=
'Babel verbosity'
)
_
(
'--hello'
,
type
=
int
,
default
=
15
,
help
=
'Hello interval for babel, in seconds'
)
_
(
'-w'
,
'--wireless'
,
action
=
'store_true'
,
...
...
@@ -87,11 +76,6 @@ def getConfig():
def
main
():
# Get arguments
config
=
getConfig
()
if
not
config
.
pp
:
config
.
pp
=
[[
'1194'
,
'udp'
],
[
'1194'
,
'tcp-server'
]]
config
.
pp
=
list
((
port
,
proto
,
're6stnet-%s'
%
proto
)
for
port
,
proto
in
config
.
pp
)
manual
=
bool
(
config
.
address
)
network
=
utils
.
networkFromCa
(
config
.
ca
)
internal_ip
,
prefix
=
utils
.
ipFromCert
(
network
,
config
.
cert
)
openvpn_args
=
ovpnArgs
(
config
.
openvpn_args
,
config
.
ca
,
config
.
cert
,
...
...
@@ -104,76 +88,76 @@ def main():
logging
.
trace
(
"Configuration :
\
n
%s"
%
config
)
# Set global variables
tunnel
.
log
=
config
.
log
plib
.
verbose
=
config
.
verbose
plib
.
log
=
tunnel
.
log
=
config
.
log
# Create and open read_only pipe to get server events
logging
.
info
(
'Creating pipe for server events...'
)
r_pipe
,
write_pipe
=
os
.
pipe
()
read_pipe
=
os
.
fdopen
(
r_pipe
)
logging
.
debug
(
'Pipe created'
)
signal
.
signal
(
signal
.
SIGHUP
,
lambda
*
args
:
sys
.
exit
(
-
1
))
# Init db and tunnels
forwarder
=
None
if
manual
:
logging
.
info
(
'Detected manual external configuration'
)
for
c
,
s
in
(
'udp'
,
'udp'
),
(
'tcp-client'
,
'tcp-server'
):
if
len
(
list
(
x
for
x
in
config
.
address
if
x
[
2
]
==
c
))
\
<
len
(
list
(
x
for
x
in
config
.
pp
if
x
[
1
]
==
s
)):
logging
.
warning
(
"""Beware: in manual configuration, you
declared less external configurations regarding
protocol %s/%s than you gave internal server
configurations"""
%
(
c
,
s
))
address
=
[]
if
config
.
pp
:
pp
=
[(
int
(
port
),
proto
)
for
port
,
proto
in
config
.
pp
]
else
:
pp
=
(
1194
,
'udp'
),
(
1194
,
'tcp'
)
ip_changed
=
lambda
ip
:
[(
ip
,
str
(
port
),
proto
)
for
port
,
proto
in
pp
]
forwarder
=
None
if
config
.
ip
==
'upnp'
or
not
config
.
ip
:
logging
.
info
(
'Attempting automatic configuration via UPnP...'
)
try
:
forwarder
=
upnpigd
.
Forwarder
()
config
.
address
=
[]
for
port
,
proto
,
_
in
config
.
pp
:
ext
=
forwarder
.
AddRule
(
port
,
proto
)
if
ext
:
config
.
address
.
append
(
ext
)
except
upnpigd
.
NoUPnPDevice
:
logging
.
info
(
'No upnp device found'
)
from
re6st.upnpigd
import
Forwarder
forwarder
=
Forwarder
()
except
Exception
,
e
:
if
config
.
ip
:
raise
logging
.
info
(
"%s: assume we are not NATed"
,
e
)
else
:
atexit
.
register
(
forwarder
.
clear
)
for
port
,
proto
in
pp
:
ip
,
port
=
forwarder
.
addRule
(
port
,
proto
)
address
.
append
((
ip
,
str
(
port
),
proto
))
elif
config
.
ip
!=
'any'
:
address
=
ip_changed
(
config
.
ip
)
if
address
:
ip_changed
=
None
peer_db
=
db
.
PeerManager
(
db_path
,
config
.
registry
,
config
.
key
,
config
.
peers_db_refresh
,
config
.
address
,
internal_ip
,
prefix
,
manual
,
config
.
pp
,
200
)
config
.
peers_db_refresh
,
address
,
internal_ip
,
prefix
,
ip_changed
,
200
)
tunnel_manager
=
tunnel
.
TunnelManager
(
write_pipe
,
peer_db
,
openvpn_args
,
config
.
hello
,
config
.
tunnel_refresh
,
config
.
connection_count
,
config
.
iface_list
,
network
,
prefix
,
2
,
config
.
encrypt
)
peer_db
.
tunnel_manager
=
tunnel_manager
# Launch routing protocol. WARNING : you have to be root to start babeld
server_tunnels
=
{}
for
x
in
pp
:
server_tunnels
.
setdefault
(
're6stnet-'
+
x
[
1
],
x
)
interface_list
=
list
(
tunnel_manager
.
free_interface_set
)
\
+
config
.
iface_list
+
list
(
iface
for
_
,
_
,
iface
in
config
.
pp
)
+
config
.
iface_list
+
server_tunnels
.
keys
()
subnet
=
utils
.
ipFromBin
((
network
+
prefix
).
ljust
(
128
,
'0'
))
router
=
plib
.
router
(
network
,
subnet
,
len
(
prefix
)
+
len
(
network
),
interface_list
,
config
.
wireless
,
config
.
hello
,
os
.
path
.
join
(
config
.
state
,
'babeld.state'
),
stdout
=
os
.
open
(
os
.
path
.
join
(
config
.
log
,
'babeld.log'
),
os
.
O_WRONLY
|
os
.
O_CREAT
|
os
.
O_TRUNC
),
stderr
=
subprocess
.
STDOUT
)
# Establish connections
server_process
=
[]
server_ip
=
internal_ip
for
port
,
proto
,
iface
in
config
.
pp
:
server_process
.
append
(
plib
.
server
(
server_ip
,
len
(
network
)
+
len
(
prefix
),
config
.
connection_count
,
config
.
dh
,
write_pipe
,
port
,
proto
,
config
.
hello
,
config
.
encrypt
,
'--dev'
,
iface
,
*
openvpn_args
,
stdout
=
os
.
open
(
os
.
path
.
join
(
config
.
log
,
're6stnet.server.%s.log'
%
(
proto
,)),
os
.
O_WRONLY
|
os
.
O_CREAT
|
os
.
O_TRUNC
),
stderr
=
subprocess
.
STDOUT
))
server_ip
=
''
router
=
plib
.
router
(
network
,
subnet
,
len
(
prefix
)
+
len
(
network
),
interface_list
,
config
.
wireless
,
config
.
hello
,
config
.
babel_verb
,
config
.
babel_pidfile
,
os
.
path
.
join
(
config
.
state
,
'babeld.state'
),
stdout
=
os
.
open
(
os
.
path
.
join
(
config
.
log
,
'babeld.log'
),
os
.
O_WRONLY
|
os
.
O_CREAT
|
os
.
O_APPEND
),
stderr
=
subprocess
.
STDOUT
)
# main loop
try
:
try
:
server_process
=
[]
for
iface
,
(
port
,
proto
)
in
server_tunnels
.
iteritems
():
server_process
.
append
(
plib
.
server
(
iface
,
internal_ip
if
proto
==
pp
[
0
][
1
]
else
None
,
len
(
network
)
+
len
(
prefix
),
config
.
connection_count
,
config
.
dh
,
write_pipe
,
port
,
proto
,
config
.
hello
,
config
.
encrypt
,
*
openvpn_args
))
while
True
:
logging
.
info
(
'Sleeping ...'
)
nextUpdate
=
min
(
tunnel_manager
.
next_refresh
,
peer_db
.
next_refresh
)
if
forwarder
!=
None
:
if
forwarder
:
nextUpdate
=
min
(
nextUpdate
,
forwarder
.
next_refresh
)
nextUpdate
=
max
(
0
,
nextUpdate
-
time
.
time
())
select_list
=
[
read_pipe
]
...
...
@@ -186,14 +170,15 @@ def main():
peer_db
.
refresh
()
if
time
.
time
()
>=
tunnel_manager
.
next_refresh
:
tunnel_manager
.
refresh
()
if
forwarder
!=
None
and
time
.
time
()
>
forwarder
.
next_refresh
:
if
forwarder
and
time
.
time
()
>
forwarder
.
next_refresh
:
forwarder
.
refresh
()
if
peer_db
.
socket_file
in
ready
:
peer_db
.
readSocket
()
finally
:
for
p
in
[
router
]
+
server_process
:
router
.
terminate
()
for
p
in
server_process
:
try
:
p
.
terminate
()
p
.
kill
()
except
:
pass
try
:
...
...
@@ -203,7 +188,10 @@ def main():
except
sqlite3
.
Error
:
traceback
.
print_exc
()
os
.
rename
(
db_path
,
db_path
+
'.bak'
)
os
.
execvp
(
sys
.
executable
,
sys
.
argv
)
try
:
sys
.
exitfunc
()
finally
:
os
.
execvp
(
sys
.
executable
,
sys
.
argv
)
except
KeyboardInterrupt
:
return
0
...
...
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