def translate_pool_rule(trans_type, addr, addr_type, addr_table, port_from, port_to, proto, addr_iface, af): """Parses fields given in the pfweb form to a pf.PFPool object""" pfaddr = False if addr_type == 'addrmask': pfaddr = translate_addrmask(af, addr) elif addr_type == 'table': if not addr_table: return "Table cannot be empty" pfaddr = pf.PFAddr("<{}>".format(addr_table)) elif addr_type == 'dynif': if trans_type.lower() == 'rdr': return "Cannot RDR to an interface" if not addr_iface: return "Interface cannot be empty" # Set PFAddr to interface and IPv4 pfaddr = pf.PFAddr("({})".format(addr_iface), af) pool_id = pf.PF_POOL_NAT port = False if trans_type.lower() == 'rdr' and (proto == socket.IPPROTO_TCP or proto == socket.IPPROTO_UDP): # Set ports to 0 if they were left blank if port_from == '': port_from = 0 port_to = 0 if port_to == '': port_to = 0 pool_id = pf.PF_POOL_RDR try: port = pf.PFPort((int(port_from), int(port_to))) except ValueError: # The user didn't give us a valid number return "Invalid port number" elif trans_type.lower() == 'rdr' and not (proto == socket.IPPROTO_TCP or proto == socket.IPPROTO_UDP): return "TCP or UDP must be used for RDR" pool = pf.PFPool(pool_id, pfaddr) if port: pool.proxy_port = port return pool
def test_load_ruleset(self): iface = pf.PFAddr(type=pf.PF_ADDR_DYNIFTL, ifname=self.testif) tables = [pf.PFTable("web_srv", "10.0.1.20", "10.0.1.21", "10.0.1.22")] rules = [ # match out on $ifname inet from !($ifname) to any nat-to ($ifname) pf.PFRule(action=pf.PF_MATCH, direction=pf.PF_OUT, ifname=self.testif, af=AF_INET, src=pf.PFRuleAddr(iface, neg=True), nat=pf.PFPool(pf.PF_POOL_NAT, iface)), # pass out quick pf.PFRule(action=pf.PF_PASS, direction=pf.PF_OUT, quick=True, flags="S", flagset="SA", keep_state=pf.PF_STATE_NORMAL), # anchor "test_anchor" pf.PFRuleset("test_anchor"), # pass in on $ifname inet proto tcp from any to $ifname port ssh pf.PFRule(action=pf.PF_PASS, direction=pf.PF_IN, ifname=self.testif, af=AF_INET, proto=IPPROTO_TCP, dst=pf.PFRuleAddr(iface, pf.PFPort("ssh", IPPROTO_TCP)), flags="S", flagset="SA", keep_state=pf.PF_STATE_NORMAL), # pass in on $ifname inet proto tcp to $ifname port www \ # rdr-to <web_srv> round-robin sticky-address pf.PFRule(action=pf.PF_PASS, direction=pf.PF_IN, ifname=self.testif, af=AF_INET, proto=IPPROTO_TCP, dst=pf.PFRuleAddr(iface, pf.PFPort("www", IPPROTO_TCP)), flags="S", flagset="SA", keep_state=pf.PF_STATE_NORMAL, rdr=pf.PFPool(pf.PF_POOL_RDR, pf.PFAddr("<web_srv>"), opts=(pf.PF_POOL_ROUNDROBIN| pf.PF_POOL_STICKYADDR))), # pass out on $ifname inet proto tcp to port 80 \ # divert-packet port 700 pf.PFRule(action=pf.PF_PASS, direction=pf.PF_OUT, ifname=self.testif, af=AF_INET, proto=IPPROTO_TCP, dst=pf.PFRuleAddr(port=pf.PFPort("www", IPPROTO_TCP)), divert=pf.PFDivert(pf.PF_DIVERT_PACKET, port=700)), # pass in inet proto icmp all icmp-type echoreq max-pkt-rate 100/10 pf.PFRule(action=pf.PF_PASS, direction=pf.PF_IN, af=AF_INET, proto=IPPROTO_ICMP, type=pf.ICMP_ECHO+1, keep_state=pf.PF_STATE_NORMAL, pktrate=pf.PFThreshold(100, 10))] rules[2].append( pf.PFTable("spammers", flags=pf.PFR_TFLAG_PERSIST), # pass in on $ifname inet proto tcp from ! <spammers> \ # to $ifname port 25 rdr-to 10.0.1.23 pf.PFRule(action=pf.PF_PASS, direction=pf.PF_IN, ifname=self.testif, af=AF_INET, proto=IPPROTO_TCP, src=pf.PFRuleAddr(pf.PFAddr("<spammers>"), neg=True), dst=pf.PFRuleAddr(iface, pf.PFPort(25, IPPROTO_TCP)), flags="S", flagset="SA", keep_state=pf.PF_STATE_NORMAL, rdr=pf.PFPool(pf.PF_POOL_RDR, pf.PFAddr("10.0.1.23")))) self.pf.clear_rules() rs = pf.PFRuleset() rs.append(*tables) rs.append(*rules) self.pf.load_ruleset(rs) self.assertEqual(len(self.pf.get_ruleset().rules), len(rules))