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
2
Issues
2
List
Boards
Labels
Milestones
Merge Requests
4
Merge Requests
4
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
nexedi
re6stnet
Commits
3493e13b
Commit
3493e13b
authored
Mar 12, 2013
by
Julien Muchembled
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New --remote-gateway option for network redundancy with multiple ISP
parent
d822bcb4
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
92 additions
and
35 deletions
+92
-35
demo/demo
demo/demo
+1
-1
re6st/plib.py
re6st/plib.py
+4
-8
re6st/tunnel.py
re6st/tunnel.py
+69
-17
re6st/utils.py
re6st/utils.py
+9
-6
re6stnet
re6stnet
+9
-3
No files found.
demo/demo
View file @
3493e13b
...
@@ -193,7 +193,7 @@ if 1:
...
@@ -193,7 +193,7 @@ if 1:
% (folder, VERBOSE, registry, args))
% (folder, VERBOSE, registry, args))
re6stnet(registry, 'registry', '--ip ' + REGISTRY, registry='http://localhost/')
re6stnet(registry, 'registry', '--ip ' + REGISTRY, registry='http://localhost/')
re6stnet(machine1, 'm1', '-I%s' % m1_if_0.name)
re6stnet(machine1, 'm1', '-I%s' % m1_if_0.name)
re6stnet(machine2, 'm2', prefix_len=80)
re6stnet(machine2, 'm2',
'--remote-gateway 10.1.1.1',
prefix_len=80)
re6stnet(machine3, 'm3', '-i%s' % m3_if_0.name)
re6stnet(machine3, 'm3', '-i%s' % m3_if_0.name)
re6stnet(machine4, 'm4', '-i%s' % m4_if_0.name)
re6stnet(machine4, 'm4', '-i%s' % m4_if_0.name)
re6stnet(machine5, 'm5', '-i%s' % m5_if_0.name)
re6stnet(machine5, 'm5', '-i%s' % m5_if_0.name)
...
...
re6st/plib.py
View file @
3493e13b
...
@@ -39,15 +39,11 @@ def server(iface, max_clients, dh_path, pipe_fd, port, proto, encrypt, *args, **
...
@@ -39,15 +39,11 @@ def server(iface, max_clients, dh_path, pipe_fd, port, proto, encrypt, *args, **
*
args
,
**
kw
)
*
args
,
**
kw
)
def
client
(
iface
,
server_address
,
encrypt
,
*
args
,
**
kw
):
def
client
(
iface
,
address_list
,
encrypt
,
*
args
,
**
kw
):
remote
=
[
'--nobind'
,
'--client'
]
remote
=
[
'--nobind'
,
'--client'
]
try
:
for
ip
,
port
,
proto
in
address_list
:
for
ip
,
port
,
proto
in
utils
.
address_list
(
server_address
):
remote
+=
'--remote'
,
ip
,
port
,
\
remote
+=
'--remote'
,
ip
,
port
,
\
'tcp-client'
if
proto
==
'tcp'
else
proto
'tcp-client'
if
proto
==
'tcp'
else
proto
except
ValueError
,
e
:
logging
.
warning
(
"Failed to parse node address %r (%s)"
,
server_address
,
e
)
remote
+=
args
remote
+=
args
return
openvpn
(
iface
,
encrypt
,
*
remote
,
**
kw
)
return
openvpn
(
iface
,
encrypt
,
*
remote
,
**
kw
)
...
...
re6st/tunnel.py
View file @
3493e13b
...
@@ -8,19 +8,71 @@ RTF_CACHE = 0x01000000 # cache entry
...
@@ -8,19 +8,71 @@ RTF_CACHE = 0x01000000 # cache entry
# Be careful the refresh interval should let the routes be established
# Be careful the refresh interval should let the routes be established
class
Connection
:
def
__init__
(
self
,
address
,
write_pipe
,
timeout
,
iface
,
prefix
,
encrypt
,
class
MultiGatewayManager
(
dict
):
ovpn_args
):
self
.
process
=
plib
.
client
(
iface
,
address
,
encrypt
,
def
__init__
(
self
,
gateway
):
'--tls-remote'
,
'%u/%u'
%
(
int
(
prefix
,
2
),
len
(
prefix
)),
if
gateway
:
self
.
_gw
=
gateway
else
:
self
.
add
=
self
.
remove
=
lambda
_
:
None
def
_route
(
self
,
cmd
,
dest
,
gw
):
cmd
=
'ip'
,
'-4'
,
'route'
,
cmd
,
'%s/32'
%
dest
,
'via'
,
gw
logging
.
trace
(
'%r'
,
cmd
)
subprocess
.
call
(
cmd
)
def
add
(
self
,
ip_list
):
for
dest
in
ip_list
:
try
:
self
[
dest
][
1
]
+=
1
except
KeyError
:
gw
=
self
.
_gw
(
dest
)
self
[
dest
]
=
[
gw
,
0
]
self
.
_route
(
'add'
,
dest
,
gw
)
def
remove
(
self
,
ip_list
):
for
dest
in
ip_list
:
gw
,
count
=
self
[
dest
]
if
count
:
self
[
dest
][
1
]
=
count
-
1
else
:
del
self
[
dest
]
try
:
self
.
_route
(
'del'
,
dest
,
gw
)
except
:
pass
class
Connection
(
object
):
def
__init__
(
self
,
address
,
iface
,
prefix
):
self
.
address_list
=
list
(
utils
.
parse_address
(
address
))
self
.
iface
=
iface
self
.
routes
=
0
self
.
_prefix
=
prefix
def
__iter__
(
self
):
if
not
hasattr
(
self
,
'_remote_ip_set'
):
self
.
_remote_ip_set
=
set
(
info
[
4
][
0
]
for
ip
,
port
,
proto
in
self
.
address_list
for
info
in
socket
.
getaddrinfo
(
ip
,
port
,
socket
.
AF_INET
,
0
,
getattr
(
socket
,
'IPPROTO_'
+
proto
.
upper
())))
return
iter
(
self
.
_remote_ip_set
)
def
open
(
self
,
write_pipe
,
timeout
,
encrypt
,
ovpn_args
):
self
.
process
=
plib
.
client
(
self
.
iface
,
self
.
address_list
,
encrypt
,
'--tls-remote'
,
'%u/%u'
%
(
int
(
self
.
_prefix
,
2
),
len
(
self
.
_prefix
)),
'--connect-retry-max'
,
'3'
,
'--tls-exit'
,
'--connect-retry-max'
,
'3'
,
'--tls-exit'
,
'--ping-exit'
,
str
(
timeout
),
'--ping-exit'
,
str
(
timeout
),
'--route-up'
,
'%s %u'
%
(
plib
.
ovpn_client
,
write_pipe
),
'--route-up'
,
'%s %u'
%
(
plib
.
ovpn_client
,
write_pipe
),
*
ovpn_args
)
*
ovpn_args
)
self
.
iface
=
iface
self
.
routes
=
0
def
close
(
self
):
self
.
_prefix
=
prefix
try
:
self
.
process
.
stop
()
except
(
AttributeError
,
OSError
):
pass
# we already polled an exited process
def
refresh
(
self
):
def
refresh
(
self
):
# Check that the connection is alive
# Check that the connection is alive
...
@@ -35,7 +87,7 @@ class TunnelManager(object):
...
@@ -35,7 +87,7 @@ class TunnelManager(object):
def
__init__
(
self
,
write_pipe
,
peer_db
,
openvpn_args
,
timeout
,
def
__init__
(
self
,
write_pipe
,
peer_db
,
openvpn_args
,
timeout
,
refresh
,
client_count
,
iface_list
,
network
,
prefix
,
refresh
,
client_count
,
iface_list
,
network
,
prefix
,
address
,
ip_changed
,
encrypt
):
address
,
ip_changed
,
encrypt
,
remote_gateway
):
self
.
_write_pipe
=
write_pipe
self
.
_write_pipe
=
write_pipe
self
.
_peer_db
=
peer_db
self
.
_peer_db
=
peer_db
self
.
_connecting
=
set
()
self
.
_connecting
=
set
()
...
@@ -49,9 +101,10 @@ class TunnelManager(object):
...
@@ -49,9 +101,10 @@ class TunnelManager(object):
self
.
_network
=
network
self
.
_network
=
network
self
.
_iface_list
=
iface_list
self
.
_iface_list
=
iface_list
self
.
_prefix
=
prefix
self
.
_prefix
=
prefix
self
.
_address
=
utils
.
address_str
(
address
)
self
.
_address
=
utils
.
dump_address
(
address
)
self
.
_ip_changed
=
ip_changed
self
.
_ip_changed
=
ip_changed
self
.
_encrypt
=
encrypt
self
.
_encrypt
=
encrypt
self
.
_gateway_manager
=
MultiGatewayManager
(
remote_gateway
)
self
.
_served
=
set
()
self
.
_served
=
set
()
self
.
sock
=
socket
.
socket
(
socket
.
AF_INET6
,
socket
.
SOCK_DGRAM
)
self
.
sock
=
socket
.
socket
(
socket
.
AF_INET6
,
socket
.
SOCK_DGRAM
)
...
@@ -131,10 +184,8 @@ class TunnelManager(object):
...
@@ -131,10 +184,8 @@ class TunnelManager(object):
int
(
prefix
,
2
),
len
(
prefix
))
int
(
prefix
,
2
),
len
(
prefix
))
connection
=
self
.
_connection_dict
.
pop
(
prefix
)
connection
=
self
.
_connection_dict
.
pop
(
prefix
)
self
.
freeInterface
(
connection
.
iface
)
self
.
freeInterface
(
connection
.
iface
)
try
:
connection
.
close
()
connection
.
process
.
stop
()
self
.
_gateway_manager
.
remove
(
connection
)
except
OSError
:
pass
# we already polled an exited process
logging
.
trace
(
'Connection with %u/%u killed'
,
logging
.
trace
(
'Connection with %u/%u killed'
,
int
(
prefix
,
2
),
len
(
prefix
))
int
(
prefix
,
2
),
len
(
prefix
))
...
@@ -146,8 +197,9 @@ class TunnelManager(object):
...
@@ -146,8 +197,9 @@ class TunnelManager(object):
logging
.
info
(
'Establishing a connection with %u/%u'
,
logging
.
info
(
'Establishing a connection with %u/%u'
,
int
(
prefix
,
2
),
len
(
prefix
))
int
(
prefix
,
2
),
len
(
prefix
))
iface
=
self
.
getFreeInterface
(
prefix
)
iface
=
self
.
getFreeInterface
(
prefix
)
self
.
_connection_dict
[
prefix
]
=
Connection
(
address
,
self
.
_write_pipe
,
self
.
_connection_dict
[
prefix
]
=
c
=
Connection
(
address
,
iface
,
prefix
)
self
.
_timeout
,
iface
,
prefix
,
self
.
_encrypt
,
self
.
_ovpn_args
)
self
.
_gateway_manager
.
add
(
c
)
c
.
open
(
self
.
_write_pipe
,
self
.
_timeout
,
self
.
_encrypt
,
self
.
_ovpn_args
)
self
.
_peer_db
.
connecting
(
prefix
,
1
)
self
.
_peer_db
.
connecting
(
prefix
,
1
)
return
True
return
True
...
@@ -301,7 +353,7 @@ class TunnelManager(object):
...
@@ -301,7 +353,7 @@ class TunnelManager(object):
def
_ovpn_route_up
(
self
,
common_name
,
ip
):
def
_ovpn_route_up
(
self
,
common_name
,
ip
):
self
.
_peer_db
.
connecting
(
utils
.
binFromSubnet
(
common_name
),
0
)
self
.
_peer_db
.
connecting
(
utils
.
binFromSubnet
(
common_name
),
0
)
if
self
.
_ip_changed
:
if
self
.
_ip_changed
:
self
.
_address
=
utils
.
address_str
(
self
.
_ip_changed
(
ip
))
self
.
_address
=
utils
.
dump_address
(
self
.
_ip_changed
(
ip
))
def
handlePeerEvent
(
self
):
def
handlePeerEvent
(
self
):
msg
,
address
=
self
.
sock
.
recvfrom
(
1
<<
16
)
msg
,
address
=
self
.
sock
.
recvfrom
(
1
<<
16
)
...
...
re6st/utils.py
View file @
3493e13b
...
@@ -139,14 +139,17 @@ def subnetFromCert(cert_path):
...
@@ -139,14 +139,17 @@ def subnetFromCert(cert_path):
cert
=
crypto
.
load_certificate
(
crypto
.
FILETYPE_PEM
,
f
.
read
())
cert
=
crypto
.
load_certificate
(
crypto
.
FILETYPE_PEM
,
f
.
read
())
return
cert
.
get_subject
().
CN
return
cert
.
get_subject
().
CN
def
address_str
(
address
):
def
dump_address
(
address
):
return
';'
.
join
(
map
(
','
.
join
,
address
))
return
';'
.
join
(
map
(
','
.
join
,
address
))
def
parse_address
(
address_list
):
def
address_list
(
address_list
):
for
address
in
address_list
.
split
(
';'
):
return
list
(
tuple
(
address
.
split
(
','
))
try
:
for
address
in
address_list
.
split
(
';'
))
ip
,
port
,
proto
=
address
.
split
(
','
)
yield
ip
,
str
(
port
),
proto
except
ValueError
,
e
:
logging
.
warning
(
"Failed to parse node address %r (%s)"
,
address
,
e
)
def
binFromSubnet
(
subnet
):
def
binFromSubnet
(
subnet
):
p
,
l
=
subnet
.
split
(
'/'
)
p
,
l
=
subnet
.
split
(
'/'
)
...
...
re6stnet
View file @
3493e13b
#!/usr/bin/python
#!/usr/bin/python
import
atexit
,
errno
,
logging
,
os
,
select
,
signal
import
atexit
,
errno
,
logging
,
os
,
random
,
select
,
signal
import
sqlite3
,
subprocess
,
sys
,
time
,
traceback
import
sqlite3
,
subprocess
,
sys
,
time
,
traceback
from
re6st
import
plib
,
utils
,
db
,
tunnel
from
re6st
import
plib
,
utils
,
db
,
tunnel
...
@@ -97,6 +97,9 @@ def getConfig():
...
@@ -97,6 +97,9 @@ def getConfig():
help
=
"Interval in seconds between two tunnel refresh: the worst"
help
=
"Interval in seconds between two tunnel refresh: the worst"
" tunnel is closed if the number of client tunnels has reached"
" tunnel is closed if the number of client tunnels has reached"
" its maximum number (client-count)."
)
" its maximum number (client-count)."
)
_
(
'--remote-gateway'
,
action
=
'append'
,
dest
=
'gw_list'
,
help
=
"Force each tunnel to be created through one the given gateways,"
" randomly."
)
_
(
'--client'
,
metavar
=
'HOST,PORT,PROTO[;...]'
,
_
(
'--client'
,
metavar
=
'HOST,PORT,PROTO[;...]'
,
help
=
"Do not run any OpenVPN server, but only 1 OpenVPN client,"
help
=
"Do not run any OpenVPN server, but only 1 OpenVPN client,"
" with specified remotes. Any other option not required in this"
" with specified remotes. Any other option not required in this"
...
@@ -145,6 +148,8 @@ def main():
...
@@ -145,6 +148,8 @@ def main():
else
:
else
:
pp
=
(
1194
,
'udp'
),
(
1194
,
'tcp'
)
pp
=
(
1194
,
'udp'
),
(
1194
,
'tcp'
)
ip_changed
=
lambda
ip
:
[(
ip
,
str
(
port
),
proto
)
for
port
,
proto
in
pp
]
ip_changed
=
lambda
ip
:
[(
ip
,
str
(
port
),
proto
)
for
port
,
proto
in
pp
]
remote_gateway
=
config
.
gw_list
and
(
lambda
_
:
random
.
choice
(
config
.
gw_list
))
forwarder
=
None
forwarder
=
None
if
config
.
ip
==
'upnp'
or
not
config
.
ip
:
if
config
.
ip
==
'upnp'
or
not
config
.
ip
:
logging
.
info
(
'Attempting automatic configuration via UPnP...'
)
logging
.
info
(
'Attempting automatic configuration via UPnP...'
)
...
@@ -207,7 +212,7 @@ def main():
...
@@ -207,7 +212,7 @@ def main():
tunnel_manager
=
tunnel
.
TunnelManager
(
write_pipe
,
peer_db
,
tunnel_manager
=
tunnel
.
TunnelManager
(
write_pipe
,
peer_db
,
config
.
openvpn_args
,
timeout
,
config
.
tunnel_refresh
,
config
.
openvpn_args
,
timeout
,
config
.
tunnel_refresh
,
config
.
client_count
,
config
.
iface_list
,
network
,
prefix
,
config
.
client_count
,
config
.
iface_list
,
network
,
prefix
,
address
,
ip_changed
,
config
.
encrypt
)
address
,
ip_changed
,
config
.
encrypt
,
remote_gateway
)
tunnel_interfaces
+=
tunnel_manager
.
new_iface_list
tunnel_interfaces
+=
tunnel_manager
.
new_iface_list
else
:
else
:
tunnel_manager
=
write_pipe
=
None
tunnel_manager
=
write_pipe
=
None
...
@@ -230,7 +235,8 @@ def main():
...
@@ -230,7 +235,8 @@ def main():
ip
(
'addrlabel'
,
'prefix'
,
my_network
,
'label'
,
'99'
)
ip
(
'addrlabel'
,
'prefix'
,
my_network
,
'label'
,
'99'
)
# prepare persistent interfaces
# prepare persistent interfaces
if
config
.
client
:
if
config
.
client
:
cleanup
.
append
(
plib
.
client
(
're6stnet'
,
config
.
client
,
cleanup
.
append
(
plib
.
client
(
're6stnet'
,
utils
.
parse_address
(
config
.
client
),
config
.
encrypt
,
'--ping-restart'
,
str
(
timeout
),
config
.
encrypt
,
'--ping-restart'
,
str
(
timeout
),
*
config
.
openvpn_args
).
stop
)
*
config
.
openvpn_args
).
stop
)
elif
server_tunnels
:
elif
server_tunnels
:
...
...
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