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