Commit 6408b7e1 authored by Julien Muchembled's avatar Julien Muchembled Committed by Joanne Hugé

re6st protocol 8: redistribute default route with src prefix

This fixes default packet redirection when merging multiple re6st
networks. Nodes will then install multiple default routes for each re6st
network with the correspond src-prefix.

The changes include:

- redistribute default route with src prefix on gateways
- remove the now obsolete default option
- if subtrees is not available in the kernel, delete src prefix from
  the default route and don't advertise the default route to other
  nodes
- if there is no src prefix in the redistributed default route, add
  one to be retro-compatible with the old gateway behaviour
parent 5d05c34b
#!/usr/bin/python2 #!/usr/bin/python2
import atexit, errno, logging, os, shutil, signal import atexit, errno, logging, os, shutil, signal
import socket, struct, subprocess, sys, time, threading import socket, struct, subprocess, sys
from collections import deque from collections import deque
from functools import partial from functools import partial
if 're6st' not in sys.modules: if 're6st' not in sys.modules:
...@@ -75,12 +75,9 @@ def getConfig(): ...@@ -75,12 +75,9 @@ def getConfig():
_('-B', dest='babel_args', metavar='ARG', action='append', default=[], _('-B', dest='babel_args', metavar='ARG', action='append', default=[],
help="Extra arguments to forward to Babel.") help="Extra arguments to forward to Babel.")
_('-D', '--default', action='store_true', _('-D', '--default', action='store_true',
help="Access internet via this network (in this case, make sure you" help="This is an obsolete option and ignored.")
" don't already have a default route), or if your kernel was"
" compiled without support for source address based routing"
" (CONFIG_IPV6_SUBTREES). Meaningless with --gateway.")
_('--table', type=int, choices=(0,), _('--table', type=int, choices=(0,),
help="DEPRECATED: Use --default instead of --table=0") help="This is an obsolete option and ignored.")
_('--gateway', action='store_true', _('--gateway', action='store_true',
help="Act as a gateway for this network (the default route will be" 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.") " exported). Do never use it if you don't know what it means.")
...@@ -159,20 +156,28 @@ def main(): ...@@ -159,20 +156,28 @@ def main():
if config.max_clients is None: if config.max_clients is None:
config.max_clients = cache.max_clients config.max_clients = cache.max_clients
if config.table is not None:
logging.warning("--table option is deprecated: use --default instead")
config.default = True
if config.default and config.gateway:
sys.exit("error: conflicting options --default and --gateway")
if config.disable_proto is None: if config.disable_proto is None:
config.disable_proto = DEFAULT_DISABLED_PROTO config.disable_proto = DEFAULT_DISABLED_PROTO
elif 'none' in config.disable_proto: elif 'none' in config.disable_proto:
config.disable_proto = () config.disable_proto = ()
if config.default:
x = ['ip', '-6', 'route', 'add', 'unreachable', '::/128', 'from', '::/128']
has_ipv6_subtrees = not subprocess.call(x)
if has_ipv6_subtrees:
x[3] = 'del'
subprocess.check_call(x)
else:
logging.warning(
"Source address based routing is not enabled in your kernel"
" (CONFIG_IPV6_SUBTREES). %s",
"Assuming you don't merge several re6st networks so routes from"
" other networks will be ignored." if config.gateway else
"This node won't receive traffic to be routed to the internet."
" Make sure you don't already have a default route.")
# Make sure we won't tunnel over re6st. # Make sure we won't tunnel over re6st.
config.disable_proto = tuple({'tcp6', 'udp6'}.union( config.disable_proto = tuple({'tcp6', 'udp6'}.union(
config.disable_proto)) config.disable_proto))
def add_tunnels(iface_list): def add_tunnels(iface_list):
for iface in iface_list: for iface in iface_list:
config.babel_args += '-C', 'interface %s type tunnel' % iface config.babel_args += '-C', 'interface %s type tunnel' % iface
...@@ -376,47 +381,12 @@ def main(): ...@@ -376,47 +381,12 @@ def main():
subprocess.call(if_rt) subprocess.call(if_rt)
if_rt[4] = my_subnet if_rt[4] = my_subnet
cleanup.append(lambda: subprocess.call(if_rt)) cleanup.append(lambda: subprocess.call(if_rt))
if config.default:
def check_no_default_route():
for route in call(('ip', '-6', 'route', 'show',
'default')).splitlines():
if not (' proto babel ' in route
or ' proto 42 ' in route):
sys.exit("Detected default route (%s)"
" whereas you specified --default."
" Fix your configuration." % route)
check_no_default_route()
def check_no_default_route_thread():
try:
while True:
time.sleep(60)
try:
check_no_default_route()
except OSError, e:
if e.errno != errno.ENOMEM:
raise
except:
utils.log_exception()
finally:
exit.kill_main(1)
t = threading.Thread(target=check_no_default_route_thread)
t.daemon = True
t.start()
else:
x = ['ip', '-6', 'route', 'add',
'unreachable', '::/128', 'from', '::/128']
if subprocess.call(x):
sys.exit('error: Source address based routing is not'
' enabled in your kernel (CONFIG_IPV6_SUBTREES).'
' Try with the --default option.')
x[3] = 'del'
subprocess.check_call(x)
ip('route', 'unreachable', my_network) ip('route', 'unreachable', my_network)
config.babel_args += config.iface_list config.babel_args += config.iface_list
cleanup.append(plib.router((my_ip, len(subnet)), ipv4, cleanup.append(plib.router((my_ip, len(subnet)), ipv4,
my_network if config.gateway or config.default else None, (my_network, config.gateway, has_ipv6_subtrees),
config.gateway, cache.hello, cache.hello,
os.path.join(config.log, 'babeld.log'), os.path.join(config.log, 'babeld.log'),
os.path.join(config.state, 'babeld.state'), os.path.join(config.state, 'babeld.state'),
os.path.join(config.run, 'babeld.pid'), os.path.join(config.run, 'babeld.pid'),
......
...@@ -62,8 +62,10 @@ def client(iface, address_list, encrypt, *args, **kw): ...@@ -62,8 +62,10 @@ def client(iface, address_list, encrypt, *args, **kw):
return openvpn(iface, encrypt, *remote, **kw) return openvpn(iface, encrypt, *remote, **kw)
def router(ip, ip4, src, gateway, hello_interval, log_path, state_path, pidfile, def router(ip, ip4, rt6, hello_interval, log_path, state_path, pidfile,
control_socket, default, hmac, *args, **kw): control_socket, default, hmac, *args, **kw):
network, gateway, has_ipv6_subtrees = rt6
network_mask = int(network[network.index('/')+1:])
ip, n = ip ip, n = ip
hmac_sign, hmac_accept = hmac hmac_sign, hmac_accept = hmac
if ip4: if ip4:
...@@ -75,12 +77,6 @@ def router(ip, ip4, src, gateway, hello_interval, log_path, state_path, pidfile, ...@@ -75,12 +77,6 @@ def router(ip, ip4, src, gateway, hello_interval, log_path, state_path, pidfile,
'-S', state_path, '-S', state_path,
'-I', pidfile, '-I', pidfile,
'-s', '-s',
# Force use of ipv6 subtrees because:
# - even Linux 2.6.32 has them
# - the fallback implementation using a separate table
# is not equivalent, at least not the way we use babeld
# (and we don't need RTA_SRC for ipv4).
'-C', 'ipv6-subtrees true',
'-C', 'redistribute local deny', '-C', 'redistribute local deny',
'-C', 'redistribute ip %s/%s eq %s' % (ip, n, n)] '-C', 'redistribute ip %s/%s eq %s' % (ip, n, n)]
if hmac_sign: if hmac_sign:
...@@ -97,13 +93,37 @@ def router(ip, ip4, src, gateway, hello_interval, log_path, state_path, pidfile, ...@@ -97,13 +93,37 @@ def router(ip, ip4, src, gateway, hello_interval, log_path, state_path, pidfile,
cmd += '-C', 'default ' + default cmd += '-C', 'default ' + default
if ip4: if ip4:
cmd += '-C', 'redistribute ip %s/%s eq %s' % (ip4, n4, n4) cmd += '-C', 'redistribute ip %s/%s eq %s' % (ip4, n4, n4)
if src:
if gateway: if gateway:
cmd += '-C', 'redistribute ip ::/0 eq 0 src-prefix ' + src cmd += '-C', 'redistribute ip ::/0 eq 0 src-prefix ' + network
if not has_ipv6_subtrees:
cmd += (
'-C', 'in ip %s ge %s' % (network, network_mask),
'-C', 'in ip ::/0 deny',
)
elif has_ipv6_subtrees:
# For backward compatibility, if the default route comes from old
# version (without source-prefix).
cmd += (
'-C', 'install ip ::/0 eq 0 src-ip ::/0 src-eq 0 src-prefix ' + network,
)
else: else:
cmd += '-C', 'install ip ::/0 eq 0 src-prefix ' + src + ' pref-src ' + ip # We patch babeld:
# - ipv6-subtrees is always true by default
# - if false, source prefix is cleared when the route is installed
cmd += (
'-C', 'ipv6-subtrees false',
# Accept default route from our network.
'-C', 'in ip ::/0 eq 0 src-ip %s src-eq %s' % (network, network_mask),
# Ignore default route from other networks. For backward
# compatibility we accept default routes from old version
# (without source-prefix).
'-C', 'in ip ::/0 eq 0 src-ip ::/0 src-ge 1 deny',
# Tell neighbours not to route to the internet via us,
# because we could be a black hole in case of misconfiguration.
'-C', 'out ip ::/0 eq 0 deny',
)
cmd += ('-C', 'redistribute deny', cmd += ('-C', 'redistribute deny',
'-C', 'install ip ::/0 ge 1 pref-src ' + ip) '-C', 'install pref-src ' + ip)
if ip4: if ip4:
cmd += '-C', 'install pref-src ' + ip4 cmd += '-C', 'install pref-src ' + ip4
if control_socket: if control_socket:
......
...@@ -32,7 +32,7 @@ if dirty: ...@@ -32,7 +32,7 @@ if dirty:
# they are intended to the network admin. # they are intended to the network admin.
# Only 'protocol' is important and it must be increased whenever they would be # Only 'protocol' is important and it must be increased whenever they would be
# a wish to force an update of nodes. # a wish to force an update of nodes.
protocol = 7 protocol = 8
min_protocol = 1 min_protocol = 1
if __name__ == "__main__": if __name__ == "__main__":
......
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