Commit d2d799f1 authored by Julien Muchembled's avatar Julien Muchembled

Better support of default route

parent 2477ff52
...@@ -186,7 +186,7 @@ if 1: ...@@ -186,7 +186,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 -v%u --registry %s %s' node.screen('../re6stnet @%s/re6stnet.conf --table 0 -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)
......
...@@ -52,7 +52,7 @@ def client(iface, server_address, encrypt, *args, **kw): ...@@ -52,7 +52,7 @@ def client(iface, server_address, encrypt, *args, **kw):
return openvpn(iface, encrypt, *remote, **kw) return openvpn(iface, encrypt, *remote, **kw)
def router(subnet, hello_interval, gateway, log_path, state_path, pidfile, def router(subnet, hello_interval, table, log_path, state_path, pidfile,
tunnel_interfaces, *args, **kw): tunnel_interfaces, *args, **kw):
s = utils.ipFromBin(subnet) s = utils.ipFromBin(subnet)
n = len(subnet) n = len(subnet)
...@@ -66,7 +66,12 @@ def router(subnet, hello_interval, gateway, log_path, state_path, pidfile, ...@@ -66,7 +66,12 @@ def router(subnet, hello_interval, gateway, log_path, state_path, pidfile,
'-C', 'redistribute local deny', '-C', 'redistribute local deny',
'-C', 'redistribute ip %s/%u eq %u' % (s, n, n), '-C', 'redistribute ip %s/%u eq %u' % (s, n, n),
'-C', 'redistribute deny'] '-C', 'redistribute deny']
if gateway: if table:
cmd += '-t%u' % table, '-T%u' % table
elif table is None:
# Tell peers not to route external IP via me.
cmd += '-C', 'out eq 0 deny'
else:
cmd[-2:-2] = '-C', 'redistribute ip ::/0 eq 0' cmd[-2:-2] = '-C', 'redistribute ip ::/0 eq 0'
for iface in tunnel_interfaces: for iface in tunnel_interfaces:
cmd += '-C', 'interface %s rxcost 512' % iface cmd += '-C', 'interface %s rxcost 512' % iface
......
...@@ -50,6 +50,9 @@ def getConfig(): ...@@ -50,6 +50,9 @@ def getConfig():
" hello interval. It takes between 3 and 4 times the" " hello interval. It takes between 3 and 4 times the"
" 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,
help="Use given table id. If 0, the main table will be used and any"
" existing default route will be exported.")
_ = 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=[],
...@@ -148,15 +151,22 @@ def main(): ...@@ -148,15 +151,22 @@ def main():
for x in pp: for x in pp:
server_tunnels.setdefault('re6stnet-' + x[1], x) server_tunnels.setdefault('re6stnet-' + x[1], x)
def call(cmd):
logging.debug('%r', cmd)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.returncode:
raise EnvironmentError("%r failed with error %u\n%s"
% (' '.join(cmd), p.returncode, stderr))
return stdout
def required(arg): def required(arg):
if not getattr(config, arg): if not getattr(config, arg):
sys.exit("error: argument --%s is required" % arg) sys.exit("error: argument --%s is required" % arg)
def ip(object, *args): def ip(object, *args):
args = ['ip', object, 'add'] + list(args) args = ['ip', '-6', object, 'add'] + list(args)
r = subprocess.call(args) call(args)
if r: args[3] = 'del'
sys.exit(r)
args[2] = 'del'
cleanup.append(lambda: subprocess.call(args)) cleanup.append(lambda: subprocess.call(args))
try: try:
...@@ -180,16 +190,9 @@ def main(): ...@@ -180,16 +190,9 @@ def main():
else: else:
tunnel_manager = write_pipe = None tunnel_manager = write_pipe = None
config.babel_args += config.iface_list cleanup = []
cleanup = [plib.router(subnet, config.hello, tunnel_manager is not None,
os.path.join(config.log, 'babeld.log'),
os.path.join(config.state, 'babeld.state'),
config.babel_pidfile, tunnel_interfaces,
*config.babel_args).terminate]
try: try:
my_network = "%s/%u" % (utils.ipFromBin(network), len(network)) my_network = "%s/%u" % (utils.ipFromBin(network), len(network))
ip('route', 'unreachable', my_network, 'proto', 'static')
# Source address selection is defined by RFC 3484, and in most # Source address selection is defined by RFC 3484, and in most
# applications, it usually works thanks to rule 5 (prefer outgoing # applications, it usually works thanks to rule 5 (prefer outgoing
# interface). But here, it rarely applies because we use several # interface). But here, it rarely applies because we use several
...@@ -217,14 +220,44 @@ def main(): ...@@ -217,14 +220,44 @@ def main():
'--ping-exit', str(timeout), *config.openvpn_args).kill) '--ping-exit', str(timeout), *config.openvpn_args).kill)
ip('addr', my_ip, 'dev', config.main_interface) ip('addr', my_ip, 'dev', config.main_interface)
if_rt = ['ip', '-6', 'route', 'del',
'fe80::/64', 'dev', config.main_interface]
if config.main_interface == 'lo': if config.main_interface == 'lo':
# WKRD: The kernel does not remove these routes on exit. # WKRD: Removed this useless route now, since the kernel does
# The first one can be removed now. # not even remove it on exit.
del_rtr = ['ip', 'route', 'del', 'unreachable', 'fe80::/64', subprocess.call(if_rt)
'dev', 'lo'] if_rt[4] = '%s/%u' % (utils.ipFromBin(subnet), len(subnet))
subprocess.call(del_rtr) cleanup.append(lambda: subprocess.call(if_rt))
del_rtr[4] = '%s/%u' % (utils.ipFromBin(subnet), len(subnet)) x = [my_network]
cleanup.append(lambda: subprocess.call(del_rtr)) if config.table:
x += 'table', str(config.table)
try:
ip('rule', 'from', *x)
except EnvironmentError:
logging.warning("I refuse to forward packets whose"
" destination IP is not part of %s, because your kernel"
" was compiled without support for source-based routing"
" policy. Pass --table 0 if you are sure you don't"
" have any default route.", my_network)
# XXX: The issue with such fallback is that a node will be
# unreachable from outside if it is only connected to
# limited peers. This could be fixed the same way as
# for checking connectedness.
config.table = None
del x[1:]
else:
ip('rule', 'to', *x)
call(if_rt)
if_rt += x[1:]
call(if_rt[:3] + ['add', 'proto', 'static'] + if_rt[4:])
ip('route', 'unreachable', *x)
config.babel_args += config.iface_list
cleanup.append(plib.router(subnet, config.hello, config.table,
os.path.join(config.log, 'babeld.log'),
os.path.join(config.state, 'babeld.state'),
config.babel_pidfile, tunnel_interfaces,
*config.babel_args).terminate)
if config.up: if config.up:
r = os.system(config.up) r = os.system(config.up)
if r: if r:
...@@ -255,9 +288,9 @@ def main(): ...@@ -255,9 +288,9 @@ def main():
if forwarder and t >= forwarder.next_refresh: if forwarder and t >= forwarder.next_refresh:
forwarder.refresh() forwarder.refresh()
finally: finally:
for cleanup in cleanup: while cleanup:
try: try:
cleanup() cleanup.pop()()
except: except:
pass pass
except sqlite3.Error: except sqlite3.Error:
......
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