Commit 2fb63515 authored by Julien Muchembled's avatar Julien Muchembled

Add support for ipv4 payload

There is no plan for a default ipv4 route.
parent f128ba9d
#!/usr/bin/python
import math, nemu, os, signal, socket, subprocess, sys, time, weakref
import math, nemu, os, re, signal, socket, subprocess, sys, time, weakref
from collections import defaultdict
IPTABLES = 'iptables'
SCREEN = 'screen'
......@@ -50,6 +50,8 @@ for name in """internet=I registry=R
globals()[name] = node = nemu.Node()
node.name = name
node.short = short
node.Popen(('sysctl', '-q',
'net.ipv4.icmp_echo_ignore_broadcasts=0')).wait()
node._screen = node.Popen((SCREEN, '-DmS', name))
node.screen = (lambda name: lambda *cmd:
subprocess.call([SCREEN, '-r', name, '-X', 'eval'] + map(
......@@ -237,7 +239,12 @@ def node_by_ll(addr):
for a in a:
p = a['prefix_len']
a = a['address']
if a.startswith('2001:db8:'):
if a.startswith('10.'):
if a.startswith('10.42.'):
assert not p % 8
_ll[socket.inet_ntoa(socket.inet_aton(
a)[:p/8].ljust(4, '\0'))] = n, t
elif a.startswith('2001:db8:'):
assert not p % 8
a = socket.inet_ntop(socket.AF_INET6,
socket.inet_pton(socket.AF_INET6,
......@@ -247,12 +254,13 @@ def node_by_ll(addr):
_ll[a] = n, t
return _ll[addr]
def route_svg(z = 4, default = type('', (), {'short': None})):
def route_svg(ipv4, z = 4, default = type('', (), {'short': None})):
graph = {}
for n in nodes:
g = graph[n] = defaultdict(list)
for r in n.get_routes():
if r.prefix is None or r.prefix.startswith('2001:db8:'):
if (r.prefix and r.prefix.startswith('10.42.') if ipv4 else
r.prefix is None or r.prefix.startswith('2001:db8:')):
try:
g[node_by_ll(r.nexthop)].append(
node_by_ll(r.prefix)[0] if r.prefix else default)
......@@ -297,13 +305,25 @@ if len(sys.argv) > 1:
import SimpleHTTPServer, SocketServer
class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler):
_path_match = re.compile('/(.+)\.html$').match
pages = 'ipv6', 'ipv4', 'tunnels'
def do_GET(self):
svg = None
if self.path == '/route.html':
other = 'tunnel'
svg = route_svg()
elif self.path == '/tunnel.html':
other = 'route'
try:
page = self.pages.index(self._path_match(self.path).group(1))
except AttributeError, ValueError:
if self.path == '/':
self.send_response(302)
self.send_header('Location', self.pages[0] + '.html')
self.end_headers()
else:
self.send_error(404)
return
if page < 2:
svg = route_svg(page)
else:
gv = registry.Popen(('python', '-c', r"""if 1:
import math, json
from re6st.registry import RegistryClient
......@@ -335,21 +355,16 @@ if len(sys.argv) > 1:
if not svg:
self.send_error(500)
return
else:
if self.path == '/':
self.send_response(302)
self.send_header('Location', 'route.html')
self.end_headers()
else:
self.send_error(404)
return
mt = 'text/html'
body = """<html>
<head><meta http-equiv="refresh" content="10"/></head>
<body><a style="position: absolute" href="%s.html">%ss</a>
<body><span style="position: absolute">%s</span>
%s
</body>
</html>""" % (other, other, svg[svg.find('<svg'):])
</html>""" % (' '.join(x if i == page else
'<a href="%s.html">%s</a>' % (x, x)
for i, x in enumerate(self.pages)),
svg[svg.find('<svg'):])
self.send_response(200)
self.send_header('Content-Length', len(body))
self.send_header('Content-type', mt + '; charset=utf-8')
......
......@@ -29,16 +29,17 @@ def _get_all_route_data():
if line == "":
continue
# PATCH: parse 'from'
# PATCH: 'dev' is missing on 'unreachable' ipv4 routes
match = re.match('(?:(unicast|local|broadcast|multicast|throw|'
r'unreachable|prohibit|blackhole|nat) )?(\S+)(?: from (\S+))?'
r'(?: via (\S+))? dev (\S+).*(?: metric (\d+))?', line)
r'(?: via (\S+))?(?: dev (\S+))?.*(?: metric (\d+))?', line)
if not match:
raise RuntimeError("Invalid output from `ip route': `%s'" % line)
tipe = match.group(1) or "unicast"
prefix = match.group(2)
#src = match.group(3)
nexthop = match.group(4)
interface = ifdata[match.group(5)]
interface = ifdata[match.group(5) or "lo"]
metric = match.group(6)
if prefix == "default" or re.search(r'/0$', prefix):
prefix = None
......
......@@ -6,3 +6,4 @@ run registry/run
hello 4
client-count 2
tunnel-refresh 100
ipv4 10.42.0.0/16 8
......@@ -83,6 +83,9 @@ def main():
_('--anonymous-prefix-length', type=int,
help="Length of allocated anonymous prefixes."
" If 0 or unset, registration by email is required")
_('--ipv4', nargs=2, metavar=("IP/N", "PLEN"),
help="Enable ipv4. Each node is assigned a subnet of length PLEN"
" inside network IP/N.")
_('-l', '--logfile', default='/var/log/re6stnet/registry.log',
help="Path to logging file.")
_('-r', '--run', default='/var/run/re6stnet',
......@@ -122,6 +125,15 @@ def main():
parser.error("--min-protocol: value must between %s and %s (included)"
% (version.min_protocol, version.protocol))
if config.ipv4:
ipv4, plen = config.ipv4
try:
ip, n = ipv4.split('/')
config.ipv4 = "%s/%s" % (socket.inet_ntoa(socket.inet_aton(ip)),
int(n)), int(plen)
except (socket.error, ValueError):
parser.error("invalid argument --ipv4")
utils.setupLog(config.verbose, config.logfile)
if config.max_clients is None:
......
......@@ -266,6 +266,8 @@ class Babel(object):
a = len(self.network)
for route in routes:
assert route.flags & 1, route # installed
if route.prefix.startswith('\0\0\0\0\0\0\0\0\0\0\xff\xff'):
continue
assert route.neigh_address == route.nexthop, route
address = route.neigh_address, route.ifindex
neigh_routes = n[address]
......
......@@ -59,9 +59,11 @@ def client(iface, address_list, encrypt, *args, **kw):
return openvpn(iface, encrypt, *remote, **kw)
def router(ip, src, hello_interval, log_path, state_path,
def router(ip, ip4, src, hello_interval, log_path, state_path,
pidfile, control_socket, default, *args, **kw):
ip, n = ip
if ip4:
ip4, n4 = ip4
cmd = ['babeld',
'-h', str(hello_interval),
'-H', str(hello_interval),
......@@ -72,12 +74,16 @@ def router(ip, src, hello_interval, log_path, state_path,
'-C', 'default ' + default,
'-C', 'redistribute local deny',
'-C', 'redistribute ip %s/%s eq %s' % (ip, n, n)]
if ip4:
cmd += '-C', 'redistribute ip %s/%s eq %s' % (ip4, n4, n4)
if src:
cmd += '-C', 'install ip ::/0 eq 0 src-prefix ' + src
elif src is None:
cmd += '-C', 'redistribute ip ::/0 eq 0'
cmd += ('-C', 'redistribute deny',
'-C', 'install pref-src ' + ip)
if ip4:
cmd += '-C', 'install pref-src ' + ip4
if control_socket:
cmd += '-R', '%s' % control_socket
cmd += args
......
......@@ -120,6 +120,8 @@ class RegistryServer(object):
'protocol': version.protocol,
'registry_prefix': self.prefix,
}
if self.config.ipv4:
kw['ipv4'], kw['ipv4_sublen'] = self.config.ipv4
for x in ('client_count', 'encrypt', 'hello',
'max_clients', 'min_protocol', 'tunnel_refresh'):
kw[x] = getattr(self.config, x)
......
......@@ -168,7 +168,8 @@ class BaseTunnelManager(object):
# TODO: To minimize downtime when network parameters change, we should do
# our best to not restart any process. Ideally, this list should be
# empty and the affected subprocesses reloaded.
NEED_RESTART = frozenset(('babel_default', 'encrypt', 'hello'))
NEED_RESTART = frozenset(('babel_default', 'encrypt', 'hello',
'ipv4', 'ipv4_sublen'))
_forward = None
......
......@@ -229,6 +229,11 @@ def main():
raise EnvironmentError("%r failed with error %u\n%s"
% (' '.join(cmd), p.returncode, stderr))
return stdout
def ip4(object, *args):
args = ['ip', '-4', object, 'add'] + list(args)
call(args)
args[3] = 'del'
cleanup.append(lambda: subprocess.call(args))
def ip(object, *args):
args = ['ip', '-6', object, 'add'] + list(args)
call(args)
......@@ -265,6 +270,31 @@ def main():
try:
exit.acquire()
ipv4 = getattr(cache, 'ipv4', None)
if ipv4:
serial = int(cert.cert.get_subject().serialNumber)
if serial.bit_length() <= cache.ipv4_sublen <= 16:
dot4 = lambda x: socket.inet_ntoa(struct.pack('!I', x))
ip4('route', 'unreachable', ipv4, 'proto', 'static')
ipv4, n = ipv4.split('/')
ipv4, = struct.unpack('!I', socket.inet_aton(ipv4))
n = int(n) + cache.ipv4_sublen
x = ipv4 | serial << 32 - n
ipv4 = dot4(x | (n < 31))
config.openvpn_args += '--ifconfig', \
ipv4, dot4((1<<32) - (1<<32-n))
ipv4 = ipv4, n
if not isinstance(tunnel_manager, tunnel.TunnelManager):
ip4('addr', "%s/%s" % ipv4,
'dev', config.main_interface)
if config.main_interface == "lo":
ip4('route', 'unreachable', "%s/%s" % (dot4(x), n),
'proto', 'static')
else:
logging.warning(
"IPv4 payload disabled due to wrong network parameters")
ipv4 = None
if os.uname()[2] < '2.6.40': # BBB
logging.warning("Fallback to ip-addrlabel because Linux < 3.0"
" does not support RTA_PREFSRC for ipv6. Note however that"
......@@ -335,7 +365,7 @@ def main():
ip('route', 'unreachable', my_network)
config.babel_args += config.iface_list
cleanup.append(plib.router((my_ip, len(subnet)),
cleanup.append(plib.router((my_ip, len(subnet)), ipv4,
None if config.gateway else
'' if config.default else
my_network, cache.hello,
......
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