diff options
author | Daniel Hartmeier <dhartmei@cvs.openbsd.org> | 2002-04-23 14:32:24 +0000 |
---|---|---|
committer | Daniel Hartmeier <dhartmei@cvs.openbsd.org> | 2002-04-23 14:32:24 +0000 |
commit | d70cb2c050204739bb31da06800d79bad94f2730 (patch) | |
tree | 36a354437114272043ed536e25019006c1c1301d /sys/net | |
parent | 06672d3a1880a142ab171f0458ad27cdb1f8e81a (diff) |
Allow explicit filtering of fragments when they are not reassembled.
Document fragment handling in the man page. Short version: if you're
scrubbing everything (as is recommended, in general), nothing changes.
If you want to deal with fragments manually, read the man page.
ok frantzen.
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/pf.c | 79 | ||||
-rw-r--r-- | sys/net/pfvar.h | 3 |
2 files changed, 80 insertions, 2 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c index 7af714ba79a..af5df4d570a 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.202 2002/04/20 10:13:57 fgsch Exp $ */ +/* $OpenBSD: pf.c,v 1.203 2002/04/23 14:32:22 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -245,6 +245,8 @@ 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_state_tcp(struct pf_state **, int, struct ifnet *, struct mbuf *, int, int, void *, struct pf_pdesc *); @@ -3005,6 +3007,8 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp, else if (r->dst.port_op && !pf_match_port(r->dst.port_op, r->dst.port[0], r->dst.port[1], th->th_dport)) r = r->skip[PF_SKIP_DST_PORT]; + else if (r->rule_flag & PFRULE_FRAGMENT) + r = TAILQ_NEXT(r, entries); else if ((r->flagset & th->th_flags) != r->flags) r = TAILQ_NEXT(r, entries); else { @@ -3239,6 +3243,8 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp, else if (r->dst.port_op && !pf_match_port(r->dst.port_op, r->dst.port[0], r->dst.port[1], uh->uh_dport)) r = r->skip[PF_SKIP_DST_PORT]; + else if (r->rule_flag & PFRULE_FRAGMENT) + r = TAILQ_NEXT(r, entries); else { *rm = r; if ((*rm)->quick) @@ -3513,6 +3519,8 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp, r = TAILQ_NEXT(r, entries); else if (r->code && r->code != icmpcode + 1) r = TAILQ_NEXT(r, entries); + else if (r->rule_flag & PFRULE_FRAGMENT) + r = TAILQ_NEXT(r, entries); else { *rm = r; if ((*rm)->quick) @@ -3716,6 +3724,8 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp, !PF_AZERO(&r->dst.mask, af) && !PF_MATCHA(r->dst.not, &r->dst.addr, &r->dst.mask, pd->dst, af)) r = r->skip[PF_SKIP_DST_ADDR]; + else if (r->rule_flag & PFRULE_FRAGMENT) + r = TAILQ_NEXT(r, entries); else { *rm = r; if ((*rm)->quick) @@ -3794,6 +3804,67 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp, } 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; + u_int8_t af = pd->af; + + *rm = NULL; + + r = TAILQ_FIRST(pf_rules_active); + while (r != NULL) { + r->evaluations++; + 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 != direction) + r = r->skip[PF_SKIP_DIR]; + else if (r->af && r->af != af) + r = r->skip[PF_SKIP_AF]; + else if (r->proto && r->proto != pd->proto) + r = r->skip[PF_SKIP_PROTO]; + else if (r->src.noroute && pf_routable(pd->src, af)) + r = TAILQ_NEXT(r, entries); + else if (!r->src.noroute && + !PF_AZERO(&r->src.mask, af) && !PF_MATCHA(r->src.not, + &r->src.addr, &r->src.mask, pd->src, af)) + r = r->skip[PF_SKIP_SRC_ADDR]; + else if (r->dst.noroute && pf_routable(pd->dst, af)) + r = TAILQ_NEXT(r, entries); + else if (!r->src.noroute && + !PF_AZERO(&r->dst.mask, af) && !PF_MATCHA(r->dst.not, + &r->dst.addr, &r->dst.mask, pd->dst, af)) + r = r->skip[PF_SKIP_DST_ADDR]; + 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; + r = TAILQ_NEXT(r, entries); + } + } + + if (*rm != NULL) { + u_short reason; + + (*rm)->packets++; + (*rm)->bytes += pd->tot_len; + REASON_SET(&reason, PFRES_MATCH); + if ((*rm)->log) + PFLOG_PACKET(ifp, h, m, af, direction, reason, *rm); + + if ((*rm)->action != PF_PASS) + return (PF_DROP); + } + + return (PF_PASS); +} + +int pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd) { @@ -5087,6 +5158,12 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) pd.af = AF_INET; pd.tot_len = h->ip_len; + /* handle fragments that didn't get reassembled by normalization */ + if (h->ip_off & (IP_MF | IP_OFFMASK)) { + action = pf_test_fragment(&r, dir, ifp, m, h, &pd); + goto done; + } + switch (h->ip_p) { case IPPROTO_TCP: { diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 0c32f00293c..824be2b28bd 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.66 2002/03/27 18:16:21 mickey Exp $ */ +/* $OpenBSD: pfvar.h,v 1.67 2002/04/23 14:32:22 dhartmei Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -245,6 +245,7 @@ struct pf_rule { #define PFRULE_RETURNRST 0x01 #define PFRULE_NODF 0x02 +#define PFRULE_FRAGMENT 0x04 struct pf_state_host { struct pf_addr addr; |