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