Support NAT/port forwards.
[nodemanager.git] / iptables.py
1 #!/usr/bin/python -tt
2
3 # Author: Daniel Hokka Zakrisson <daniel@hozac.com>
4 # $Id$
5
6 import os
7 import logger
8 import subprocess
9
10 class IPTables:
11     IPTABLES_RESTORE = "/sbin/iptables-restore"
12
13     def __init__(self):
14         self.extifs = []
15         self.intifs = []
16         self.pfs = []
17
18     def add(self, table, chain, rule):
19         self.rules[table][chain].append(rule)
20
21     def add_ext(self, interface):
22         self.extifs.append(interface)
23
24     def add_int(self, interface):
25         self.intifs.append(interface)
26
27     def add_pf(self, pf):
28         # XXX Should make sure the required fields are there
29         self.pfs.append(pf)
30
31     def commit(self):
32         # XXX This should check for errors
33         #     and make sure the new ruleset differs from the current one
34
35         if (len(self.extifs) + len(self.intifs) + len(self.pfs)) == 0:
36             return True
37
38         restore = subprocess.Popen([self.IPTABLES_RESTORE], stdin=subprocess.PIPE)
39         restore.stdin.write("""*filter
40 :INPUT ACCEPT [0:0]
41 :FORWARD ACCEPT [0:0]
42 :OUTPUT ACCEPT [0:0]
43 :BLACKLIST - [0:0]
44 :LOGDROP - [0:0]
45 :SLICESPRE - [0:0]
46 :SLICES - [0:0]
47 :PORTFW - [0:0]
48
49 -A LOGDROP -j LOG
50 -A LOGDROP -j DROP
51 -A OUTPUT -j BLACKLIST
52 -A OUTPUT -m mark ! --mark 0/65535 -j SLICESPRE
53 -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
54 """)
55
56         for int in self.intifs:
57             for ext in self.extifs:
58                 restore.stdin.write("-A FORWARD -i %s -o %s -j ACCEPT\n" % (int, ext))
59             restore.stdin.write("-A SLICESPRE -o %s -j SLICES\n" % int)
60
61         restore.stdin.write("-A FORWARD -m state --state NEW -j PORTFW\n")
62         for pf in self.pfs:
63             rule = "-A PORTFW -p %s -d %s " % (pf['protocol'], pf['destination'])
64             if 'interface' in pf:
65                 rule += "-i %s " % pf['interface']
66             if 'source' in pf:
67                 rule += "-s %s " % pf['source']
68             rule += "--dport %s" % pf['new_dport']
69             restore.stdin.write(rule + "\n")
70
71         restore.stdin.write("-A FORWARD -j LOGDROP\n")
72
73         # This should have a way to add rules
74         restore.stdin.write("-A SLICES -j LOGDROP\n")
75         restore.stdin.write("""COMMIT
76 *nat
77 :PREROUTING ACCEPT [0:0]
78 :POSTROUTING ACCEPT [0:0]
79 :OUTPUT ACCEPT [0:0]
80 :PORTFW - [0:0]
81 :MASQ - [0:0]
82 """)
83
84         for ext in self.extifs:
85             restore.stdin.write("-A MASQ -o %s -j MASQUERADE\n")
86
87         for pf in self.pfs:
88             rule = "-A PORTFW -p %s " % pf['protocol']
89             if 'interface' in pf:
90                 rule += "-i %s " % pf['interface']
91             if 'source' in pf:
92                 rule += "-s %s " % pf['source']
93             rule += "--dport %s -j DNAT --to %s:%s" % (pf['dport'], pf['destination'],
94                     pf['new_dport'])
95             restore.stdin.write(rule + "\n")
96
97         restore.stdin.write("COMMIT\n")
98         restore.stdin.close()
99         return restore.wait() == 0