Commit eba6c762 authored by Julien Muchembled's avatar Julien Muchembled

Abort in case of unexpected default route

This is a common misconfiguration that may break internet acces for other peers.

We also stop checking for child process termination when used without tunnel
manager (i.e. with --client or --client-count=0) because it conflicts with the
'ip route' command that is called every minute if --table=0 is used.
Anyway, with a tunnel manager, only openvpn client are watched.
parent c1749ede
...@@ -25,3 +25,6 @@ ...@@ -25,3 +25,6 @@
- Is it useful that each node regenerates its own DH parameter ? - Is it useful that each node regenerates its own DH parameter ?
- Filter non-routable IPs. Add an option not to do it. - Filter non-routable IPs. Add an option not to do it.
- Abort in case of import child process failure (babel, openvpn server,
openvpn client if run with --client).
\ No newline at end of file
...@@ -194,7 +194,7 @@ if 1: ...@@ -194,7 +194,7 @@ if 1:
p.communicate(str(token[0])) p.communicate(str(token[0]))
os.remove(dh_path) os.remove(dh_path)
os.remove(folder + '/ca.crt') os.remove(folder + '/ca.crt')
node.screen('../re6stnet @%s/re6stnet.conf --table 0 -v%u --registry %s %s' node.screen('../re6stnet @%s/re6stnet.conf -v%u --registry %s %s'
% (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)
......
...@@ -7,5 +7,6 @@ dh dh2048.pem ...@@ -7,5 +7,6 @@ dh dh2048.pem
ca ca.crt ca ca.crt
cert m1/cert.crt cert m1/cert.crt
key m1/cert.key key m1/cert.key
table 0
client-count 2 client-count 2
tunnel-refresh 100 tunnel-refresh 100
...@@ -7,5 +7,6 @@ dh dh2048.pem ...@@ -7,5 +7,6 @@ dh dh2048.pem
ca ca.crt ca ca.crt
cert m2/cert.crt cert m2/cert.crt
key m2/cert.key key m2/cert.key
table 0
client-count 2 client-count 2
tunnel-refresh 100 tunnel-refresh 100
...@@ -7,5 +7,6 @@ dh dh2048.pem ...@@ -7,5 +7,6 @@ dh dh2048.pem
ca ca.crt ca ca.crt
cert m3/cert.crt cert m3/cert.crt
key m3/cert.key key m3/cert.key
table 0
client-count 2 client-count 2
tunnel-refresh 100 tunnel-refresh 100
...@@ -7,5 +7,6 @@ dh dh2048.pem ...@@ -7,5 +7,6 @@ dh dh2048.pem
ca ca.crt ca ca.crt
cert m4/cert.crt cert m4/cert.crt
key m4/cert.key key m4/cert.key
table 0
client-count 2 client-count 2
tunnel-refresh 100 tunnel-refresh 100
...@@ -5,5 +5,6 @@ hello 4 ...@@ -5,5 +5,6 @@ hello 4
ca ca.crt ca ca.crt
cert m5/cert.crt cert m5/cert.crt
key m5/cert.key key m5/cert.key
table 0
client-count 0 client-count 0
max-clients 0 max-clients 0
...@@ -7,6 +7,7 @@ dh dh2048.pem ...@@ -7,6 +7,7 @@ dh dh2048.pem
ca ca.crt ca ca.crt
cert m6/cert.crt cert m6/cert.crt
key m6/cert.key key m6/cert.key
table 0
client-count 2 client-count 2
tunnel-refresh 100 tunnel-refresh 100
# TODO: Run a DHCPv4 client on machine9. Unfortunately, isc-dhcp-client 4.2.4 # TODO: Run a DHCPv4 client on machine9. Unfortunately, isc-dhcp-client 4.2.4
......
...@@ -7,5 +7,6 @@ dh dh2048.pem ...@@ -7,5 +7,6 @@ dh dh2048.pem
ca ca.crt ca ca.crt
cert m7/cert.crt cert m7/cert.crt
key m7/cert.key key m7/cert.key
table 0
client-count 2 client-count 2
tunnel-refresh 100 tunnel-refresh 100
...@@ -5,4 +5,5 @@ hello 4 ...@@ -5,4 +5,5 @@ hello 4
ca ca.crt ca ca.crt
cert m8/cert.crt cert m8/cert.crt
key m8/cert.key key m8/cert.key
table 0
client 10.0.1.2,1194,udp;10.0.1.3,1194,udp client 10.0.1.2,1194,udp;10.0.1.3,1194,udp
...@@ -6,5 +6,6 @@ dh dh2048.pem ...@@ -6,5 +6,6 @@ dh dh2048.pem
ca ca.crt ca ca.crt
cert registry/cert.crt cert registry/cert.crt
key registry/cert.key key registry/cert.key
gateway
client-count 2 client-count 2
tunnel-refresh 100 tunnel-refresh 100
import argparse, calendar, errno, logging, os, shlex, signal, socket import argparse, calendar, errno, logging, os, shlex, signal, socket
import struct, subprocess, textwrap, threading, time import struct, subprocess, sys, textwrap, threading, time, traceback
logging_levels = logging.WARNING, logging.INFO, logging.DEBUG, 5 logging_levels = logging.WARNING, logging.INFO, logging.DEBUG, 5
...@@ -44,6 +44,10 @@ def setupLog(log_level, filename=None, **kw): ...@@ -44,6 +44,10 @@ def setupLog(log_level, filename=None, **kw):
logging.addLevelName(5, 'TRACE') logging.addLevelName(5, 'TRACE')
logging.trace = lambda *args, **kw: logging.log(5, *args, **kw) logging.trace = lambda *args, **kw: logging.log(5, *args, **kw)
def log_exception():
f = traceback.format_exception(*sys.exc_info())
logging.error('%s%s', f.pop(), ''.join(f))
class HelpFormatter(argparse.ArgumentDefaultsHelpFormatter): class HelpFormatter(argparse.ArgumentDefaultsHelpFormatter):
......
#!/usr/bin/python #!/usr/bin/python
import atexit, errno, logging, os, select, signal import atexit, errno, logging, os, select, signal
import sqlite3, subprocess, sys, time, traceback import sqlite3, subprocess, sys, time, threading
from collections import deque from collections import deque
from OpenSSL import crypto from OpenSSL import crypto
from re6st import db, plib, tunnel, utils from re6st import db, plib, tunnel, utils
...@@ -65,12 +65,14 @@ def getConfig(): ...@@ -65,12 +65,14 @@ def getConfig():
" hello interval for Babel to re-establish connection with a" " hello interval for Babel to re-establish connection with a"
" node for which the direct connection has been cut.") " node for which the direct connection has been cut.")
_('--table', type=int, default=42, _('--table', type=int, default=42,
help="Use given table id. Set 0 to use the main table, if:\n" help="Use given table id. Set 0 to use the main table, if you want to"
"- you are a gateway of this network (the default route will be" " access internet via this network (in this case, make sure you"
" exported)\n" " don't already have a default route). Don't use this option with"
"- or you want to use the default route of this network for all" " --gateway (main table is automatically used).")
" communications (in this case, make sure you don't already have" _('--gateway', action='store_true',
" a default route).\n") help="Act as a gateway for this network (the default route will be"
" exported). Do never use it if you don't know what it means.")
_ = parser.add_argument_group('tunnelling').add_argument _ = parser.add_argument_group('tunnelling').add_argument
_('-O', dest='openvpn_args', metavar='ARG', action='append', default=[], _('-O', dest='openvpn_args', metavar='ARG', action='append', default=[],
help="Extra arguments to forward to both server and client OpenVPN" help="Extra arguments to forward to both server and client OpenVPN"
...@@ -319,7 +321,9 @@ def main(): ...@@ -319,7 +321,9 @@ def main():
if_rt[4] = my_subnet if_rt[4] = my_subnet
cleanup.append(lambda: subprocess.call(if_rt)) cleanup.append(lambda: subprocess.call(if_rt))
x = [my_network] x = [my_network]
if config.table: if config.gateway:
config.table = 0
elif config.table:
x += 'table', str(config.table) x += 'table', str(config.table)
try: try:
ip('rule', 'from', *x) ip('rule', 'from', *x)
...@@ -333,6 +337,25 @@ def main(): ...@@ -333,6 +337,25 @@ def main():
call(if_rt) call(if_rt)
if_rt += x[1:] if_rt += x[1:]
call(if_rt[:3] + ['add', 'proto', 'static'] + if_rt[4:]) call(if_rt[:3] + ['add', 'proto', 'static'] + if_rt[4:])
else:
def check_no_default_route():
try:
while True:
for route in call(('ip', '-6', 'route', 'show',
'default')).splitlines():
if ' proto 42 ' not in route:
logging.fatal("Detected default route (%s)"
" whereas you specified --table=0."
" Fix your configuration.", route)
return
time.sleep(60)
except:
utils.log_exception()
finally:
exit(1)
t = threading.Thread(target=check_no_default_route)
t.daemon = True
t.start()
ip('route', 'unreachable', *x) ip('route', 'unreachable', *x)
config.babel_args += config.iface_list config.babel_args += config.iface_list
...@@ -350,10 +373,6 @@ def main(): ...@@ -350,10 +373,6 @@ def main():
# main loop # main loop
if tunnel_manager is None: if tunnel_manager is None:
t = threading.Thread(target=lambda:
exit(os.WEXITSTATUS(os.wait()[1])))
t.daemon = True
t.start()
time.sleep(max(0, next_renew - time.time())) time.sleep(max(0, next_renew - time.time()))
raise ReexecException("Restart to renew certificate") raise ReexecException("Restart to renew certificate")
cleanup += tunnel_manager.delInterfaces, tunnel_manager.killAll cleanup += tunnel_manager.delInterfaces, tunnel_manager.killAll
...@@ -393,8 +412,7 @@ def main(): ...@@ -393,8 +412,7 @@ def main():
except KeyboardInterrupt: except KeyboardInterrupt:
return 0 return 0
except Exception: except Exception:
f = traceback.format_exception(*sys.exc_info()) utils.log_exception()
logging.error('%s%s', f.pop(), ''.join(f))
sys.exit(1) sys.exit(1)
try: try:
sys.exitfunc() sys.exitfunc()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment