From 82d61045001b4efe8f7a69179470782099dae558 Mon Sep 17 00:00:00 2001 From: Claudio-Daniel Freire Date: Mon, 23 May 2011 10:59:42 +0200 Subject: [PATCH] vroute script to permite manipulation of routing tables in a secure manner (ie: doesn't affect other slices) --- exec/vroute | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100755 exec/vroute diff --git a/exec/vroute b/exec/vroute new file mode 100755 index 0000000..63a9029 --- /dev/null +++ b/exec/vroute @@ -0,0 +1,158 @@ +#!/usr/bin/python +# VSYS script to configure routes on virtual network interfaces from the root slice +# Thom Haddow - 06/10/09 +# +# Gets slice name as argv[1] +# Takes routing rules on stdin, one per line +# rule := command ' ' target ' gw ' host device +# command := 'add' | 'del' +# target := host | network +# network := host [ '/' netmask ] +# netmask := number +# host := number '.' number '.' number '.' number +# number := [0-9]+ +# device := ( tun | tap ) slice '-' number +# slice := +# +# All networks and gateways MUST belong to the virtual +# network assigned to the slice (according to the vsys_vnet tag) +# +# Examples: +# +# add 10.0.0.0/24 gw 10.0.0.1 tap754-0 +# del 10.0.0.0/24 gw 10.0.0.1 tap754-0 +# + + +import sys +import pwd +import re +import socket +import struct +import os +import string +import subprocess + +vsys_config_dir = "/etc/planetlab/vsys-attributes" + +if len(sys.argv) != 2: sys.exit(1) + +# VSYS scripts get slicename as $1 +slicename=sys.argv[1] +sliceid = pwd.getpwnam(slicename).pw_uid + +netblock_config=os.path.join(vsys_config_dir,slicename,"vsys_vnet") + +# Read netblock allocation file +vnet_base = None +vnet_mask = None + +try: + for netblock in open(netblock_config,'r'): + vnet_base, vnet_mask = netblock.split('/') + vnet_mask = int(vnet_mask) +except: + vnet_base = vnet_mask = None + +if vnet_base is None: + #print >>sys.stderr, "Could not find entry for slice %s in netblock config file %s" % (slicename, netblock_config) + #sys.exit(1) + vnet_base = '192.168.2.0' + vnet_mask = 24 + +vnet_int = struct.unpack('!L', socket.inet_aton(vnet_base))[0] +vnet_int = (vnet_int >> vnet_mask) << vnet_mask + +mask_int = (0xffffffff << vnet_mask) & 0xffffffff + +# rule line regex +rule_re = r"(?Padd|del)\s+(?P(?:\d{1,3}[.]){3}\d{1,3})(?:/(?P\d{1,2}))?\s+gw\s+(?P(?:\d{1,3}[.]){3}\d{1,3}) (?P(?:tun|tap)%d-\d{1,5})" % (sliceid,) +rule_re = re.compile(rule_re) + +### Read args from stdin +for argline in sys.stdin: + argline = argline.strip() + + # Match rule against the regex, + # validating overall structure in the process + match = rule_re.match(argline) + if not match: + print >>sys.stderr, "Invalid rule %r:" % (argline,) + continue + + # Validate IPs involved + try: + target_ip_int = struct.unpack('!L', + socket.inet_aton(match.group('targetbase')))[0] + except Exception,e: + print >>sys.stderr, "Invalid target ip: %s" % (e,) + continue + + try: + gw_ip_int = struct.unpack('!L', + socket.inet_aton(match.group('gw')))[0] + except Exception,e: + print >>sys.stderr, "Invalid target ip: %s" % (e,) + continue + + if match.group('targetprefix'): + try: + target_mask = int(match.group('targetprefix')) + except Exception,e: + print >>sys.stderr, "Invalid target mask: %s" % (e,) + continue + else: + # host route + target_mask = 32 + + ifname = match.group('dev') + if not ifname: + # Shouldn't happen, but just in case + print >>sys.stderr, "Invalid rule %r: Unspecified interface" % (argline,) + continue + + # Make sure all IPs/networks fall within the assigne vnet + if target_mask < vnet_mask: + print >>sys.stderr, "Invalid rule %r: target must belong to the %s/%s network" % (argline, vnet_base, vnet_mask) + continue + + if (target_ip_int & mask_int) != vnet_int: + print >>sys.stderr, "Invalid rule %r: target must belong to the %s/%s network" % (argline, vnet_base, vnet_mask) + continue + + if (gw_ip_int & mask_int) != vnet_int: + print >>sys.stderr, "Invalid rule %r: gateway must belong to the %s/%s network" % (argline, vnet_base, vnet_mask) + continue + + # Revalidate command (just in case) + command = match.group("cmd") + if command not in ('add','del'): + print >>sys.stderr, "Invalid rule %r: invalid command" % (argline,) + continue + + # Apply the rule + routeargs = [ "/sbin/route", command ] + + target_ip_str = socket.inet_ntoa( + struct.pack('!L', target_ip_int)) + + gw_ip_str = socket.inet_ntoa( + struct.pack('!L', gw_ip_int)) + + if target_mask != 32: + routeargs.extend([ + "-net", "%s/%d" % (target_ip_str, target_mask) + ]) + else: + routeargs.append(target_ip_str) + + routeargs.extend([ + "gw", gw_ip_str, + "dev", ifname, + ]) + + proc = subprocess.Popen(routeargs) + if proc.wait(): + print >>sys.stderr, "Could not set up route" + + -- 2.43.0