diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y --- a/sbin/pfctl/parse.y +++ b/sbin/pfctl/parse.y @@ -1528,9 +1528,9 @@ } ; -fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } - | FRAGMENT FRAGCROP { $$ = 0; } - | FRAGMENT FRAGDROP { $$ = 0; } +fragcache : FRAGMENT REASSEMBLE { $$ = PFRULE_REASSEMBLE_FRAG; } + | FRAGMENT FRAGCROP { $$ = PFRULE_REASSEMBLE_FRAG; } + | FRAGMENT FRAGDROP { $$ = PFRULE_REASSEMBLE_FRAG; } ; antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -1131,7 +1131,8 @@ if (r->rule_flag & PFRULE_REASSEMBLE_TCP) printf(" reassemble tcp"); - printf(" fragment reassemble"); + if (r->rule_flag & PFRULE_REASSEMBLE_FRAG) + printf(" fragment reassemble"); } i = 0; while (r->label[i][0]) diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h --- a/sys/netpfil/pf/pf.h +++ b/sys/netpfil/pf/pf.h @@ -598,6 +598,7 @@ /* scrub flags */ #define PFRULE_NODF 0x0100 +#define PFRULE_REASSEMBLE_FRAG 0x0200 #define PFRULE_RANDOMID 0x0800 #define PFRULE_REASSEMBLE_TCP 0x1000 #define PFRULE_SET_TOS 0x2000 diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c --- a/sys/netpfil/pf/pf_norm.c +++ b/sys/netpfil/pf/pf_norm.c @@ -1115,31 +1115,34 @@ DPFPRINTF(("max packet %d\n", fragoff + ip_len)); goto bad; } - max = fragoff + ip_len; - /* Fully buffer all of the fragments - * Might return a completely reassembled mbuf, or NULL */ - PF_FRAG_LOCK(); - DPFPRINTF(("reass frag %d @ %d-%d\n", h->ip_id, fragoff, max)); - verdict = pf_reassemble(m0, h, dir, reason); - PF_FRAG_UNLOCK(); + if (r->rule_flag & PFRULE_REASSEMBLE_FRAG) { + max = fragoff + ip_len; - if (verdict != PF_PASS) - return (PF_DROP); + /* Fully buffer all of the fragments + * Might return a completely reassembled mbuf, or NULL */ + PF_FRAG_LOCK(); + DPFPRINTF(("reass frag %d @ %d-%d\n", h->ip_id, fragoff, max)); + verdict = pf_reassemble(m0, h, dir, reason); + PF_FRAG_UNLOCK(); - m = *m0; - if (m == NULL) - return (PF_DROP); + if (verdict != PF_PASS) + return (PF_DROP); + + m = *m0; + if (m == NULL) + return (PF_DROP); - h = mtod(m, struct ip *); + h = mtod(m, struct ip *); no_fragment: - /* At this point, only IP_DF is allowed in ip_off */ - if (h->ip_off & ~htons(IP_DF)) { - u_int16_t ip_off = h->ip_off; + /* At this point, only IP_DF is allowed in ip_off */ + if (h->ip_off & ~htons(IP_DF)) { + u_int16_t ip_off = h->ip_off; - h->ip_off &= htons(IP_DF); - h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0); + h->ip_off &= htons(IP_DF); + h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0); + } } pf_scrub_ip(&m, r->rule_flag, r->min_ttl, r->set_tos);