From: Andy Bavier Date: Thu, 8 Aug 2013 21:27:19 +0000 (-0400) Subject: Set up iptables and dnsmasq for NAT X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=80b7e1174de5f63e0c86cd26446064679b5bceea;p=nodemanager.git Set up iptables and dnsmasq for NAT --- diff --git a/net.py b/net.py index b962864..da33e54 100644 --- a/net.py +++ b/net.py @@ -2,6 +2,7 @@ # system provided modules import os, string, time, socket +from socket import inet_aton # PlanetLab system modules import sioc, plnet @@ -9,6 +10,7 @@ import sioc, plnet # local modules import plnode.bwlimit as bwlimit import logger, iptables, tools +import subprocess # we can't do anything without a network priority=1 @@ -40,6 +42,8 @@ def GetSlivers(data, config, plc): ################## plnet.InitInterfaces(logger, plc, data) + + """ if 'OVERRIDES' in dir(config): if config.OVERRIDES.get('net_max_rate') == '-1': logger.log("net: Slice and node BW Limits disabled.") @@ -53,6 +57,9 @@ def GetSlivers(data, config, plc): InitNodeLimit(data) InitI2(plc, data) InitNAT(plc, data) + """ + + InitPlanetStack(plc, data) def InitNodeLimit(data): @@ -170,3 +177,110 @@ def InitNAT(plc, data): fields['source'] = "0.0.0.0/0" ipt.add_pf(fields) ipt.commit() + +# Helper functions for converting to CIDR notation +def get_net_size(netmask): + binary_str = '' + for octet in netmask: + binary_str += bin(int(octet))[2:].zfill(8) + return str(len(binary_str.rstrip('0'))) + +def to_cidr(ipaddr, netmask): + # validate input + inet_aton(ipaddr) + inet_aton(netmask) + + ipaddr = ipaddr.split('.') + netmask = netmask.split('.') + + net_start = [str(int(ipaddr[x]) & int(netmask[x])) for x in range(0,4)] + return '.'.join(net_start) + '/' + get_net_size(netmask) + +def ipaddr_range(network, broadcast): + start = network.split('.') + end = broadcast.split('.') + + # Assume interface always claims the first address in the block + start[3] = str(int(start[3]) + 2) + end[3] = str(int(end[3]) - 1) + + return '.'.join(start) + ',' + '.'.join(end) + +def InitPlanetStack(plc, data): + + for interface in data[KEY_NAME]: + try: + settings = plc.GetInterfaceTags({'interface_tag_id': interface['interface_tag_ids']}) + except: + continue + + tags = {} + for setting in settings: + tags[setting['tagname'].upper()] = setting['value'] + + if 'IFNAME' in tags: + dev = tags['IFNAME'] + else: + # Skip devices that don't have names + logger.log('net:InitPlanetStack: Device has no name, skipping...') + continue + + logger.log('net:InitPlanetStack: Processing device %s' % dev) + + if 'NAT' in tags: + # Enable iptables MASQ on this device + # Right now the subnet is hardcoded, should instead use interface's subnet + ipaddr = interface['ip'] + netmask = interface['netmask'] + + if (ipaddr and netmask): + try: + cidr = to_cidr(ipaddr, netmask) + except: + logger.log('net:InitPlanetStack: could not convert ipaddr %s and netmask %s to CIDR' % (ipaddr, netmask)) + + if cidr: + cmd = ['/sbin/iptables', '-t', 'nat', '-C', 'POSTROUTING', '-s', cidr, + '!', '-d', cidr, '-j', 'MASQUERADE'] + try: + logger.log('net:InitPlanetStack: checking if NAT iptables rule present for device %s' % dev) + subprocess.check_call(cmd) + except: + logger.log('net:InitPlanetStack: adding NAT iptables NAT for device %s' % dev) + cmd[3] = '-A' + try: + subprocess.check_call(cmd) + except: + logger.log('net:InitPlanetStack: failed to add NAT iptables rule for device %s' % dev) + + # Enable dnsmasq for this interface + # Check if dnsmasq already running + start_dnsmasq = True + pidfile = '/var/run/dnsmasq-%s.pid' % dev + try: + pid = open(pidfile, 'r').read().strip() + if os.path.exists('/proc/%s' % pid): + start_dnsmasq = False + logger.log('net:InitPlanetStack: dnsmasq already running on device %s' % dev) + except: + pass + + if start_dnsmasq: + try: + logger.log('net:InitPlanetStack: starting dnsmasq on device %s' % dev) + iprange = ipaddr_range(interface['network'], interface['broadcast']) + logger.log('net:InitPlanetStack: IP range: %s' % iprange) + subprocess.check_call(['/usr/sbin/dnsmasq', + '--strict-order', + '--bind-interfaces', + '--local=//', + '--domain-needed', + '--pid-file=%s' % pidfile, + '--conf-file=', + '--interface=%s' % dev, + '--dhcp-range=%s' % iprange, + '--dhcp-leasefile=/var/lib/dnsmasq/%s.leases' % dev, + '--dhcp-no-override']) + + except: + logger.log('net:InitPlanetStack: failed to start dnsmasq for device %s' % dev)