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