diff options
author | Daniel Hartmeier <dhartmei@cvs.openbsd.org> | 2002-12-06 00:47:33 +0000 |
---|---|---|
committer | Daniel Hartmeier <dhartmei@cvs.openbsd.org> | 2002-12-06 00:47:33 +0000 |
commit | 0c408b075f1e6e1911db1000cfcbb398ffdae48e (patch) | |
tree | f080855d3f372b0b1c7eccc81c79a14a8dcc5067 /sys | |
parent | 7654c4a4b93a0c8473a697480f604acf3272bbcc (diff) |
Introduce anchors and named rule sets, allowing to load additional rule
sets with pfctl and evaluate them from the main rule set using a new type
of rule (which will support conditional evaluation soon). Makes
maintenance of sub-rulesets simpler for pfctl and daemons.
Idea and ok deraadt@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/pf.c | 430 | ||||
-rw-r--r-- | sys/net/pf_ioctl.c | 792 | ||||
-rw-r--r-- | sys/net/pf_norm.c | 16 | ||||
-rw-r--r-- | sys/net/pfvar.h | 161 |
4 files changed, 1016 insertions, 383 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c index 242a60c9871..f06258fd956 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.268 2002/12/03 15:52:33 mickey Exp $ */ +/* $OpenBSD: pf.c,v 1.269 2002/12/06 00:47:32 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -91,28 +91,15 @@ struct pf_state_tree; * Global variables */ -struct pf_rulequeue pf_rules[2]; -struct pf_rulequeue *pf_rules_active; -struct pf_rulequeue *pf_rules_inactive; -struct pf_natqueue *pf_nats_active; -struct pf_natqueue *pf_nats_inactive; -struct pf_binatqueue *pf_binats_active; -struct pf_binatqueue *pf_binats_inactive; -struct pf_rdrqueue *pf_rdrs_active; -struct pf_rdrqueue *pf_rdrs_inactive; +struct pf_anchorqueue pf_anchors; +struct pf_ruleset pf_main_ruleset; +struct pf_altqqueue pf_altqs[2]; +struct pf_palist pf_pabuf[2]; struct pf_altqqueue *pf_altqs_active; struct pf_altqqueue *pf_altqs_inactive; struct pf_status pf_status; struct ifnet *status_ifp; -u_int32_t ticket_rules_active; -u_int32_t ticket_rules_inactive; -u_int32_t ticket_nats_active; -u_int32_t ticket_nats_inactive; -u_int32_t ticket_binats_active; -u_int32_t ticket_binats_inactive; -u_int32_t ticket_rdrs_active; -u_int32_t ticket_rdrs_inactive; u_int32_t ticket_altqs_active; u_int32_t ticket_altqs_inactive; u_int32_t ticket_pabuf; @@ -148,7 +135,8 @@ int *pftm_timeouts[PFTM_MAX] = { &pftm_tcp_first_packet, &pftm_udp_single, &pftm_udp_multiple, &pftm_icmp_first_packet, &pftm_icmp_error_reply, &pftm_other_first_packet, &pftm_other_single, - &pftm_other_multiple, &pftm_frag, &pftm_interval }; + &pftm_other_multiple, &pftm_frag, + &pftm_interval }; struct pool pf_tree_pl, pf_rule_pl, pf_nat_pl, pf_sport_pl; @@ -207,8 +195,9 @@ int pf_test_icmp(struct pf_rule **, int, struct ifnet *, struct mbuf *, int, int, void *, struct pf_pdesc *); int pf_test_other(struct pf_rule **, int, struct ifnet *, struct mbuf *, void *, struct pf_pdesc *); -int pf_test_fragment(struct pf_rule **, int, struct ifnet *, - struct mbuf *, void *, struct pf_pdesc *); +int pf_test_fragment(struct pf_rule **, int, + struct ifnet *, struct mbuf *, void *, + struct pf_pdesc *); int pf_test_state_tcp(struct pf_state **, int, struct ifnet *, struct mbuf *, int, int, void *, struct pf_pdesc *); @@ -245,8 +234,8 @@ void pf_route6(struct mbuf **, struct pf_rule *, int, struct ifnet *, struct pf_state *); int pf_socket_lookup(uid_t *, gid_t *, int, sa_family_t, int, struct pf_pdesc *); -struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { { &pf_state_pl, UINT_MAX }, - { &pf_frent_pl, PFFRAG_FRENT_HIWAT } }; +struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = + { { &pf_state_pl, UINT_MAX }, { &pf_frent_pl, PFFRAG_FRENT_HIWAT } }; #define STATE_TRANSLATE(s) \ @@ -266,13 +255,6 @@ static __inline int pf_state_compare(struct pf_tree_node *, struct pf_state_tree tree_lan_ext, tree_ext_gwy; RB_GENERATE(pf_state_tree, pf_tree_node, entry, pf_state_compare); -struct pf_rulequeue pf_rules[2]; -struct pf_natqueue pf_nats[2]; -struct pf_binatqueue pf_binats[2]; -struct pf_rdrqueue pf_rdrs[2]; -struct pf_altqqueue pf_altqs[2]; -struct pf_palist pf_pabuf[2]; - static __inline int pf_state_compare(struct pf_tree_node *a, struct pf_tree_node *b) { @@ -756,8 +738,10 @@ pf_calc_skip_steps(struct pf_rulequeue *rules) PF_CALC_SKIP_STEP(PF_SKIP_SRC_ADDR, s->src.addr.addr_dyn == NULL && r->src.addr.addr_dyn == NULL && - PF_AEQ(&s->src.addr.addr, &r->src.addr.addr, r->af) && - PF_AEQ(&s->src.addr.mask, &r->src.addr.mask, r->af) && + PF_AEQ(&s->src.addr.addr, &r->src.addr.addr, + r->af) && + PF_AEQ(&s->src.addr.mask, &r->src.addr.mask, + r->af) && s->src.not == r->src.not); PF_CALC_SKIP_STEP(PF_SKIP_SRC_PORT, s->src.port[0] == r->src.port[0] && @@ -766,8 +750,10 @@ pf_calc_skip_steps(struct pf_rulequeue *rules) PF_CALC_SKIP_STEP(PF_SKIP_DST_ADDR, s->dst.addr.addr_dyn == NULL && r->dst.addr.addr_dyn == NULL && - PF_AEQ(&s->dst.addr.addr, &r->dst.addr.addr, r->af) && - PF_AEQ(&s->dst.addr.mask, &r->dst.addr.mask, r->af) && + PF_AEQ(&s->dst.addr.addr, &r->dst.addr.addr, + r->af) && + PF_AEQ(&s->dst.addr.mask, &r->dst.addr.mask, + r->af) && s->dst.not == r->dst.not); PF_CALC_SKIP_STEP(PF_SKIP_DST_PORT, s->dst.port[0] == r->dst.port[0] && @@ -779,6 +765,40 @@ pf_calc_skip_steps(struct pf_rulequeue *rules) } } +void +pf_update_anchor_rules() +{ + struct pf_rule *rule; + struct pf_nat *nat; + struct pf_rdr *rdr; + struct pf_binat *binat; + + TAILQ_FOREACH(rule, pf_main_ruleset.rules.active.ptr, entries) { + if (rule->anchorname[0]) + rule->anchor = pf_find_anchor(rule->anchorname); + else + rule->anchor = NULL; + } + TAILQ_FOREACH(nat, pf_main_ruleset.nats.active.ptr, entries) { + if (nat->anchorname[0]) + nat->anchor = pf_find_anchor(nat->anchorname); + else + nat->anchor = NULL; + } + TAILQ_FOREACH(rdr, pf_main_ruleset.rdrs.active.ptr, entries) { + if (rdr->anchorname[0]) + rdr->anchor = pf_find_anchor(rdr->anchorname); + else + rdr->anchor = NULL; + } + TAILQ_FOREACH(binat, pf_main_ruleset.binats.active.ptr, entries) { + if (binat->anchorname[0]) + binat->anchor = pf_find_anchor(binat->anchorname); + else + binat->anchor = NULL; + } +} + u_int16_t pf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp) { @@ -893,7 +913,7 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, if (pc != NULL) *ic = pf_cksum_fixup(*ic, opc, *pc, 0); PF_ACPY(ia, na, af); - /* Change inner ip address, fix inner ipv4 checksum and icmp checksum. */ + /* Change inner ip address, fix inner ipv4 and icmp checksums. */ switch (af) { #ifdef INET case AF_INET: @@ -1234,6 +1254,37 @@ pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g) return (pf_match(op, a1, a2, g)); } +#define PF_STEP_INTO_ANCHOR(r, a, s, n) \ + do { \ + if ((r) == NULL || (r)->anchor == NULL || \ + (s) != NULL || (a) != NULL) \ + panic("PF_STEP_INTO_ANCHOR"); \ + (a) = (r); \ + (s) = TAILQ_FIRST(&(r)->anchor->rulesets); \ + (r) = NULL; \ + while ((s) != NULL && \ + ((r) = TAILQ_FIRST((s)->n.active.ptr)) == NULL) \ + (s) = TAILQ_NEXT((s), entries); \ + if ((r) == NULL) { \ + (r) = TAILQ_NEXT((a), entries); \ + (a) = NULL; \ + } \ + } while (0) + +#define PF_STEP_OUT_OF_ANCHOR(r, a, s, n) \ + do { \ + if ((r) != NULL || (a) == NULL || (s) == NULL) \ + panic("PF_STEP_OUT_OF_ANCHOR"); \ + (s) = TAILQ_NEXT((s), entries); \ + while ((s) != NULL && \ + ((r) = TAILQ_FIRST((s)->n.active.ptr)) == NULL) \ + (s) = TAILQ_NEXT((s), entries); \ + if ((r) == NULL) { \ + (r) = TAILQ_NEXT((a), entries); \ + (a) = NULL; \ + } \ + } while (0) + #ifdef INET6 void pf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr, @@ -1532,9 +1583,10 @@ pf_get_nat(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr, u_int16_t sport, struct pf_addr *daddr, u_int16_t dport, struct pf_addr *naddr, u_int16_t *nport, sa_family_t af) { - struct pf_nat *n, *nm = NULL; + struct pf_nat *n, *nm = NULL, *anchorrule = NULL; + struct pf_ruleset *ruleset = NULL; - n = TAILQ_FIRST(pf_nats_active); + n = TAILQ_FIRST(pf_main_ruleset.nats.active.ptr); while (n && nm == NULL) { if (((n->ifp == NULL) || (n->ifp == ifp && !n->ifnot) || (n->ifp != ifp && n->ifnot)) && @@ -1555,10 +1607,17 @@ pf_get_nat(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr, (!n->dst.port_op || (proto != IPPROTO_TCP && proto != IPPROTO_UDP) || pf_match_port(n->dst.port_op, n->dst.port[0], - n->dst.port[1], dport))) - nm = n; - else + n->dst.port[1], dport)) && + (!n->anchorname[0] || n->anchor != NULL)) { + if (n->anchor == NULL) + nm = n; + else + PF_STEP_INTO_ANCHOR(n, anchorrule, ruleset, + nats); + } else n = TAILQ_NEXT(n, entries); + if (n == NULL && anchorrule != NULL) + PF_STEP_OUT_OF_ANCHOR(n, anchorrule, ruleset, nats); } if (nm) { if (nm->no) @@ -1585,34 +1644,38 @@ pf_get_binat(int direction, struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr, struct pf_addr *daddr, struct pf_addr *naddr, sa_family_t af) { - struct pf_binat *b, *bm = NULL; + struct pf_binat *b, *bm = NULL, *anchorrule = NULL; + struct pf_ruleset *ruleset = NULL; - b = TAILQ_FIRST(pf_binats_active); + b = TAILQ_FIRST(pf_main_ruleset.binats.active.ptr); while (b && bm == NULL) { - if (direction == PF_OUT && b->ifp == ifp && - (!b->proto || b->proto == proto) && - (!b->af || b->af == af) && - (b->saddr.addr_dyn == NULL || - !b->saddr.addr_dyn->undefined) && - PF_MATCHA(0, &b->saddr.addr, &b->saddr.mask, saddr, af) && - (b->daddr.addr_dyn == NULL || - !b->daddr.addr_dyn->undefined) && - PF_MATCHA(b->dnot, &b->daddr.addr, &b->daddr.mask, - daddr, af)) - bm = b; - else if (direction == PF_IN && b->ifp == ifp && + struct pf_addr_wrap *src; + + if (direction == PF_OUT) + src = &b->saddr; + else + src = &b->raddr; + + if (b->ifp == ifp && (!b->proto || b->proto == proto) && (!b->af || b->af == af) && - (b->raddr.addr_dyn == NULL || - !b->raddr.addr_dyn->undefined) && - PF_MATCHA(0, &b->raddr.addr, &b->raddr.mask, saddr, af) && + (src->addr_dyn == NULL || + !src->addr_dyn->undefined) && + PF_MATCHA(0, &src->addr, &src->mask, saddr, af) && (b->daddr.addr_dyn == NULL || !b->daddr.addr_dyn->undefined) && PF_MATCHA(b->dnot, &b->daddr.addr, &b->daddr.mask, - daddr, af)) - bm = b; - else + daddr, af) && + (!b->anchorname[0] || b->anchor != NULL)) { + if (b->anchor == NULL) + bm = b; + else + PF_STEP_INTO_ANCHOR(b, anchorrule, ruleset, + binats); + } else b = TAILQ_NEXT(b, entries); + if (b == NULL && anchorrule != NULL) + PF_STEP_OUT_OF_ANCHOR(b, anchorrule, ruleset, binats); } if (bm) { @@ -1646,9 +1709,10 @@ pf_get_rdr(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport, struct pf_addr *naddr, sa_family_t af) { - struct pf_rdr *r, *rm = NULL; + struct pf_rdr *r, *rm = NULL, *anchorrule = NULL; + struct pf_ruleset *ruleset = NULL; - r = TAILQ_FIRST(pf_rdrs_active); + r = TAILQ_FIRST(pf_main_ruleset.rdrs.active.ptr); while (r && rm == NULL) { if (((r->ifp == NULL) || (r->ifp == ifp && !r->ifnot) || (r->ifp != ifp && r->ifnot)) && @@ -1664,10 +1728,17 @@ pf_get_rdr(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr, daddr, af) && ((!r->dport2 && (!r->dport || dport == r->dport)) || (r->dport2 && (ntohs(dport) >= ntohs(r->dport)) && - ntohs(dport) <= ntohs(r->dport2)))) - rm = r; - else + ntohs(dport) <= ntohs(r->dport2))) && + (!r->anchorname[0] || r->anchor != NULL)) { + if (r->anchor == NULL) + rm = r; + else + PF_STEP_INTO_ANCHOR(r, anchorrule, ruleset, + rdrs); + } else r = TAILQ_NEXT(r, entries); + if (r == NULL && anchorrule != NULL) + PF_STEP_OUT_OF_ANCHOR(r, anchorrule, ruleset, rdrs); } if (rm) { if (rm->no || pf_map_addr(rm->af, &rm->rpool, @@ -1755,7 +1826,8 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp, int lookup = -1; uid_t uid; gid_t gid; - struct pf_rule *r; + struct pf_rule *r, *rs = NULL, *anchorrule = NULL; + struct pf_ruleset *ruleset = NULL; u_short reason; int rewrite = 0; @@ -1808,7 +1880,7 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp, } } - r = TAILQ_FIRST(pf_rules_active); + r = TAILQ_FIRST(pf_main_ruleset.rules.active.ptr); while (r != NULL) { r->evaluations++; if (r->action == PF_SCRUB) @@ -1816,7 +1888,7 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp, else if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) || (r->ifp == ifp && r->ifnot))) r = r->skip[PF_SKIP_IFP]; - else if (r->direction != direction) + else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR]; else if (r->af && r->af != af) r = r->skip[PF_SKIP_AF]; @@ -1847,26 +1919,41 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp, else if ((r->flagset & th->th_flags) != r->flags) r = TAILQ_NEXT(r, entries); else if (r->uid.op && (lookup != -1 || (lookup = - pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_TCP, pd), - 1)) && !pf_match_uid(r->uid.op, r->uid.uid[0], - r->uid.uid[1], uid)) + pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_TCP, + pd), 1)) && + !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], + uid)) r = TAILQ_NEXT(r, entries); else if (r->gid.op && (lookup != -1 || (lookup = - pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_TCP, pd), - 1)) && !pf_match_gid(r->gid.op, r->gid.gid[0], - r->gid.gid[1], gid)) + pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_TCP, + pd), 1)) && + !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], + gid)) r = TAILQ_NEXT(r, entries); - else { - *rm = r; - if ((*rm)->quick) - break; + else if (r->anchorname[0] && r->anchor == NULL) r = TAILQ_NEXT(r, entries); + else { + if (r->anchor == NULL) { + *rm = r; + rs = (anchorrule == NULL ? r : anchorrule); + if ((*rm)->quick) + break; + r = TAILQ_NEXT(r, entries); + } else + PF_STEP_INTO_ANCHOR(r, anchorrule, ruleset, + rules); } + if (r == NULL && anchorrule != NULL) + PF_STEP_OUT_OF_ANCHOR(r, anchorrule, ruleset, rules); } if (*rm != NULL) { (*rm)->packets++; (*rm)->bytes += pd->tot_len; + if (rs != *rm) { + rs->packets++; + rs->bytes += pd->tot_len; + } REASON_SET(&reason, PFRES_MATCH); if ((*rm)->log) { @@ -1921,10 +2008,10 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp, REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } - if (*rm != NULL) - (*rm)->states++; + if (rs != NULL) + rs->states++; - s->rule.ptr = *rm; + s->rule.ptr = rs; s->allow_opts = *rm && (*rm)->allow_opts; s->log = *rm && ((*rm)->log & 2); s->proto = IPPROTO_TCP; @@ -2012,7 +2099,8 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp, int lookup = -1; uid_t uid; gid_t gid; - struct pf_rule *r; + struct pf_rule *r, *rs = NULL, *anchorrule = NULL; + struct pf_ruleset *ruleset = NULL; u_short reason; int rewrite = 0; @@ -2066,7 +2154,7 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp, } } - r = TAILQ_FIRST(pf_rules_active); + r = TAILQ_FIRST(pf_main_ruleset.rules.active.ptr); while (r != NULL) { r->evaluations++; if (r->action == PF_SCRUB) @@ -2074,7 +2162,7 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp, else if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) || (r->ifp == ifp && r->ifnot))) r = r->skip[PF_SKIP_IFP]; - else if (r->direction != direction) + else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR]; else if (r->af && r->af != af) r = r->skip[PF_SKIP_AF]; @@ -2105,26 +2193,41 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp, else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); else if (r->uid.op && (lookup != -1 || (lookup = - pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_UDP, pd), - 1)) && !pf_match_uid(r->uid.op, r->uid.uid[0], - r->uid.uid[1], uid)) + pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_UDP, + pd), 1)) && + !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], + uid)) r = TAILQ_NEXT(r, entries); else if (r->gid.op && (lookup != -1 || (lookup = - pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_UDP, pd), - 1)) && !pf_match_gid(r->gid.op, r->gid.gid[0], - r->gid.gid[1], gid)) + pf_socket_lookup(&uid, &gid, direction, af, IPPROTO_UDP, + pd), 1)) && + !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], + gid)) r = TAILQ_NEXT(r, entries); - else { - *rm = r; - if ((*rm)->quick) - break; + else if (r->anchorname[0] && r->anchor == NULL) r = TAILQ_NEXT(r, entries); + else { + if (r->anchor == NULL) { + *rm = r; + rs = (anchorrule == NULL ? r : anchorrule); + if ((*rm)->quick) + break; + r = TAILQ_NEXT(r, entries); + } else + PF_STEP_INTO_ANCHOR(r, anchorrule, ruleset, + rules); } + if (r == NULL && anchorrule != NULL) + PF_STEP_OUT_OF_ANCHOR(r, anchorrule, ruleset, rules); } if (*rm != NULL) { (*rm)->packets++; (*rm)->bytes += pd->tot_len; + if (rs != *rm) { + rs->packets++; + rs->bytes += pd->tot_len; + } REASON_SET(&reason, PFRES_MATCH); if ((*rm)->log) { @@ -2170,10 +2273,10 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp, s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) return (PF_DROP); - if (*rm != NULL) - (*rm)->states++; + if (rs != NULL) + rs->states++; - s->rule.ptr = *rm; + s->rule.ptr = rs; s->allow_opts = *rm && (*rm)->allow_opts; s->log = *rm && ((*rm)->log & 2); s->proto = IPPROTO_UDP; @@ -2240,7 +2343,8 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp, struct pf_binat *binat = NULL; struct pf_rdr *rdr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst, baddr, naddr; - struct pf_rule *r; + struct pf_rule *r, *rs = NULL, *anchorrule = NULL; + struct pf_ruleset *ruleset = NULL; u_short reason; u_int16_t icmpid; sa_family_t af = pd->af; @@ -2366,7 +2470,7 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp, } } - r = TAILQ_FIRST(pf_rules_active); + r = TAILQ_FIRST(pf_main_ruleset.rules.active.ptr); while (r != NULL) { r->evaluations++; if (r->action == PF_SCRUB) @@ -2374,7 +2478,7 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp, else if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) || (r->ifp == ifp && r->ifnot))) r = r->skip[PF_SKIP_IFP]; - else if (r->direction != direction) + else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR]; else if (r->af && r->af != af) r = r->skip[PF_SKIP_AF]; @@ -2400,17 +2504,30 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp, r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); - else { - *rm = r; - if ((*rm)->quick) - break; + else if (r->anchorname[0] && r->anchor == NULL) r = TAILQ_NEXT(r, entries); + else { + if (r->anchor == NULL) { + *rm = r; + rs = (anchorrule == NULL ? r : anchorrule); + if ((*rm)->quick) + break; + r = TAILQ_NEXT(r, entries); + } else + PF_STEP_INTO_ANCHOR(r, anchorrule, ruleset, + rules); } + if (r == NULL && anchorrule != NULL) + PF_STEP_OUT_OF_ANCHOR(r, anchorrule, ruleset, rules); } if (*rm != NULL) { (*rm)->packets++; (*rm)->bytes += pd->tot_len; + if (rs != *rm) { + rs->packets++; + rs->bytes += pd->tot_len; + } REASON_SET(&reason, PFRES_MATCH); if ((*rm)->log) { @@ -2436,10 +2553,10 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp, s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) return (PF_DROP); - if (*rm != NULL) - (*rm)->states++; + if (rs != NULL) + rs->states++; - s->rule.ptr = *rm; + s->rule.ptr = rs; s->allow_opts = *rm && (*rm)->allow_opts; s->log = *rm && ((*rm)->log & 2); s->proto = pd->proto; @@ -2501,7 +2618,8 @@ int pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp, struct mbuf *m, void *h, struct pf_pdesc *pd) { - struct pf_rule *r; + struct pf_rule *r, *rs = NULL, *anchorrule = NULL; + struct pf_ruleset *ruleset = NULL; struct pf_nat *nat = NULL; struct pf_binat *binat = NULL; struct pf_rdr *rdr = NULL; @@ -2588,7 +2706,7 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp, } } - r = TAILQ_FIRST(pf_rules_active); + r = TAILQ_FIRST(pf_main_ruleset.rules.active.ptr); while (r != NULL) { r->evaluations++; if (r->action == PF_SCRUB) @@ -2596,7 +2714,7 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp, else if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) || (r->ifp == ifp && r->ifnot))) r = r->skip[PF_SKIP_IFP]; - else if (r->direction != direction) + else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR]; else if (r->af && r->af != af) r = r->skip[PF_SKIP_AF]; @@ -2618,17 +2736,30 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp, r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); - else { - *rm = r; - if ((*rm)->quick) - break; + else if (r->anchorname[0] && r->anchor == NULL) r = TAILQ_NEXT(r, entries); + else { + if (r->anchor == NULL) { + *rm = r; + rs = (anchorrule == NULL ? r : anchorrule); + if ((*rm)->quick) + break; + r = TAILQ_NEXT(r, entries); + } else + PF_STEP_INTO_ANCHOR(r, anchorrule, ruleset, + rules); } + if (r == NULL && anchorrule != NULL) + PF_STEP_OUT_OF_ANCHOR(r, anchorrule, ruleset, rules); } if (*rm != NULL) { (*rm)->packets++; (*rm)->bytes += pd->tot_len; + if (rs != *rm) { + rs->packets++; + rs->bytes += pd->tot_len; + } REASON_SET(&reason, PFRES_MATCH); if ((*rm)->log) PFLOG_PACKET(ifp, h, m, af, direction, reason, *rm); @@ -2647,10 +2778,10 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp, s = pool_get(&pf_state_pl, PR_NOWAIT); if (s == NULL) return (PF_DROP); - if (*rm != NULL) - (*rm)->states++; + if (rs != NULL) + rs->states++; - s->rule.ptr = *rm; + s->rule.ptr = rs; s->allow_opts = *rm && (*rm)->allow_opts; s->log = *rm && ((*rm)->log & 2); s->proto = pd->proto; @@ -2708,12 +2839,13 @@ int pf_test_fragment(struct pf_rule **rm, int direction, struct ifnet *ifp, struct mbuf *m, void *h, struct pf_pdesc *pd) { - struct pf_rule *r; + struct pf_rule *r, *rs = NULL, *anchorrule = NULL; + struct pf_ruleset *ruleset = NULL; sa_family_t af = pd->af; *rm = NULL; - r = TAILQ_FIRST(pf_rules_active); + r = TAILQ_FIRST(pf_main_ruleset.rules.active.ptr); while (r != NULL) { r->evaluations++; if (r->action == PF_SCRUB) @@ -2721,7 +2853,7 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct ifnet *ifp, else if (r->ifp != NULL && ((r->ifp != ifp && !r->ifnot) || (r->ifp == ifp && r->ifnot))) r = r->skip[PF_SKIP_IFP]; - else if (r->direction != direction) + else if (r->direction && r->direction != direction) r = r->skip[PF_SKIP_DIR]; else if (r->af && r->af != af) r = r->skip[PF_SKIP_AF]; @@ -2744,12 +2876,21 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct ifnet *ifp, else if (r->src.port_op || r->dst.port_op || r->flagset || r->type || r->code) r = TAILQ_NEXT(r, entries); - else { - *rm = r; - if ((*rm)->quick) - break; + else if (r->anchorname[0] && r->anchor == NULL) r = TAILQ_NEXT(r, entries); + else { + if (r->anchor == NULL) { + *rm = r; + rs = (anchorrule == NULL ? r : anchorrule); + if ((*rm)->quick) + break; + r = TAILQ_NEXT(r, entries); + } else + PF_STEP_INTO_ANCHOR(r, anchorrule, ruleset, + rules); } + if (r == NULL && anchorrule != NULL) + PF_STEP_OUT_OF_ANCHOR(r, anchorrule, ruleset, rules); } if (*rm != NULL) { @@ -2757,6 +2898,10 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct ifnet *ifp, (*rm)->packets++; (*rm)->bytes += pd->tot_len; + if (rs != *rm) { + rs->packets++; + rs->bytes += pd->tot_len; + } REASON_SET(&reason, PFRES_MATCH); if ((*rm)->log) PFLOG_PACKET(ifp, h, m, af, direction, reason, *rm); @@ -3257,10 +3402,14 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2), NULL, NULL, pd2.af)) { DPFPRINTF(PF_DEBUG_MISC, - ("pf: ICMP error message too short (ip)\n")); + ("pf: ICMP error message too short " + "(ip)\n")); return (PF_DROP); } - /* ICMP error messages don't refer to non-first fragments */ + /* + * ICMP error messages don't refer to non-first + * fragments + */ if (ntohs(h2.ip_off) & IP_OFFMASK) return (PF_DROP); @@ -3280,7 +3429,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6), NULL, NULL, pd2.af)) { DPFPRINTF(PF_DEBUG_MISC, - ("pf: ICMP error message too short (ip6)\n")); + ("pf: ICMP error message too short " + "(ip6)\n")); return (PF_DROP); } pd2.proto = h2_6.ip6_nxt; @@ -3340,7 +3490,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, */ if (!pf_pull_hdr(m, off2, &th, 8, NULL, NULL, pd2.af)) { DPFPRINTF(PF_DEBUG_MISC, - ("pf: ICMP error message too short (tcp)\n")); + ("pf: ICMP error message too short " + "(tcp)\n")); return (PF_DROP); } @@ -3429,7 +3580,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, if (!pf_pull_hdr(m, off2, &uh, sizeof(uh), NULL, NULL, pd2.af)) { DPFPRINTF(PF_DEBUG_MISC, - ("pf: ICMP error message too short (udp)\n")); + ("pf: ICMP error message too short " + "(udp)\n")); return (PF_DROP); } @@ -3494,7 +3646,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN, NULL, NULL, pd2.af)) { DPFPRINTF(PF_DEBUG_MISC, - ("pf: ICMP error message too short (icmp)\n")); + ("pf: ICMP error message too short i" + "(icmp)\n")); return (PF_DROP); } @@ -3546,7 +3699,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN, NULL, NULL, pd2.af)) { DPFPRINTF(PF_DEBUG_MISC, - ("pf: ICMP error message too short (icmp6)\n")); + ("pf: ICMP error message too short " + "(icmp6)\n")); return (PF_DROP); } @@ -3652,7 +3806,8 @@ pf_test_state_other(struct pf_state **state, int direction, struct ifnet *ifp, #ifdef INET case AF_INET: pf_change_a(&pd->src->v4.s_addr, - pd->ip_sum, (*state)->gwy.addr.v4.s_addr, 0); + pd->ip_sum, (*state)->gwy.addr.v4.s_addr, + 0); break; #endif /* INET */ #ifdef INET6 @@ -3666,7 +3821,8 @@ pf_test_state_other(struct pf_state **state, int direction, struct ifnet *ifp, #ifdef INET case AF_INET: pf_change_a(&pd->dst->v4.s_addr, - pd->ip_sum, (*state)->lan.addr.v4.s_addr, 0); + pd->ip_sum, (*state)->lan.addr.v4.s_addr, + 0); break; #endif /* INET */ #ifdef INET6 @@ -4172,8 +4328,8 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) } if (ifp == status_ifp) { - pf_status.bcounters[0][dir] += pd.tot_len; - pf_status.pcounters[0][dir][action]++; + pf_status.bcounters[0][dir == PF_OUT] += pd.tot_len; + pf_status.pcounters[0][dir == PF_OUT][action]++; } done: @@ -4369,8 +4525,8 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0) } if (ifp == status_ifp) { - pf_status.bcounters[1][dir] += pd.tot_len; - pf_status.pcounters[1][dir][action]++; + pf_status.bcounters[1][dir == PF_OUT] += pd.tot_len; + pf_status.pcounters[1][dir == PF_OUT][action]++; } done: diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c index eaab678741c..e1511993cda 100644 --- a/sys/net/pf_ioctl.c +++ b/sys/net/pf_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_ioctl.c,v 1.22 2002/12/01 19:56:38 henning Exp $ */ +/* $OpenBSD: pf_ioctl.c,v 1.23 2002/12/06 00:47:32 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -70,8 +70,8 @@ void pfattach(int); int pfopen(dev_t, int, int, struct proc *); int pfclose(dev_t, int, int, struct proc *); -struct pf_pool *pf_get_pool(u_int32_t, u_int8_t, u_int8_t, - u_int8_t, u_int8_t); +struct pf_pool *pf_get_pool(char *, char *, u_int32_t, + u_int8_t, u_int8_t, u_int8_t, u_int8_t); int pf_add_addr(struct pf_pool *, struct pf_pooladdr *, u_int8_t); int pf_compare_addr_wrap(struct pf_addr_wrap *, @@ -86,6 +86,11 @@ int pf_compare_binats(struct pf_binat *, int pf_compare_pooladdrs(struct pf_pooladdr *, struct pf_pooladdr *, sa_family_t); int pf_compare_rdrs(struct pf_rdr *, struct pf_rdr *); +void pf_init_ruleset(struct pf_ruleset *); +struct pf_anchor *pf_find_anchor(const char *); +struct pf_ruleset *pf_find_ruleset(char *, char *); +struct pf_ruleset *pf_find_or_create_ruleset(char *, char *); +void pf_remove_if_empty_ruleset(struct pf_ruleset *); void pf_mv_pool(struct pf_palist *, struct pf_palist *); void pf_empty_pool(struct pf_palist *); void pf_rm_rule(struct pf_rulequeue *, struct pf_rule *); @@ -120,26 +125,12 @@ pfattach(int num) pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, "pfpooladdrpl", NULL); - TAILQ_INIT(&pf_rules[0]); - TAILQ_INIT(&pf_rules[1]); - TAILQ_INIT(&pf_nats[0]); - TAILQ_INIT(&pf_nats[1]); - TAILQ_INIT(&pf_binats[0]); - TAILQ_INIT(&pf_binats[1]); - TAILQ_INIT(&pf_rdrs[0]); - TAILQ_INIT(&pf_rdrs[1]); + TAILQ_INIT(&pf_anchors); + pf_init_ruleset(&pf_main_ruleset); TAILQ_INIT(&pf_altqs[0]); TAILQ_INIT(&pf_altqs[1]); TAILQ_INIT(&pf_pabuf[0]); TAILQ_INIT(&pf_pabuf[1]); - pf_rules_active = &pf_rules[0]; - pf_rules_inactive = &pf_rules[1]; - pf_nats_active = &pf_nats[0]; - pf_nats_inactive = &pf_nats[1]; - pf_binats_active = &pf_binats[0]; - pf_binats_inactive = &pf_binats[1]; - pf_rdrs_active = &pf_rdrs[0]; - pf_rdrs_inactive = &pf_rdrs[1]; pf_altqs_active = &pf_altqs[0]; pf_altqs_inactive = &pf_altqs[1]; @@ -167,32 +158,38 @@ pfclose(dev_t dev, int flags, int fmt, struct proc *p) } struct pf_pool * -pf_get_pool(u_int32_t ticket, u_int8_t r_id, u_int8_t r_num, u_int8_t active, - u_int8_t check_ticket) +pf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket, + u_int8_t r_id, u_int8_t r_num, u_int8_t active, u_int8_t check_ticket) { + struct pf_ruleset *ruleset; struct pf_rule *rule; struct pf_nat *nat; struct pf_rdr *rdr; u_int32_t nr = 0; + ruleset = pf_find_ruleset(anchorname, rulesetname); + if (ruleset == NULL) + return (NULL); switch (r_id & PF_POOL_IDMASK) { case PF_POOL_RULE_RT: if (active) { - if (check_ticket && ticket != ticket_rules_active) + if (check_ticket && ticket != + ruleset->rules.active.ticket) break; if (r_id & PF_POOL_LAST) - rule = TAILQ_LAST(pf_rules_active, + rule = TAILQ_LAST(ruleset->rules.active.ptr, pf_rulequeue); else - rule = TAILQ_FIRST(pf_rules_active); + rule = TAILQ_FIRST(ruleset->rules.active.ptr); } else { - if (check_ticket && ticket != ticket_rules_inactive) + if (check_ticket && ticket != + ruleset->rules.inactive.ticket) break; if (r_id & PF_POOL_LAST) - rule = TAILQ_LAST(pf_rules_inactive, + rule = TAILQ_LAST(ruleset->rules.inactive.ptr, pf_rulequeue); else - rule = TAILQ_FIRST(pf_rules_inactive); + rule = TAILQ_FIRST(ruleset->rules.inactive.ptr); } if (!(r_id & PF_POOL_LAST)) { while ((rule != NULL) && (rule->nr < r_num)) @@ -205,19 +202,23 @@ pf_get_pool(u_int32_t ticket, u_int8_t r_id, u_int8_t r_num, u_int8_t active, case PF_POOL_NAT_R: if (active) { - if (check_ticket && ticket != ticket_nats_active) + if (check_ticket && ticket != + ruleset->nats.active.ticket) break; if (r_id & PF_POOL_LAST) - nat = TAILQ_LAST(pf_nats_active, pf_natqueue); + nat = TAILQ_LAST(ruleset->nats.active.ptr, + pf_natqueue); else - nat = TAILQ_FIRST(pf_nats_active); + nat = TAILQ_FIRST(ruleset->nats.active.ptr); } else { - if (check_ticket && ticket != ticket_nats_inactive) + if (check_ticket && ticket != + ruleset->nats.inactive.ticket) break; if (r_id & PF_POOL_LAST) - nat = TAILQ_LAST(pf_nats_inactive, pf_natqueue); + nat = TAILQ_LAST(ruleset->nats.inactive.ptr, + pf_natqueue); else - nat = TAILQ_FIRST(pf_nats_inactive); + nat = TAILQ_FIRST(ruleset->nats.inactive.ptr); } if (!(r_id & PF_POOL_LAST)) { while ((nat != NULL) && (nr < r_num)) { @@ -232,19 +233,23 @@ pf_get_pool(u_int32_t ticket, u_int8_t r_id, u_int8_t r_num, u_int8_t active, case PF_POOL_RDR_R: if (active) { - if (check_ticket && ticket != ticket_rdrs_active) + if (check_ticket && ticket != + ruleset->rdrs.active.ticket) break; if (r_id & PF_POOL_LAST) - rdr = TAILQ_LAST(pf_rdrs_active, pf_rdrqueue); + rdr = TAILQ_LAST(ruleset->rdrs.active.ptr, + pf_rdrqueue); else - rdr = TAILQ_FIRST(pf_rdrs_active); + rdr = TAILQ_FIRST(ruleset->rdrs.active.ptr); } else { - if (check_ticket && ticket != ticket_rdrs_inactive) + if (check_ticket && ticket != + ruleset->rdrs.inactive.ticket) break; if (r_id & PF_POOL_LAST) - rdr = TAILQ_LAST(pf_rdrs_inactive, pf_rdrqueue); + rdr = TAILQ_LAST(ruleset->rdrs.inactive.ptr, + pf_rdrqueue); else - rdr = TAILQ_FIRST(pf_rdrs_inactive); + rdr = TAILQ_FIRST(ruleset->rdrs.inactive.ptr); } if (!(r_id & PF_POOL_LAST)) { while ((rdr != NULL) && (nr < r_num)) { @@ -373,6 +378,7 @@ pf_compare_rules(struct pf_rule *a, struct pf_rule *b) if (pf_compare_pool(&a->rt_pool, &b->rt_pool, a->af)) return (1); if (strcmp(a->ifname, b->ifname) || + strcmp(a->anchorname, b->anchorname) || strcmp(a->label, b->label)) return (1); return (0); @@ -464,9 +470,142 @@ pf_compare_pooladdrs(struct pf_pooladdr *a, struct pf_pooladdr *b, return (0); } -/* - * Move the contents of poola to poolb - */ +void +pf_init_ruleset(struct pf_ruleset *ruleset) +{ + memset(ruleset, 0, sizeof(struct pf_ruleset)); + TAILQ_INIT(&ruleset->rules.queues[0]); + TAILQ_INIT(&ruleset->rules.queues[1]); + ruleset->rules.active.ptr = &ruleset->rules.queues[0]; + ruleset->rules.inactive.ptr = &ruleset->rules.queues[1]; + TAILQ_INIT(&ruleset->nats.queues[0]); + TAILQ_INIT(&ruleset->nats.queues[1]); + ruleset->nats.active.ptr = &ruleset->nats.queues[0]; + ruleset->nats.inactive.ptr = &ruleset->nats.queues[1]; + TAILQ_INIT(&ruleset->rdrs.queues[0]); + TAILQ_INIT(&ruleset->rdrs.queues[1]); + ruleset->rdrs.active.ptr = &ruleset->rdrs.queues[0]; + ruleset->rdrs.inactive.ptr = &ruleset->rdrs.queues[1]; + TAILQ_INIT(&ruleset->binats.queues[0]); + TAILQ_INIT(&ruleset->binats.queues[1]); + ruleset->binats.active.ptr = &ruleset->binats.queues[0]; + ruleset->binats.inactive.ptr = &ruleset->binats.queues[1]; +} + +struct pf_anchor * +pf_find_anchor(const char *anchorname) +{ + struct pf_anchor *anchor; + int n = -1; + + anchor = TAILQ_FIRST(&pf_anchors); + while (anchor != NULL && (n = strcmp(anchor->name, anchorname)) < 0) + anchor = TAILQ_NEXT(anchor, entries); + if (n == 0) + return (anchor); + else + return (NULL); +} + +struct pf_ruleset * +pf_find_ruleset(char *anchorname, char *rulesetname) +{ + struct pf_anchor *anchor; + struct pf_ruleset *ruleset; + + if (!anchorname[0] && !rulesetname[0]) + return (&pf_main_ruleset); + if (!anchorname[0] || !rulesetname[0]) + return (NULL); + anchorname[PF_ANCHOR_NAME_SIZE-1] = 0; + rulesetname[PF_RULESET_NAME_SIZE-1] = 0; + anchor = pf_find_anchor(anchorname); + if (anchor == NULL) + return (NULL); + ruleset = TAILQ_FIRST(&anchor->rulesets); + while (ruleset != NULL && strcmp(ruleset->name, rulesetname) < 0) + ruleset = TAILQ_NEXT(ruleset, entries); + if (ruleset != NULL && !strcmp(ruleset->name, rulesetname)) + return (ruleset); + else + return (NULL); +} + +struct pf_ruleset * +pf_find_or_create_ruleset(char *anchorname, char *rulesetname) +{ + struct pf_anchor *anchor, *a; + struct pf_ruleset *ruleset, *r; + + if (!anchorname[0] && !rulesetname[0]) + return (&pf_main_ruleset); + if (!anchorname[0] || !rulesetname[0]) + return (NULL); + anchorname[PF_ANCHOR_NAME_SIZE-1] = 0; + rulesetname[PF_RULESET_NAME_SIZE-1] = 0; + a = TAILQ_FIRST(&pf_anchors); + while (a != NULL && strcmp(a->name, anchorname) < 0) + a = TAILQ_NEXT(a, entries); + if (a != NULL && !strcmp(a->name, anchorname)) + anchor = a; + else { + anchor = (struct pf_anchor *)malloc(sizeof(struct pf_anchor), + M_TEMP, M_NOWAIT); + if (anchor == NULL) + return (NULL); + memset(anchor, 0, sizeof(struct pf_anchor)); + bcopy(anchorname, anchor->name, sizeof(anchor->name)); + TAILQ_INIT(&anchor->rulesets); + if (a != NULL) + TAILQ_INSERT_BEFORE(a, anchor, entries); + else + TAILQ_INSERT_TAIL(&pf_anchors, anchor, entries); + } + r = TAILQ_FIRST(&anchor->rulesets); + while (r != NULL && strcmp(r->name, rulesetname) < 0) + r = TAILQ_NEXT(r, entries); + if (r != NULL && !strcmp(r->name, rulesetname)) + return (r); + ruleset = (struct pf_ruleset *)malloc(sizeof(struct pf_ruleset), + M_TEMP, M_NOWAIT); + if (ruleset != NULL) { + pf_init_ruleset(ruleset); + bcopy(rulesetname, ruleset->name, sizeof(ruleset->name)); + ruleset->anchor = anchor; + if (r != NULL) + TAILQ_INSERT_BEFORE(r, ruleset, entries); + else + TAILQ_INSERT_TAIL(&anchor->rulesets, ruleset, entries); + } + return (ruleset); +} + +void +pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset) +{ + struct pf_anchor *anchor; + + if (ruleset == NULL || ruleset->anchor == NULL || + !TAILQ_EMPTY(ruleset->rules.active.ptr) || + !TAILQ_EMPTY(ruleset->rules.inactive.ptr) || + !TAILQ_EMPTY(ruleset->nats.active.ptr) || + !TAILQ_EMPTY(ruleset->nats.inactive.ptr) || + !TAILQ_EMPTY(ruleset->rdrs.active.ptr) || + !TAILQ_EMPTY(ruleset->rdrs.inactive.ptr) || + !TAILQ_EMPTY(ruleset->binats.active.ptr) || + !TAILQ_EMPTY(ruleset->binats.inactive.ptr)) + return; + + anchor = ruleset->anchor; + TAILQ_REMOVE(&anchor->rulesets, ruleset, entries); + free(ruleset, M_TEMP); + + if (TAILQ_EMPTY(&anchor->rulesets)) { + TAILQ_REMOVE(&pf_anchors, anchor, entries); + free(anchor, M_TEMP); + } +} + void pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb) { @@ -478,9 +617,6 @@ pf_mv_pool(struct pf_palist *poola, struct pf_palist *poolb) } } -/* - * Functions to clean up after ourselves. - */ void pf_empty_pool(struct pf_palist *poola) { @@ -537,7 +673,6 @@ pf_rm_rdr(struct pf_rdrqueue *rdrqueue, struct pf_rdr *rdr) pool_put(&pf_rdr_pl, rdr); } - int pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) { @@ -572,6 +707,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETALTQS: case DIOCGETALTQ: case DIOCGETQSTATS: + case DIOCGETANCHORS: + case DIOCGETANCHOR: + case DIOCGETRULESETS: + case DIOCGETRULESET: break; default: return (EPERM); @@ -597,6 +736,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETALTQS: case DIOCGETALTQ: case DIOCGETQSTATS: + case DIOCGETANCHORS: + case DIOCGETANCHOR: + case DIOCGETRULESETS: + case DIOCGETRULESET: break; default: return (EACCES); @@ -630,31 +773,52 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; case DIOCBEGINRULES: { - u_int32_t *ticket = (u_int32_t *)addr; + struct pfioc_rule *pr = (struct pfioc_rule *)addr; + struct pf_ruleset *ruleset; struct pf_rule *rule; - while ((rule = TAILQ_FIRST(pf_rules_inactive)) != NULL) { - pf_rm_rule(pf_rules_inactive, rule); + ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; } - *ticket = ++ticket_rules_inactive; + while ((rule = TAILQ_FIRST(ruleset->rules.inactive.ptr)) != + NULL) + pf_rm_rule(ruleset->rules.inactive.ptr, rule); + pr->ticket = ++ruleset->rules.inactive.ticket; break; } case DIOCADDRULE: { struct pfioc_rule *pr = (struct pfioc_rule *)addr; + struct pf_ruleset *ruleset; struct pf_rule *rule, *tail; + ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + if (pr->rule.anchorname[0] && ruleset != &pf_main_ruleset) { + error = EINVAL; + break; + } + if (pr->ticket != ruleset->rules.inactive.ticket) { + error = EBUSY; + break; + } if (pr->pool_ticket != ticket_pabuf) { error = EBUSY; break; } - rule = pool_get(&pf_rule_pl, PR_NOWAIT); if (rule == NULL) { error = ENOMEM; break; } bcopy(&pr->rule, rule, sizeof(struct pf_rule)); + rule->anchor = NULL; + rule->ifp = NULL; TAILQ_INIT(&rule->rt_pool.list); #ifndef INET if (rule->af == AF_INET) { @@ -670,7 +834,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } #endif /* INET6 */ - tail = TAILQ_LAST(pf_rules_inactive, pf_rulequeue); + tail = TAILQ_LAST(ruleset->rules.inactive.ptr, pf_rulequeue); if (tail) rule->nr = tail->nr + 1; else @@ -682,8 +846,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } - } else - rule->ifp = NULL; + } if (pf_dynaddr_setup(&rule->src.addr, rule->af)) error = EINVAL; @@ -696,17 +859,23 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) pf_mv_pool(&pf_pabuf[0], &rule->rt_pool.list); rule->rt_pool.cur = TAILQ_FIRST(&rule->rt_pool.list); rule->evaluations = rule->packets = rule->bytes = 0; - TAILQ_INSERT_TAIL(pf_rules_inactive, rule, entries); + TAILQ_INSERT_TAIL(ruleset->rules.inactive.ptr, rule, entries); break; } case DIOCCOMMITRULES: { - u_int32_t *ticket = (u_int32_t *)addr; + struct pfioc_rule *pr = (struct pfioc_rule *)addr; + struct pf_ruleset *ruleset; struct pf_rulequeue *old_rules; struct pf_rule *rule; struct pf_tree_node *n; - if (*ticket != ticket_rules_inactive) { + ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + if (pr->ticket != ruleset->rules.inactive.ticket) { error = EBUSY; break; } @@ -716,47 +885,62 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) /* * Rules are about to get freed, clear rule pointers in states */ - RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) - n->state->rule.ptr = NULL; - old_rules = pf_rules_active; - pf_rules_active = pf_rules_inactive; - pf_rules_inactive = old_rules; - ticket_rules_active = ticket_rules_inactive; - pf_calc_skip_steps(pf_rules_active); - splx(s); + if (ruleset == &pf_main_ruleset) { + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) + n->state->rule.ptr = NULL; + } + old_rules = ruleset->rules.active.ptr; + ruleset->rules.active.ptr = ruleset->rules.inactive.ptr; + ruleset->rules.inactive.ptr = old_rules; + ruleset->rules.active.ticket = ruleset->rules.inactive.ticket; + pf_calc_skip_steps(ruleset->rules.active.ptr); /* Purge the old rule list. */ - while ((rule = TAILQ_FIRST(old_rules)) != NULL) { + while ((rule = TAILQ_FIRST(old_rules)) != NULL) pf_rm_rule(old_rules, rule); - } + pf_remove_if_empty_ruleset(ruleset); + pf_update_anchor_rules(); + splx(s); break; } case DIOCGETRULES: { struct pfioc_rule *pr = (struct pfioc_rule *)addr; + struct pf_ruleset *ruleset; struct pf_rule *tail; + ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } s = splsoftnet(); - tail = TAILQ_LAST(pf_rules_active, pf_rulequeue); + tail = TAILQ_LAST(ruleset->rules.active.ptr, pf_rulequeue); if (tail) pr->nr = tail->nr + 1; else pr->nr = 0; - pr->ticket = ticket_rules_active; + pr->ticket = ruleset->rules.active.ticket; splx(s); break; } case DIOCGETRULE: { struct pfioc_rule *pr = (struct pfioc_rule *)addr; + struct pf_ruleset *ruleset; struct pf_rule *rule; - if (pr->ticket != ticket_rules_active) { + ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + if (pr->ticket != ruleset->rules.active.ticket) { error = EBUSY; break; } s = splsoftnet(); - rule = TAILQ_FIRST(pf_rules_active); + rule = TAILQ_FIRST(ruleset->rules.active.ptr); while ((rule != NULL) && (rule->nr != pr->nr)) rule = TAILQ_NEXT(rule, entries); if (rule == NULL) { @@ -773,6 +957,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCCHANGERULE: { struct pfioc_changerule *pcr = (struct pfioc_changerule *)addr; + struct pf_ruleset *ruleset; struct pf_rule *oldrule = NULL, *newrule = NULL; u_int32_t nr = 0; @@ -786,6 +971,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } + ruleset = pf_find_ruleset(pcr->anchor, pcr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } if (pcr->action != PF_CHANGE_REMOVE) { newrule = pool_get(&pf_rule_pl, PR_NOWAIT); @@ -836,12 +1026,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) s = splsoftnet(); if (pcr->action == PF_CHANGE_ADD_HEAD) - oldrule = TAILQ_FIRST(pf_rules_active); + oldrule = TAILQ_FIRST(ruleset->rules.active.ptr); else if (pcr->action == PF_CHANGE_ADD_TAIL) - oldrule = TAILQ_LAST(pf_rules_active, pf_rulequeue); + oldrule = TAILQ_LAST(ruleset->rules.active.ptr, + pf_rulequeue); else { pf_mv_pool(&pf_pabuf[0], &pcr->oldrule.rt_pool.list); - oldrule = TAILQ_FIRST(pf_rules_active); + oldrule = TAILQ_FIRST(ruleset->rules.active.ptr); while ((oldrule != NULL) && pf_compare_rules(oldrule, &pcr->oldrule)) oldrule = TAILQ_NEXT(oldrule, entries); @@ -857,53 +1048,72 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (pcr->action == PF_CHANGE_REMOVE) { struct pf_tree_node *n; - RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) - if (n->state->rule.ptr == oldrule) - n->state->rule.ptr = NULL; + if (ruleset == &pf_main_ruleset) { + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) + if (n->state->rule.ptr == oldrule) + n->state->rule.ptr = NULL; + } pf_rm_rule(NULL, oldrule); } else { if (oldrule == NULL) - TAILQ_INSERT_TAIL(pf_rules_active, newrule, - entries); + TAILQ_INSERT_TAIL(ruleset->rules.active.ptr, + newrule, entries); else if (pcr->action == PF_CHANGE_ADD_HEAD || pcr->action == PF_CHANGE_ADD_BEFORE) TAILQ_INSERT_BEFORE(oldrule, newrule, entries); else - TAILQ_INSERT_AFTER(pf_rules_active, oldrule, - newrule, entries); + TAILQ_INSERT_AFTER(ruleset->rules.active.ptr, + oldrule, newrule, entries); } - TAILQ_FOREACH(oldrule, pf_rules_active, entries) + TAILQ_FOREACH(oldrule, ruleset->rules.active.ptr, entries) oldrule->nr = nr++; - pf_calc_skip_steps(pf_rules_active); + pf_calc_skip_steps(ruleset->rules.active.ptr); + pf_remove_if_empty_ruleset(ruleset); + pf_update_anchor_rules(); - ticket_rules_active++; + ruleset->rules.active.ticket++; splx(s); break; } case DIOCBEGINNATS: { - u_int32_t *ticket = (u_int32_t *)addr; + struct pfioc_nat *pn = (struct pfioc_nat *)addr; + struct pf_ruleset *ruleset; struct pf_nat *nat; - while ((nat = TAILQ_FIRST(pf_nats_inactive)) != NULL) { - pf_rm_nat(pf_nats_inactive, nat); + ruleset = pf_find_or_create_ruleset(pn->anchor, pn->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; } - *ticket = ++ticket_nats_inactive; + while ((nat = TAILQ_FIRST(ruleset->nats.inactive.ptr)) != + NULL) + pf_rm_nat(ruleset->nats.inactive.ptr, nat); + pn->ticket = ++ruleset->nats.inactive.ticket; break; } case DIOCADDNAT: { struct pfioc_nat *pn = (struct pfioc_nat *)addr; + struct pf_ruleset *ruleset; struct pf_nat *nat; - if (pn->pool_ticket != ticket_pabuf) { + ruleset = pf_find_ruleset(pn->anchor, pn->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + if (pn->nat.anchorname[0] && ruleset != &pf_main_ruleset) { + error = EINVAL; + break; + } + if (pn->ticket != ruleset->nats.inactive.ticket) { error = EBUSY; break; } - - if (pn->ticket != ticket_nats_inactive) { + if (pn->pool_ticket != ticket_pabuf) { error = EBUSY; break; } @@ -913,6 +1123,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pn->nat, nat, sizeof(struct pf_nat)); + nat->anchor = NULL; + nat->ifp = NULL; TAILQ_INIT(&nat->rpool.list); #ifndef INET if (nat->af == AF_INET) { @@ -935,8 +1147,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } - } else - nat->ifp = NULL; + } if (pf_dynaddr_setup(&nat->src.addr, nat->af)) error = EINVAL; @@ -948,60 +1159,79 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } pf_mv_pool(&pf_pabuf[0], &nat->rpool.list); nat->rpool.cur = TAILQ_FIRST(&nat->rpool.list); - TAILQ_INSERT_TAIL(pf_nats_inactive, nat, entries); + TAILQ_INSERT_TAIL(ruleset->nats.inactive.ptr, nat, entries); break; } case DIOCCOMMITNATS: { - u_int32_t *ticket = (u_int32_t *)addr; + struct pfioc_nat *pn = (struct pfioc_nat *)addr; + struct pf_ruleset *ruleset; struct pf_natqueue *old_nats; struct pf_nat *nat; - if (*ticket != ticket_nats_inactive) { + ruleset = pf_find_ruleset(pn->anchor, pn->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + if (pn->ticket != ruleset->nats.inactive.ticket) { error = EBUSY; break; } /* Swap nats, keep the old. */ s = splsoftnet(); - old_nats = pf_nats_active; - pf_nats_active = pf_nats_inactive; - pf_nats_inactive = old_nats; - ticket_nats_active = ticket_nats_inactive; - splx(s); + old_nats = ruleset->nats.active.ptr; + ruleset->nats.active.ptr = ruleset->nats.inactive.ptr; + ruleset->nats.inactive.ptr = old_nats; + ruleset->nats.active.ticket = ruleset->nats.inactive.ticket; /* Purge the old nat list */ - while ((nat = TAILQ_FIRST(old_nats)) != NULL) { + while ((nat = TAILQ_FIRST(old_nats)) != NULL) pf_rm_nat(old_nats, nat); - } + pf_remove_if_empty_ruleset(ruleset); + pf_update_anchor_rules(); + splx(s); break; } case DIOCGETNATS: { struct pfioc_nat *pn = (struct pfioc_nat *)addr; + struct pf_ruleset *ruleset; struct pf_nat *nat; + ruleset = pf_find_ruleset(pn->anchor, pn->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } pn->nr = 0; s = splsoftnet(); - TAILQ_FOREACH(nat, pf_nats_active, entries) + TAILQ_FOREACH(nat, ruleset->nats.active.ptr, entries) pn->nr++; - pn->ticket = ticket_nats_active; + pn->ticket = ruleset->nats.active.ticket; splx(s); break; } case DIOCGETNAT: { struct pfioc_nat *pn = (struct pfioc_nat *)addr; + struct pf_ruleset *ruleset; struct pf_nat *nat; u_int32_t nr; - if (pn->ticket != ticket_nats_active) { + ruleset = pf_find_ruleset(pn->anchor, pn->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + if (pn->ticket != ruleset->nats.active.ticket) { error = EBUSY; break; } nr = 0; s = splsoftnet(); - nat = TAILQ_FIRST(pf_nats_active); + nat = TAILQ_FIRST(ruleset->nats.active.ptr); while ((nat != NULL) && (nr < pn->nr)) { nat = TAILQ_NEXT(nat, entries); nr++; @@ -1020,6 +1250,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCCHANGENAT: { struct pfioc_changenat *pcn = (struct pfioc_changenat *)addr; + struct pf_ruleset *ruleset; struct pf_nat *oldnat = NULL, *newnat = NULL; if (pcn->pool_ticket != ticket_pabuf) { @@ -1032,6 +1263,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } + ruleset = pf_find_ruleset(pcn->anchor, pcn->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } if (pcn->action != PF_CHANGE_REMOVE) { newnat = pool_get(&pf_nat_pl, PR_NOWAIT); @@ -1080,12 +1316,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) s = splsoftnet(); if (pcn->action == PF_CHANGE_ADD_HEAD) - oldnat = TAILQ_FIRST(pf_nats_active); + oldnat = TAILQ_FIRST(ruleset->nats.active.ptr); else if (pcn->action == PF_CHANGE_ADD_TAIL) - oldnat = TAILQ_LAST(pf_nats_active, pf_natqueue); + oldnat = TAILQ_LAST(ruleset->nats.active.ptr, + pf_natqueue); else { pf_mv_pool(&pf_pabuf[1], &pcn->oldnat.rpool.list); - oldnat = TAILQ_FIRST(pf_nats_active); + oldnat = TAILQ_FIRST(ruleset->nats.active.ptr); while ((oldnat != NULL) && pf_compare_nats(oldnat, &pcn->oldnat)) oldnat = TAILQ_NEXT(oldnat, entries); @@ -1098,41 +1335,60 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } } - if (pcn->action == PF_CHANGE_REMOVE) { - pf_rm_nat(pf_nats_active, oldnat); - } else { + if (pcn->action == PF_CHANGE_REMOVE) + pf_rm_nat(ruleset->nats.active.ptr, oldnat); + else { if (oldnat == NULL) - TAILQ_INSERT_TAIL(pf_nats_active, newnat, - entries); + TAILQ_INSERT_TAIL(ruleset->nats.active.ptr, + newnat, entries); else if (pcn->action == PF_CHANGE_ADD_HEAD || pcn->action == PF_CHANGE_ADD_BEFORE) TAILQ_INSERT_BEFORE(oldnat, newnat, entries); else - TAILQ_INSERT_AFTER(pf_nats_active, oldnat, - newnat, entries); + TAILQ_INSERT_AFTER(ruleset->nats.active.ptr, + oldnat, newnat, entries); } - ticket_nats_active++; + pf_remove_if_empty_ruleset(ruleset); + pf_update_anchor_rules(); + + ruleset->nats.active.ticket++; splx(s); break; } case DIOCBEGINBINATS: { - u_int32_t *ticket = (u_int32_t *)addr; + struct pfioc_binat *pb = (struct pfioc_binat *)addr; + struct pf_ruleset *ruleset; struct pf_binat *binat; - while ((binat = TAILQ_FIRST(pf_binats_inactive)) != NULL) { - pf_rm_binat(pf_binats_inactive, binat); + ruleset = pf_find_or_create_ruleset(pb->anchor, pb->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; } - *ticket = ++ticket_binats_inactive; + while ((binat = TAILQ_FIRST(ruleset->binats.inactive.ptr)) != + NULL) + pf_rm_binat(ruleset->binats.inactive.ptr, binat); + pb->ticket = ++ruleset->binats.inactive.ticket; break; } case DIOCADDBINAT: { struct pfioc_binat *pb = (struct pfioc_binat *)addr; + struct pf_ruleset *ruleset; struct pf_binat *binat; - if (pb->ticket != ticket_binats_inactive) { + ruleset = pf_find_ruleset(pb->anchor, pb->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + if (pb->binat.anchorname[0] && ruleset != &pf_main_ruleset) { + error = EINVAL; + break; + } + if (pb->ticket != ruleset->binats.inactive.ticket) { error = EBUSY; break; } @@ -1142,6 +1398,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pb->binat, binat, sizeof(struct pf_binat)); + binat->anchor = NULL; + binat->ifp = NULL; #ifndef INET if (binat->af == AF_INET) { pool_put(&pf_binat_pl, binat); @@ -1163,8 +1421,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } - } else - binat->ifp = NULL; + } + if (pf_dynaddr_setup(&binat->saddr, binat->af)) error = EINVAL; if (pf_dynaddr_setup(&binat->daddr, binat->af)) @@ -1175,60 +1433,80 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) pf_rm_binat(NULL, binat); break; } - TAILQ_INSERT_TAIL(pf_binats_inactive, binat, entries); + TAILQ_INSERT_TAIL(ruleset->binats.inactive.ptr, binat, + entries); break; } case DIOCCOMMITBINATS: { - u_int32_t *ticket = (u_int32_t *)addr; + struct pfioc_binat *pb = (struct pfioc_binat *)addr; + struct pf_ruleset *ruleset; struct pf_binatqueue *old_binats; struct pf_binat *binat; - if (*ticket != ticket_binats_inactive) { + ruleset = pf_find_ruleset(pb->anchor, pb->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + if (pb->ticket != ruleset->binats.inactive.ticket) { error = EBUSY; break; } /* Swap binats, keep the old. */ s = splsoftnet(); - old_binats = pf_binats_active; - pf_binats_active = pf_binats_inactive; - pf_binats_inactive = old_binats; - ticket_binats_active = ticket_binats_inactive; - splx(s); + old_binats = ruleset->binats.active.ptr; + ruleset->binats.active.ptr = ruleset->binats.inactive.ptr; + ruleset->binats.inactive.ptr = old_binats; + ruleset->binats.active.ticket = ruleset->binats.inactive.ticket; /* Purge the old binat list */ - while ((binat = TAILQ_FIRST(old_binats)) != NULL) { + while ((binat = TAILQ_FIRST(old_binats)) != NULL) pf_rm_binat(old_binats, binat); - } + pf_remove_if_empty_ruleset(ruleset); + pf_update_anchor_rules(); + splx(s); break; } case DIOCGETBINATS: { struct pfioc_binat *pb = (struct pfioc_binat *)addr; + struct pf_ruleset *ruleset; struct pf_binat *binat; + ruleset = pf_find_ruleset(pb->anchor, pb->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } pb->nr = 0; s = splsoftnet(); - TAILQ_FOREACH(binat, pf_binats_active, entries) + TAILQ_FOREACH(binat, ruleset->binats.active.ptr, entries) pb->nr++; - pb->ticket = ticket_binats_active; + pb->ticket = ruleset->binats.active.ticket; splx(s); break; } case DIOCGETBINAT: { struct pfioc_binat *pb = (struct pfioc_binat *)addr; + struct pf_ruleset *ruleset; struct pf_binat *binat; u_int32_t nr; - if (pb->ticket != ticket_binats_active) { + ruleset = pf_find_or_create_ruleset(pb->anchor, pb->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + if (pb->ticket != ruleset->binats.active.ticket) { error = EBUSY; break; } nr = 0; s = splsoftnet(); - binat = TAILQ_FIRST(pf_binats_active); + binat = TAILQ_FIRST(ruleset->binats.active.ptr); while ((binat != NULL) && (nr < pb->nr)) { binat = TAILQ_NEXT(binat, entries); nr++; @@ -1247,7 +1525,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCCHANGEBINAT: { - struct pfioc_changebinat *pcn = (struct pfioc_changebinat *)addr; + struct pfioc_changebinat *pcn = + (struct pfioc_changebinat *)addr; + struct pf_ruleset *ruleset; struct pf_binat *oldbinat = NULL, *newbinat = NULL; if (pcn->action < PF_CHANGE_ADD_HEAD || @@ -1255,6 +1535,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } + ruleset = pf_find_ruleset(pcn->anchor, pcn->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } if (pcn->action != PF_CHANGE_REMOVE) { newbinat = pool_get(&pf_binat_pl, PR_NOWAIT); @@ -1302,11 +1587,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) s = splsoftnet(); if (pcn->action == PF_CHANGE_ADD_HEAD) - oldbinat = TAILQ_FIRST(pf_binats_active); + oldbinat = TAILQ_FIRST(ruleset->binats.active.ptr); else if (pcn->action == PF_CHANGE_ADD_TAIL) - oldbinat = TAILQ_LAST(pf_binats_active, pf_binatqueue); + oldbinat = TAILQ_LAST(ruleset->binats.active.ptr, + pf_binatqueue); else { - oldbinat = TAILQ_FIRST(pf_binats_active); + oldbinat = TAILQ_FIRST(ruleset->binats.active.ptr); while ((oldbinat != NULL) && pf_compare_binats(oldbinat, &pcn->oldbinat)) oldbinat = TAILQ_NEXT(oldbinat, entries); @@ -1318,47 +1604,65 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } } - if (pcn->action == PF_CHANGE_REMOVE) { - pf_rm_binat(pf_binats_active, oldbinat); - } else { + if (pcn->action == PF_CHANGE_REMOVE) + pf_rm_binat(ruleset->binats.active.ptr, oldbinat); + else { if (oldbinat == NULL) - TAILQ_INSERT_TAIL(pf_binats_active, newbinat, - entries); + TAILQ_INSERT_TAIL(ruleset->binats.active.ptr, + newbinat, entries); else if (pcn->action == PF_CHANGE_ADD_HEAD || pcn->action == PF_CHANGE_ADD_BEFORE) TAILQ_INSERT_BEFORE(oldbinat, newbinat, entries); else - TAILQ_INSERT_AFTER(pf_binats_active, oldbinat, - newbinat, entries); + TAILQ_INSERT_AFTER(ruleset->binats.active.ptr, + oldbinat, newbinat, entries); } - ticket_binats_active++; + pf_remove_if_empty_ruleset(ruleset); + pf_update_anchor_rules(); + + ruleset->binats.active.ticket++; splx(s); break; } case DIOCBEGINRDRS: { - u_int32_t *ticket = (u_int32_t *)addr; + struct pfioc_rdr *pr = (struct pfioc_rdr *)addr; + struct pf_ruleset *ruleset; struct pf_rdr *rdr; - while ((rdr = TAILQ_FIRST(pf_rdrs_inactive)) != NULL) { - pf_rm_rdr(pf_rdrs_inactive, rdr); + ruleset = pf_find_or_create_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; } - *ticket = ++ticket_rdrs_inactive; + while ((rdr = TAILQ_FIRST(ruleset->rdrs.inactive.ptr)) != + NULL) + pf_rm_rdr(ruleset->rdrs.inactive.ptr, rdr); + pr->ticket = ++ruleset->rdrs.inactive.ticket; break; } case DIOCADDRDR: { struct pfioc_rdr *pr = (struct pfioc_rdr *)addr; + struct pf_ruleset *ruleset; struct pf_rdr *rdr; - if (pr->pool_ticket != ticket_pabuf) { + ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + if (pr->rdr.anchorname[0] && ruleset != &pf_main_ruleset) { + error = EINVAL; + break; + } + if (pr->ticket != ruleset->rdrs.inactive.ticket) { error = EBUSY; break; } - - if (pr->ticket != ticket_rdrs_inactive) { + if (pr->pool_ticket != ticket_pabuf) { error = EBUSY; break; } @@ -1368,6 +1672,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(&pr->rdr, rdr, sizeof(struct pf_rdr)); + rdr->anchor = NULL; + rdr->ifp = NULL; TAILQ_INIT(&rdr->rpool.list); #ifndef INET if (rdr->af == AF_INET) { @@ -1390,8 +1696,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } - } else - rdr->ifp = NULL; + } if (pf_dynaddr_setup(&rdr->saddr, rdr->af)) error = EINVAL; @@ -1403,60 +1708,79 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } pf_mv_pool(&pf_pabuf[0], &rdr->rpool.list); rdr->rpool.cur = TAILQ_FIRST(&rdr->rpool.list); - TAILQ_INSERT_TAIL(pf_rdrs_inactive, rdr, entries); + TAILQ_INSERT_TAIL(ruleset->rdrs.inactive.ptr, rdr, entries); break; } case DIOCCOMMITRDRS: { - u_int32_t *ticket = (u_int32_t *)addr; + struct pfioc_rdr *pr = (struct pfioc_rdr *)addr; + struct pf_ruleset *ruleset; struct pf_rdrqueue *old_rdrs; struct pf_rdr *rdr; - if (*ticket != ticket_rdrs_inactive) { + ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + if (pr->ticket != ruleset->rdrs.inactive.ticket) { error = EBUSY; break; } /* Swap rdrs, keep the old. */ s = splsoftnet(); - old_rdrs = pf_rdrs_active; - pf_rdrs_active = pf_rdrs_inactive; - pf_rdrs_inactive = old_rdrs; - ticket_rdrs_active = ticket_rdrs_inactive; - splx(s); + old_rdrs = ruleset->rdrs.active.ptr; + ruleset->rdrs.active.ptr = ruleset->rdrs.inactive.ptr; + ruleset->rdrs.inactive.ptr = old_rdrs; + ruleset->rdrs.active.ticket = ruleset->rdrs.inactive.ticket; /* Purge the old rdr list */ - while ((rdr = TAILQ_FIRST(old_rdrs)) != NULL) { + while ((rdr = TAILQ_FIRST(old_rdrs)) != NULL) pf_rm_rdr(old_rdrs, rdr); - } + pf_remove_if_empty_ruleset(ruleset); + pf_update_anchor_rules(); + splx(s); break; } case DIOCGETRDRS: { struct pfioc_rdr *pr = (struct pfioc_rdr *)addr; + struct pf_ruleset *ruleset; struct pf_rdr *rdr; + ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } pr->nr = 0; s = splsoftnet(); - TAILQ_FOREACH(rdr, pf_rdrs_active, entries) + TAILQ_FOREACH(rdr, ruleset->rdrs.active.ptr, entries) pr->nr++; - pr->ticket = ticket_rdrs_active; + pr->ticket = ruleset->rdrs.active.ticket; splx(s); break; } case DIOCGETRDR: { struct pfioc_rdr *pr = (struct pfioc_rdr *)addr; + struct pf_ruleset *ruleset; struct pf_rdr *rdr; u_int32_t nr; - if (pr->ticket != ticket_rdrs_active) { + ruleset = pf_find_ruleset(pr->anchor, pr->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } + if (pr->ticket != ruleset->rdrs.active.ticket) { error = EBUSY; break; } nr = 0; s = splsoftnet(); - rdr = TAILQ_FIRST(pf_rdrs_active); + rdr = TAILQ_FIRST(ruleset->rdrs.active.ptr); while ((rdr != NULL) && (nr < pr->nr)) { rdr = TAILQ_NEXT(rdr, entries); nr++; @@ -1475,6 +1799,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCCHANGERDR: { struct pfioc_changerdr *pcn = (struct pfioc_changerdr *)addr; + struct pf_ruleset *ruleset; struct pf_rdr *oldrdr = NULL, *newrdr = NULL; if (pcn->pool_ticket != ticket_pabuf) { @@ -1487,6 +1812,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } + ruleset = pf_find_ruleset(pcn->anchor, pcn->ruleset); + if (ruleset == NULL) { + error = EINVAL; + break; + } if (pcn->action != PF_CHANGE_REMOVE) { newrdr = pool_get(&pf_rdr_pl, PR_NOWAIT); @@ -1525,7 +1855,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (pf_dynaddr_setup(&newrdr->daddr, newrdr->af)) error = EINVAL; if (error) { - pf_rm_rdr(pf_rdrs_inactive, newrdr); + pf_rm_rdr(NULL, newrdr); break; } pf_mv_pool(&pf_pabuf[0], &newrdr->rpool.list); @@ -1535,12 +1865,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) s = splsoftnet(); if (pcn->action == PF_CHANGE_ADD_HEAD) - oldrdr = TAILQ_FIRST(pf_rdrs_active); + oldrdr = TAILQ_FIRST(ruleset->rdrs.active.ptr); else if (pcn->action == PF_CHANGE_ADD_TAIL) - oldrdr = TAILQ_LAST(pf_rdrs_active, pf_rdrqueue); + oldrdr = TAILQ_LAST(ruleset->rdrs.active.ptr, + pf_rdrqueue); else { pf_mv_pool(&pf_pabuf[1], &pcn->oldrdr.rpool.list); - oldrdr = TAILQ_FIRST(pf_rdrs_active); + oldrdr = TAILQ_FIRST(ruleset->rdrs.active.ptr); while ((oldrdr != NULL) && pf_compare_rdrs(oldrdr, &pcn->oldrdr)) oldrdr = TAILQ_NEXT(oldrdr, entries); @@ -1553,21 +1884,24 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } } - if (pcn->action == PF_CHANGE_REMOVE) { - pf_rm_rdr(pf_rdrs_active, oldrdr); - } else { + if (pcn->action == PF_CHANGE_REMOVE) + pf_rm_rdr(ruleset->rdrs.active.ptr, oldrdr); + else { if (oldrdr == NULL) - TAILQ_INSERT_TAIL(pf_rdrs_active, newrdr, - entries); + TAILQ_INSERT_TAIL(ruleset->rdrs.active.ptr, + newrdr, entries); else if (pcn->action == PF_CHANGE_ADD_HEAD || pcn->action == PF_CHANGE_ADD_BEFORE) TAILQ_INSERT_BEFORE(oldrdr, newrdr, entries); else - TAILQ_INSERT_AFTER(pf_rdrs_active, oldrdr, - newrdr, entries); + TAILQ_INSERT_AFTER(ruleset->rdrs.active.ptr, + oldrdr, newrdr, entries); } - ticket_rdrs_active++; + pf_remove_if_empty_ruleset(ruleset); + pf_update_anchor_rules(); + + ruleset->rdrs.active.ticket++; splx(s); break; } @@ -1733,7 +2067,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; else { status_ifp = ifp; - strlcpy(pf_status.ifname, ifp->if_xname, IFNAMSIZ); + strlcpy(pf_status.ifname, ifp->if_xname, + IFNAMSIZ); } break; } @@ -1877,10 +2212,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCCLRRULECTRS: { + struct pf_ruleset *ruleset = &pf_main_ruleset; struct pf_rule *rule; s = splsoftnet(); - TAILQ_FOREACH(rule, pf_rules_active, entries) + TAILQ_FOREACH(rule, ruleset->rules.active.ptr, entries) rule->evaluations = rule->packets = rule->bytes = 0; splx(s); @@ -2143,13 +2479,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) #endif /* ALTQ */ case DIOCBEGINADDRS: { - u_int32_t *ticket = (u_int32_t *)addr; + struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; pf_empty_pool(&pf_pabuf[1]); pf_mv_pool(&pf_pabuf[0], &pf_pabuf[1]); - - *ticket = ++ticket_pabuf; - + pp->ticket = ++ticket_pabuf; break; } @@ -2198,7 +2532,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) pp->nr = 0; s = splsoftnet(); - pool = pf_get_pool(pp->ticket, pp->r_id, pp->r_num, 1, 0); + pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket, + pp->r_id, pp->r_num, 1, 0); if (pool == NULL) { error = EBUSY; splx(s); @@ -2215,7 +2550,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) u_int32_t nr = 0; s = splsoftnet(); - pool = pf_get_pool(pp->ticket, pp->r_id, pp->r_num, 1, 1); + pool = pf_get_pool(pp->anchor, pp->ruleset, pp->ticket, + pp->r_id, pp->r_num, 1, 1); if (pool == NULL) { error = EBUSY; splx(s); @@ -2247,7 +2583,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } - pool = pf_get_pool(0, pca->r_id, pca->r_num, 1, 0); + pool = pf_get_pool(pca->anchor, pca->ruleset, 0, + pca->r_id, pca->r_num, 1, 0); if (pool == NULL) { error = EBUSY; break; @@ -2330,6 +2667,71 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } + case DIOCGETANCHORS: { + struct pfioc_anchor *pa = (struct pfioc_anchor *)addr; + struct pf_anchor *anchor; + + pa->nr = 0; + TAILQ_FOREACH(anchor, &pf_anchors, entries) + pa->nr++; + break; + } + + case DIOCGETANCHOR: { + struct pfioc_anchor *pa = (struct pfioc_anchor *)addr; + struct pf_anchor *anchor; + u_int32_t nr = 0; + + anchor = TAILQ_FIRST(&pf_anchors); + while (anchor != NULL && nr < pa->nr) { + anchor = TAILQ_NEXT(anchor, entries); + nr++; + } + if (anchor == NULL) + error = EBUSY; + else + bcopy(anchor->name, pa->name, sizeof(pa->name)); + break; + } + + case DIOCGETRULESETS: { + struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; + struct pf_anchor *anchor; + struct pf_ruleset *ruleset; + + pr->anchor[PF_ANCHOR_NAME_SIZE-1] = 0; + if ((anchor = pf_find_anchor(pr->anchor)) == NULL) { + error = EINVAL; + break; + } + pr->nr = 0; + TAILQ_FOREACH(ruleset, &anchor->rulesets, entries) + pr->nr++; + break; + } + + case DIOCGETRULESET: { + struct pfioc_ruleset *pr = (struct pfioc_ruleset *)addr; + struct pf_anchor *anchor; + struct pf_ruleset *ruleset; + u_int32_t nr = 0; + + if ((anchor = pf_find_anchor(pr->anchor)) == NULL) { + error = EINVAL; + break; + } + ruleset = TAILQ_FIRST(&anchor->rulesets); + while (ruleset != NULL && nr < pr->nr) { + ruleset = TAILQ_NEXT(ruleset, entries); + nr++; + } + if (ruleset == NULL) + error = EBUSY; + else + bcopy(ruleset->name, pr->name, sizeof(pr->name)); + break; + } + default: error = ENODEV; break; diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c index 3c45dbd6cb8..e10acfd93f4 100644 --- a/sys/net/pf_norm.c +++ b/sys/net/pf_norm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_norm.c,v 1.39 2002/11/23 05:16:58 mcbride Exp $ */ +/* $OpenBSD: pf_norm.c,v 1.40 2002/12/06 00:47:32 dhartmei Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> @@ -699,7 +699,8 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment *frag, int mff, if (merge) { if (cur && fra->fr_off <= cur->fr_end) { /* Need to merge in a previous 'cur' */ - DPFPRINTF(("fragcache[%d]: adjacent(merge %d-%d) %d-%d (%d-%d)\n", + DPFPRINTF(("fragcache[%d]: adjacent(merge " + "%d-%d) %d-%d (%d-%d)\n", h->ip_id, cur->fr_off, cur->fr_end, off, max, fra->fr_off, fra->fr_end)); fra->fr_off = cur->fr_off; @@ -711,7 +712,8 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment *frag, int mff, } else if (frp && fra->fr_off <= frp->fr_end) { /* Need to merge in a modified 'frp' */ KASSERT(cur == NULL); - DPFPRINTF(("fragcache[%d]: adjacent(merge %d-%d) %d-%d (%d-%d)\n", + DPFPRINTF(("fragcache[%d]: adjacent(merge " + "%d-%d) %d-%d (%d-%d)\n", h->ip_id, frp->fr_off, frp->fr_end, off, max, fra->fr_off, fra->fr_end)); fra->fr_off = frp->fr_off; @@ -797,13 +799,13 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct ifnet *ifp, u_short *reason) int ip_len; int ip_off; - r = TAILQ_FIRST(pf_rules_active); + r = TAILQ_FIRST(pf_main_ruleset.rules.active.ptr); while (r != NULL) { if (r->action != PF_SCRUB) r = r->skip[PF_SKIP_ACTION]; else if (r->ifp != NULL && r->ifp != ifp) r = r->skip[PF_SKIP_IFP]; - else if (r->direction != dir) + else if (r->direction && r->direction != dir) r = r->skip[PF_SKIP_DIR]; else if (r->af && r->af != AF_INET) r = r->skip[PF_SKIP_AF]; @@ -998,13 +1000,13 @@ pf_normalize_tcp(int dir, struct ifnet *ifp, struct mbuf *m, int ipoff, u_int8_t flags; sa_family_t af = pd->af; - r = TAILQ_FIRST(pf_rules_active); + r = TAILQ_FIRST(pf_main_ruleset.rules.active.ptr); while (r != NULL) { if (r->action != PF_SCRUB) r = r->skip[PF_SKIP_ACTION]; else if (r->ifp != NULL && r->ifp != ifp) r = r->skip[PF_SKIP_IFP]; - else if (r->direction != dir) + else if (r->direction && r->direction != dir) r = r->skip[PF_SKIP_DIR]; else if (r->af && r->af != af) r = r->skip[PF_SKIP_AF]; diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 15e56e1eab7..178b4acc49d 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.107 2002/12/01 19:54:32 mcbride Exp $ */ +/* $OpenBSD: pfvar.h,v 1.108 2002/12/06 00:47:32 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -37,7 +37,7 @@ #include <sys/queue.h> #include <sys/tree.h> -enum { PF_IN=0, PF_OUT=1 }; +enum { PF_IN=1, PF_OUT=2 }; enum { PF_PASS=0, PF_DROP=1, PF_SCRUB=2 }; enum { PF_OP_IRG=1, PF_OP_EQ=2, PF_OP_NE=3, PF_OP_LT=4, PF_OP_LE=5, PF_OP_GT=6, PF_OP_GE=7, PF_OP_XRG=8 }; @@ -293,6 +293,8 @@ struct pf_rule { #define PF_QNAME_SIZE 16 char ifname[IFNAMSIZ]; char qname[PF_QNAME_SIZE]; +#define PF_ANCHOR_NAME_SIZE 16 + char anchorname[PF_ANCHOR_NAME_SIZE]; TAILQ_ENTRY(pf_rule) entries; struct pf_pool rt_pool; @@ -301,6 +303,7 @@ struct pf_rule { u_int64_t bytes; struct ifnet *ifp; + struct pf_anchor *anchor; u_int32_t states; u_int32_t max_states; @@ -403,7 +406,9 @@ struct pf_nat { struct pf_pool rpool; struct pf_pooladdr *rcur; char ifname[IFNAMSIZ]; + char anchorname[PF_ANCHOR_NAME_SIZE]; struct ifnet *ifp; + struct pf_anchor *anchor; TAILQ_ENTRY(pf_nat) entries; u_int32_t rlistid; u_int16_t proxy_port[2]; @@ -415,7 +420,9 @@ struct pf_nat { struct pf_binat { char ifname[IFNAMSIZ]; + char anchorname[PF_ANCHOR_NAME_SIZE]; struct ifnet *ifp; + struct pf_anchor *anchor; TAILQ_ENTRY(pf_binat) entries; struct pf_addr_wrap saddr; struct pf_addr_wrap daddr; @@ -428,7 +435,9 @@ struct pf_binat { struct pf_rdr { char ifname[IFNAMSIZ]; + char anchorname[PF_ANCHOR_NAME_SIZE]; struct ifnet *ifp; + struct pf_anchor *anchor; TAILQ_ENTRY(pf_rdr) entries; struct pf_addr_wrap saddr; struct pf_addr_wrap daddr; @@ -448,6 +457,56 @@ struct pf_rdr { }; TAILQ_HEAD(pf_rulequeue, pf_rule); +TAILQ_HEAD(pf_natqueue, pf_nat); +TAILQ_HEAD(pf_binatqueue, pf_binat); +TAILQ_HEAD(pf_rdrqueue, pf_rdr); + +struct pf_anchor; + +struct pf_ruleset { + TAILQ_ENTRY(pf_ruleset) entries; +#define PF_RULESET_NAME_SIZE 16 + char name[PF_RULESET_NAME_SIZE]; + struct { + struct pf_rulequeue queues[2]; + struct { + struct pf_rulequeue *ptr; + u_int32_t ticket; + } active, inactive; + } rules; + struct { + struct pf_natqueue queues[2]; + struct { + struct pf_natqueue *ptr; + u_int32_t ticket; + } active, inactive; + } nats; + struct { + struct pf_rdrqueue queues[2]; + struct { + struct pf_rdrqueue *ptr; + u_int32_t ticket; + } active, inactive; + } rdrs; + struct { + struct pf_binatqueue queues[2]; + struct { + struct pf_binatqueue *ptr; + u_int32_t ticket; + } active, inactive; + } binats; + struct pf_anchor *anchor; +}; + +TAILQ_HEAD(pf_rulesetqueue, pf_ruleset); + +struct pf_anchor { + TAILQ_ENTRY(pf_anchor) entries; + char name[PF_ANCHOR_NAME_SIZE]; + struct pf_rulesetqueue rulesets; +}; + +TAILQ_HEAD(pf_anchorqueue, pf_anchor); struct pf_pdesc { u_int64_t tot_len; /* Make Mickey money */ @@ -619,6 +678,8 @@ struct pfioc_pooladdr { u_int32_t r_num; u_int8_t r_id; u_int8_t af; + char anchor[PF_ANCHOR_NAME_SIZE]; + char ruleset[PF_RULESET_NAME_SIZE]; struct pf_pooladdr addr; }; @@ -627,6 +688,8 @@ struct pfioc_changeaddr { u_int32_t r_num; u_int8_t r_id; u_int8_t af; + char anchor[PF_ANCHOR_NAME_SIZE]; + char ruleset[PF_RULESET_NAME_SIZE]; struct pf_pooladdr newaddr; struct pf_pooladdr oldaddr; }; @@ -635,26 +698,34 @@ struct pfioc_rule { u_int32_t ticket; u_int32_t pool_ticket; u_int32_t nr; + char anchor[PF_ANCHOR_NAME_SIZE]; + char ruleset[PF_RULESET_NAME_SIZE]; struct pf_rule rule; }; struct pfioc_changerule { - u_int32_t pool_ticket; - u_int32_t action; - struct pf_rule oldrule; - struct pf_rule newrule; + u_int32_t pool_ticket; + u_int32_t action; + char anchor[PF_ANCHOR_NAME_SIZE]; + char ruleset[PF_RULESET_NAME_SIZE]; + struct pf_rule oldrule; + struct pf_rule newrule; }; struct pfioc_nat { u_int32_t ticket; u_int32_t pool_ticket; u_int32_t nr; + char anchor[PF_ANCHOR_NAME_SIZE]; + char ruleset[PF_RULESET_NAME_SIZE]; struct pf_nat nat; }; struct pfioc_changenat { u_int32_t pool_ticket; u_int32_t action; + char anchor[PF_ANCHOR_NAME_SIZE]; + char ruleset[PF_RULESET_NAME_SIZE]; struct pf_nat oldnat; struct pf_nat newnat; }; @@ -676,25 +747,33 @@ struct pfioc_natlook { struct pfioc_binat { u_int32_t ticket; u_int32_t nr; + char anchor[PF_ANCHOR_NAME_SIZE]; + char ruleset[PF_RULESET_NAME_SIZE]; struct pf_binat binat; }; struct pfioc_changebinat { - u_int32_t action; - struct pf_binat oldbinat; - struct pf_binat newbinat; + u_int32_t action; + char anchor[PF_ANCHOR_NAME_SIZE]; + char ruleset[PF_RULESET_NAME_SIZE]; + struct pf_binat oldbinat; + struct pf_binat newbinat; }; struct pfioc_rdr { u_int32_t ticket; u_int32_t pool_ticket; u_int32_t nr; + char anchor[PF_ANCHOR_NAME_SIZE]; + char ruleset[PF_RULESET_NAME_SIZE]; struct pf_rdr rdr; }; struct pfioc_changerdr { u_int32_t pool_ticket; u_int32_t action; + char anchor[PF_ANCHOR_NAME_SIZE]; + char ruleset[PF_RULESET_NAME_SIZE]; struct pf_rdr oldrdr; struct pf_rdr newrdr; }; @@ -756,25 +835,37 @@ struct pfioc_qstats { u_int8_t scheduler; }; +struct pfioc_anchor { + u_int32_t nr; + char name[PF_ANCHOR_NAME_SIZE]; +}; + +struct pfioc_ruleset { + u_int32_t nr; + char anchor[PF_ANCHOR_NAME_SIZE]; + char name[PF_RULESET_NAME_SIZE]; +}; + + /* * ioctl operations */ #define DIOCSTART _IO ('D', 1) #define DIOCSTOP _IO ('D', 2) -#define DIOCBEGINRULES _IOWR('D', 3, u_int32_t) +#define DIOCBEGINRULES _IOWR('D', 3, struct pfioc_rule) #define DIOCADDRULE _IOWR('D', 4, struct pfioc_rule) -#define DIOCCOMMITRULES _IOWR('D', 5, u_int32_t) +#define DIOCCOMMITRULES _IOWR('D', 5, struct pfioc_rule) #define DIOCGETRULES _IOWR('D', 6, struct pfioc_rule) #define DIOCGETRULE _IOWR('D', 7, struct pfioc_rule) -#define DIOCBEGINNATS _IOWR('D', 8, u_int32_t) +#define DIOCBEGINNATS _IOWR('D', 8, struct pfioc_nat) #define DIOCADDNAT _IOWR('D', 9, struct pfioc_nat) -#define DIOCCOMMITNATS _IOWR('D', 10, u_int32_t) +#define DIOCCOMMITNATS _IOWR('D', 10, struct pfioc_nat) #define DIOCGETNATS _IOWR('D', 11, struct pfioc_nat) #define DIOCGETNAT _IOWR('D', 12, struct pfioc_nat) -#define DIOCBEGINRDRS _IOWR('D', 13, u_int32_t) +#define DIOCBEGINRDRS _IOWR('D', 13, struct pfioc_rdr) #define DIOCADDRDR _IOWR('D', 14, struct pfioc_rdr) -#define DIOCCOMMITRDRS _IOWR('D', 15, u_int32_t) +#define DIOCCOMMITRDRS _IOWR('D', 15, struct pfioc_rdr) #define DIOCGETRDRS _IOWR('D', 16, struct pfioc_rdr) #define DIOCGETRDR _IOWR('D', 17, struct pfioc_rdr) #define DIOCCLRSTATES _IO ('D', 18) @@ -790,9 +881,9 @@ struct pfioc_qstats { #define DIOCCHANGERDR _IOWR('D', 28, struct pfioc_changerdr) #define DIOCSETTIMEOUT _IOWR('D', 29, struct pfioc_tm) #define DIOCGETTIMEOUT _IOWR('D', 30, struct pfioc_tm) -#define DIOCBEGINBINATS _IOWR('D', 31, u_int32_t) +#define DIOCBEGINBINATS _IOWR('D', 31, struct pfioc_binat) #define DIOCADDBINAT _IOWR('D', 32, struct pfioc_binat) -#define DIOCCOMMITBINATS _IOWR('D', 33, u_int32_t) +#define DIOCCOMMITBINATS _IOWR('D', 33, struct pfioc_binat) #define DIOCGETBINATS _IOWR('D', 34, struct pfioc_binat) #define DIOCGETBINAT _IOWR('D', 35, struct pfioc_binat) #define DIOCCHANGEBINAT _IOWR('D', 36, struct pfioc_changebinat) @@ -810,11 +901,15 @@ struct pfioc_qstats { #define DIOCGETALTQ _IOWR('D', 48, struct pfioc_altq) #define DIOCCHANGEALTQ _IOWR('D', 49, struct pfioc_altq) #define DIOCGETQSTATS _IOWR('D', 50, struct pfioc_qstats) -#define DIOCBEGINADDRS _IOWR('D', 51, u_int32_t) +#define DIOCBEGINADDRS _IOWR('D', 51, struct pfioc_pooladdr) #define DIOCADDADDR _IOWR('D', 52, struct pfioc_pooladdr) #define DIOCGETADDRS _IOWR('D', 53, struct pfioc_pooladdr) #define DIOCGETADDR _IOWR('D', 54, struct pfioc_pooladdr) #define DIOCCHANGEADDR _IOWR('D', 55, struct pfioc_changeaddr) +#define DIOCGETANCHORS _IOWR('D', 56, struct pfioc_anchor) +#define DIOCGETANCHOR _IOWR('D', 57, struct pfioc_anchor) +#define DIOCGETRULESETS _IOWR('D', 58, struct pfioc_ruleset) +#define DIOCGETRULESET _IOWR('D', 59, struct pfioc_ruleset) #ifdef _KERNEL @@ -822,13 +917,8 @@ RB_HEAD(pf_state_tree, pf_tree_node); RB_PROTOTYPE(pf_state_tree, pf_tree_node, entry, pf_state_compare); extern struct pf_state_tree tree_lan_ext, tree_ext_gwy; -extern struct pf_rulequeue pf_rules[2]; -TAILQ_HEAD(pf_natqueue, pf_nat); -extern struct pf_natqueue pf_nats[2]; -TAILQ_HEAD(pf_binatqueue, pf_binat); -extern struct pf_binatqueue pf_binats[2]; -TAILQ_HEAD(pf_rdrqueue, pf_rdr); -extern struct pf_rdrqueue pf_rdrs[2]; +extern struct pf_anchorqueue pf_anchors; +extern struct pf_ruleset pf_main_ruleset; TAILQ_HEAD(pf_poolqueue, pf_pool); extern struct pf_poolqueue pf_pools[2]; TAILQ_HEAD(pf_altqqueue, pf_altq); @@ -836,27 +926,9 @@ extern struct pf_altqqueue pf_altqs[2]; extern struct pf_palist pf_pabuf[2]; -extern u_int32_t ticket_rules_active; -extern u_int32_t ticket_rules_active; -extern u_int32_t ticket_rules_inactive; -extern u_int32_t ticket_nats_active; -extern u_int32_t ticket_nats_inactive; -extern u_int32_t ticket_binats_active; -extern u_int32_t ticket_binats_inactive; -extern u_int32_t ticket_rdrs_active; -extern u_int32_t ticket_rdrs_inactive; -extern u_int32_t ticket_rules_inactive; extern u_int32_t ticket_altqs_active; extern u_int32_t ticket_altqs_inactive; extern u_int32_t ticket_pabuf; -extern struct pf_rulequeue *pf_rules_active; -extern struct pf_rulequeue *pf_rules_inactive; -extern struct pf_natqueue *pf_nats_active; -extern struct pf_natqueue *pf_nats_inactive; -extern struct pf_binatqueue *pf_binats_active; -extern struct pf_binatqueue *pf_binats_inactive; -extern struct pf_rdrqueue *pf_rdrs_active; -extern struct pf_rdrqueue *pf_rdrs_inactive; extern struct pf_altqqueue *pf_altqs_active; extern struct pf_altqqueue *pf_altqs_inactive; extern struct pf_poolqueue *pf_pools_active; @@ -865,6 +937,7 @@ extern void pf_dynaddr_remove(struct pf_addr_wrap *); extern int pf_dynaddr_setup(struct pf_addr_wrap *, u_int8_t); extern void pf_calc_skip_steps(struct pf_rulequeue *); +extern void pf_update_anchor_rules(void); extern void pf_dynaddr_copyout(struct pf_addr_wrap *); extern struct pool pf_tree_pl, pf_rule_pl, pf_nat_pl; extern struct pool pf_rdr_pl, pf_state_pl, pf_binat_pl, @@ -877,6 +950,7 @@ extern void pf_purge_expired_states(void); extern int pf_insert_state(struct pf_state *); extern struct pf_state *pf_find_state(struct pf_state_tree *, struct pf_tree_node *); +extern struct pf_anchor *pf_find_anchor(const char *); extern struct ifnet *status_ifp; extern int *pftm_timeouts[PFTM_MAX]; extern void pf_addrcpy(struct pf_addr *, struct pf_addr *, @@ -904,7 +978,6 @@ int pf_normalize_ip(struct mbuf **, int, struct ifnet *, u_short *); void pf_purge_expired_fragments(void); int pf_routable(struct pf_addr *addr, sa_family_t af); -extern struct pf_rulequeue *pf_rules_active; extern struct pf_status pf_status; extern struct pool pf_frent_pl, pf_frag_pl; struct pf_pool_limit { |