6 # Author: Daniel Hokka Zakrisson <daniel@hozac.com>
13 """A class to encapsulate iptables operations"""
14 IPTABLES_RESTORE = "/sbin/iptables-restore"
21 def add_ext(self, interface):
22 """Adds an external interface. An external interface is one where
23 outgoing traffic will be NATed, and incoming traffic will go to
24 the port forward chain."""
25 self.extifs.append(interface)
27 def add_int(self, interface):
28 """Adds an internal interface. An internal interface is trusted,
29 and traffic coming in on it is allowed through."""
30 self.intifs.append(interface)
33 """Adds a port forward. The argument is a dict consisting of:
35 'destination' the new destination IP
36 'dport' the destination port
37 'new_dport' the new destination port
39 'interface' the incoming interface
40 'source' limit the redirect to these IPs"""
41 # XXX Should make sure the required fields are there
45 """Call commit when all the rules are ready to be applied.
46 This is a no-op if no port forwards, external or internal
47 interfaces have been declared."""
49 # XXX This should check for errors
50 # and make sure the new ruleset differs from the current one
52 if (len(self.extifs) + len(self.intifs) + len(self.pfs)) == 0:
55 restore = subprocess.Popen([self.IPTABLES_RESTORE, "--noflush"], stdin=subprocess.PIPE)
56 restore.stdin.write("""*filter
71 -A OUTPUT -j BLACKLIST
72 -A OUTPUT -m mark ! --mark 0/65535 -j SLICESPRE
73 -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
76 for int in self.intifs:
77 # Allow all traffic from internal to external
78 for ext in self.extifs:
79 restore.stdin.write("-A FORWARD -i %s -o %s -j ACCEPT\n" % (int, ext))
80 # Traffic from slices to internal networks is scrutinized
81 restore.stdin.write("-A SLICESPRE -o %s -j SLICES\n" % int)
83 restore.stdin.write("-A FORWARD -m state --state NEW -j PORTFW\n")
85 # Port forwards, redirect incoming external traffic to some internal address
86 rule = "-A PORTFW -p %s -d %s " % (pf['protocol'], pf['destination'])
88 rule += "-i %s " % pf['interface']
90 rule += "-s %s " % pf['source']
91 rule += "--dport %s" % pf['new_dport']
92 restore.stdin.write(rule + "\n")
94 restore.stdin.write("-A FORWARD -j LOGDROP\n")
96 # This should have a way to add rules
97 restore.stdin.write("-A SLICES -j LOGDROP\n")
98 restore.stdin.write("""COMMIT
100 :PREROUTING ACCEPT [0:0]
101 :POSTROUTING ACCEPT [0:0]
111 # Outgoing traffic on external interfaces needs to be NATed
112 for ext in self.extifs:
113 restore.stdin.write("-A MASQ -o %s -j MASQUERADE\n")
115 # Redirect port forwards to their real destination
117 rule = "-A PORTFW -p %s " % pf['protocol']
118 if 'interface' in pf:
119 rule += "-i %s " % pf['interface']
121 rule += "-s %s " % pf['source']
122 rule += "--dport %s -j DNAT --to %s:%s" % (pf['dport'], pf['destination'],
124 restore.stdin.write(rule + "\n")
126 restore.stdin.write("COMMIT\n")
127 restore.stdin.close()
128 return restore.wait() == 0