--- /dev/null
+#!/usr/bin/python -tt
+
+# Author: Daniel Hokka Zakrisson <daniel@hozac.com>
+# $Id$
+
+import os
+import logger
+import subprocess
+
+class IPTables:
+ IPTABLES_RESTORE = "/sbin/iptables-restore"
+
+ def __init__(self):
+ self.extifs = []
+ self.intifs = []
+ self.pfs = []
+
+ def add(self, table, chain, rule):
+ self.rules[table][chain].append(rule)
+
+ def add_ext(self, interface):
+ self.extifs.append(interface)
+
+ def add_int(self, interface):
+ self.intifs.append(interface)
+
+ def add_pf(self, pf):
+ # XXX Should make sure the required fields are there
+ self.pfs.append(pf)
+
+ def commit(self):
+ # XXX This should check for errors
+ # and make sure the new ruleset differs from the current one
+
+ if (len(self.extifs) + len(self.intifs) + len(self.pfs)) == 0:
+ return True
+
+ restore = subprocess.Popen([self.IPTABLES_RESTORE], stdin=subprocess.PIPE)
+ restore.stdin.write("""*filter
+:INPUT ACCEPT [0:0]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+:BLACKLIST - [0:0]
+:LOGDROP - [0:0]
+:SLICESPRE - [0:0]
+:SLICES - [0:0]
+:PORTFW - [0:0]
+
+-A LOGDROP -j LOG
+-A LOGDROP -j DROP
+-A OUTPUT -j BLACKLIST
+-A OUTPUT -m mark ! --mark 0/65535 -j SLICESPRE
+-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
+""")
+
+ for int in self.intifs:
+ for ext in self.extifs:
+ restore.stdin.write("-A FORWARD -i %s -o %s -j ACCEPT\n" % (int, ext))
+ restore.stdin.write("-A SLICESPRE -o %s -j SLICES\n" % int)
+
+ restore.stdin.write("-A FORWARD -m state --state NEW -j PORTFW\n")
+ for pf in self.pfs:
+ rule = "-A PORTFW -p %s -d %s " % (pf['protocol'], pf['destination'])
+ if 'interface' in pf:
+ rule += "-i %s " % pf['interface']
+ if 'source' in pf:
+ rule += "-s %s " % pf['source']
+ rule += "--dport %s" % pf['new_dport']
+ restore.stdin.write(rule + "\n")
+
+ restore.stdin.write("-A FORWARD -j LOGDROP\n")
+
+ # This should have a way to add rules
+ restore.stdin.write("-A SLICES -j LOGDROP\n")
+ restore.stdin.write("""COMMIT
+*nat
+:PREROUTING ACCEPT [0:0]
+:POSTROUTING ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+:PORTFW - [0:0]
+:MASQ - [0:0]
+""")
+
+ for ext in self.extifs:
+ restore.stdin.write("-A MASQ -o %s -j MASQUERADE\n")
+
+ for pf in self.pfs:
+ rule = "-A PORTFW -p %s " % pf['protocol']
+ if 'interface' in pf:
+ rule += "-i %s " % pf['interface']
+ if 'source' in pf:
+ rule += "-s %s " % pf['source']
+ rule += "--dport %s -j DNAT --to %s:%s" % (pf['dport'], pf['destination'],
+ pf['new_dport'])
+ restore.stdin.write(rule + "\n")
+
+ restore.stdin.write("COMMIT\n")
+ restore.stdin.close()
+ return restore.wait() == 0
import bwlimit
import logger
import string
+import iptables
def GetSlivers(plc, data):
InitNodeLimit(data)
InitI2(plc, data)
+ InitNAT(plc, data)
def InitNodeLimit(data):
# query running network interfaces
i2nodes.append(node['ip'])
bwlimit.exempt_init('Internet2', i2nodes)
+def InitNAT(plc, data):
+ # query running network interfaces
+ devs = sioc.gifconf()
+ ips = dict(zip(devs.values(), devs.keys()))
+ macs = {}
+ for dev in devs:
+ macs[sioc.gifhwaddr(dev).lower()] = dev
+
+ ipt = iptables.IPTables()
+ for network in data['networks']:
+ # Get interface name preferably from MAC address, falling
+ # back on IP address.
+ if macs.has_key(network['mac']):
+ dev = macs[network['mac'].lower()]
+ elif ips.has_key(network['ip']):
+ dev = ips[network['ip']]
+ else:
+ logger.log('%s: no such interface with address %s/%s' % (network['hostname'], network['ip'], network['mac']))
+ continue
+
+ try:
+ settings = plc.GetNodeNetworkSettings({'nodenetwork_setting_id': network['nodenetwork_setting_ids']})
+ except:
+ continue
+ # XXX arbitrary names
+ for setting in settings:
+ if setting['category'] != 'firewall':
+ continue
+ if setting['name'] == 'external':
+ # Enable NAT for this interface
+ ipt.add_ext(dev)
+ elif setting['name'] == 'internal':
+ ipt.add_int(dev)
+ elif setting['name'] == 'pf': # XXX Uglier code is hard to find...
+ for pf in setting['value'].split("\n"):
+ fields = {}
+ for field in pf.split(","):
+ (key, val) = field.split("=", 2)
+ fields[key] = val
+ if 'new_dport' not in fields:
+ fields['new_dport'] = fields['dport']
+ if 'source' not in fields:
+ fields['source'] = "0.0.0.0/0"
+ ipt.add_pf(fields)
+ ipt.commit()
+
def start(options, config):
pass