Index: head/UPDATING =================================================================== --- head/UPDATING +++ head/UPDATING @@ -31,6 +31,11 @@ disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20150827: + pf no longer supports 'scrub fragment crop' or 'scrub fragment drop-ovl' + These configurations are now automatically interpreted as + 'scrub fragment reassemble'. + 20150817: Kernel-loadable modules for the random(4) device are back. To use them, the kernel must have Index: head/sbin/pfctl/parse.y =================================================================== --- head/sbin/pfctl/parse.y +++ head/sbin/pfctl/parse.y @@ -1197,8 +1197,8 @@ ; fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } - | FRAGMENT FRAGCROP { $$ = PFRULE_FRAGCROP; } - | FRAGMENT FRAGDROP { $$ = PFRULE_FRAGDROP; } + | FRAGMENT FRAGCROP { $$ = 0; } + | FRAGMENT FRAGDROP { $$ = 0; } ; antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { Index: head/sbin/pfctl/pfctl_parser.c =================================================================== --- head/sbin/pfctl/pfctl_parser.c +++ head/sbin/pfctl/pfctl_parser.c @@ -990,12 +990,7 @@ if (r->rule_flag & PFRULE_REASSEMBLE_TCP) printf(" reassemble tcp"); - if (r->rule_flag & PFRULE_FRAGDROP) - printf(" fragment drop-ovl"); - else if (r->rule_flag & PFRULE_FRAGCROP) - printf(" fragment crop"); - else - printf(" fragment reassemble"); + printf(" fragment reassemble"); } if (r->label[0]) printf(" label \"%s\"", r->label); Index: head/share/man/man5/pf.conf.5 =================================================================== --- head/share/man/man5/pf.conf.5 +++ head/share/man/man5/pf.conf.5 @@ -666,33 +666,6 @@ The advantage is that filter rules have to deal only with complete packets, and can ignore fragments. The drawback of caching fragments is the additional memory cost. -But the full reassembly method is the only method that currently works -with NAT. -This is the default behavior of a -.Ar scrub -rule if no fragmentation modifier is supplied. -.It Ar fragment crop -The default fragment reassembly method is expensive, hence the option -to crop is provided. -In this case, -.Xr pf 4 -will track the fragments and cache a small range descriptor. -Duplicate fragments are dropped and overlaps are cropped. -Thus data will only occur once on the wire with ambiguities resolving to -the first occurrence. -Unlike the -.Ar fragment reassemble -modifier, fragments are not buffered, they are passed as soon as they -are received. -The -.Ar fragment crop -reassembly mechanism does not yet work with NAT. -.It Ar fragment drop-ovl -This option is similar to the -.Ar fragment crop -modifier except that all overlapping or duplicate fragments will be -dropped, and all further corresponding fragments will be -dropped as well. .It Ar reassemble tcp Statefully normalizes TCP connections. .Ar scrub reassemble tcp @@ -2987,8 +2960,7 @@ "overload" "\*(Lt" string "\*(Gt" [ "flush" ] | "if-bound" | "floating" ) -fragmentation = [ "fragment reassemble" | "fragment crop" | - "fragment drop-ovl" ] +fragmentation = [ "fragment reassemble" ] timeout-list = timeout [ [ "," ] timeout-list ] timeout = ( "tcp.first" | "tcp.opening" | "tcp.established" | Index: head/sys/net/pfvar.h =================================================================== --- head/sys/net/pfvar.h +++ head/sys/net/pfvar.h @@ -598,8 +598,6 @@ /* scrub flags */ #define PFRULE_NODF 0x0100 -#define PFRULE_FRAGCROP 0x0200 /* non-buffering frag cache */ -#define PFRULE_FRAGDROP 0x0400 /* drop funny fragments */ #define PFRULE_RANDOMID 0x0800 #define PFRULE_REASSEMBLE_TCP 0x1000 #define PFRULE_SET_TOS 0x2000 Index: head/sys/netpfil/pf/pf_norm.c =================================================================== --- head/sys/netpfil/pf/pf_norm.c +++ head/sys/netpfil/pf/pf_norm.c @@ -88,12 +88,6 @@ RB_ENTRY(pf_fragment) fr_entry; TAILQ_ENTRY(pf_fragment) frag_next; - uint8_t fr_flags; /* status flags */ -#define PFFRAG_SEENLAST 0x0001 /* Seen the last fragment for this */ -#define PFFRAG_NOBUFFER 0x0002 /* Non-buffering fragment cache */ -#define PFFRAG_DROP 0x0004 /* Drop all fragments */ -#define BUFFER_FRAGMENTS(fr) (!((fr)->fr_flags & PFFRAG_NOBUFFER)) - uint16_t fr_max; /* fragment data max */ uint32_t fr_timeout; uint16_t fr_maxlen; /* maximum length of single fragment */ TAILQ_HEAD(pf_fragq, pf_frent) fr_queue; @@ -123,13 +117,9 @@ TAILQ_HEAD(pf_cachequeue, pf_fragment); static VNET_DEFINE(struct pf_fragqueue, pf_fragqueue); #define V_pf_fragqueue VNET(pf_fragqueue) -static VNET_DEFINE(struct pf_cachequeue, pf_cachequeue); -#define V_pf_cachequeue VNET(pf_cachequeue) RB_HEAD(pf_frag_tree, pf_fragment); static VNET_DEFINE(struct pf_frag_tree, pf_frag_tree); #define V_pf_frag_tree VNET(pf_frag_tree) -static VNET_DEFINE(struct pf_frag_tree, pf_cache_tree); -#define V_pf_cache_tree VNET(pf_cache_tree) static int pf_frag_compare(struct pf_fragment *, struct pf_fragment *); static RB_PROTOTYPE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare); @@ -150,8 +140,6 @@ #ifdef INET static void pf_scrub_ip(struct mbuf **, uint32_t, uint8_t, uint8_t); static int pf_reassemble(struct mbuf **, struct ip *, int, u_short *); -static struct mbuf *pf_fragcache(struct mbuf **, struct ip*, - struct pf_fragment **, int, int, int *); #endif /* INET */ #ifdef INET6 static int pf_reassemble6(struct mbuf **, struct ip6_hdr *, @@ -197,7 +185,6 @@ uma_zone_set_warning(V_pf_frent_z, "PF frag entries limit reached"); TAILQ_INIT(&V_pf_fragqueue); - TAILQ_INIT(&V_pf_cachequeue); } void @@ -236,8 +223,6 @@ PF_FRAG_LOCK(); while ((frag = TAILQ_LAST(&V_pf_fragqueue, pf_fragqueue)) != NULL) { - KASSERT((BUFFER_FRAGMENTS(frag)), - ("BUFFER_FRAGMENTS(frag) == 0: %s", __FUNCTION__)); if (frag->fr_timeout > expire) break; @@ -245,19 +230,6 @@ pf_free_fragment(frag); } - while ((frag = TAILQ_LAST(&V_pf_cachequeue, pf_cachequeue)) != NULL) { - KASSERT((!BUFFER_FRAGMENTS(frag)), - ("BUFFER_FRAGMENTS(frag) != 0: %s", __FUNCTION__)); - if (frag->fr_timeout > expire) - break; - - DPFPRINTF(("expiring %d(%p)\n", frag->fr_id, frag)); - pf_free_fragment(frag); - KASSERT((TAILQ_EMPTY(&V_pf_cachequeue) || - TAILQ_LAST(&V_pf_cachequeue, pf_cachequeue) != frag), - ("!(TAILQ_EMPTY() || TAILQ_LAST() == farg): %s", - __FUNCTION__)); - } PF_FRAG_UNLOCK(); } @@ -267,7 +239,7 @@ static void pf_flush_fragments(void) { - struct pf_fragment *frag, *cache; + struct pf_fragment *frag; int goal; PF_FRAG_ASSERT(); @@ -278,10 +250,7 @@ frag = TAILQ_LAST(&V_pf_fragqueue, pf_fragqueue); if (frag) pf_free_fragment(frag); - cache = TAILQ_LAST(&V_pf_cachequeue, pf_cachequeue); - if (cache) - pf_free_fragment(cache); - if (frag == NULL && cache == NULL) + else break; } } @@ -295,27 +264,12 @@ PF_FRAG_ASSERT(); /* Free all fragments */ - if (BUFFER_FRAGMENTS(frag)) { - for (frent = TAILQ_FIRST(&frag->fr_queue); frent; - frent = TAILQ_FIRST(&frag->fr_queue)) { - TAILQ_REMOVE(&frag->fr_queue, frent, fr_next); - - m_freem(frent->fe_m); - uma_zfree(V_pf_frent_z, frent); - } - } else { - for (frent = TAILQ_FIRST(&frag->fr_queue); frent; - frent = TAILQ_FIRST(&frag->fr_queue)) { - TAILQ_REMOVE(&frag->fr_queue, frent, fr_next); - - KASSERT((TAILQ_EMPTY(&frag->fr_queue) || - TAILQ_FIRST(&frag->fr_queue)->fe_off > - frent->fe_len), - ("! (TAILQ_EMPTY() || TAILQ_FIRST()->fe_off >" - " frent->fe_len): %s", __func__)); + for (frent = TAILQ_FIRST(&frag->fr_queue); frent; + frent = TAILQ_FIRST(&frag->fr_queue)) { + TAILQ_REMOVE(&frag->fr_queue, frent, fr_next); - uma_zfree(V_pf_frent_z, frent); - } + m_freem(frent->fe_m); + uma_zfree(V_pf_frent_z, frent); } pf_remove_fragment(frag); @@ -332,13 +286,8 @@ if (frag != NULL) { /* XXX Are we sure we want to update the timeout? */ frag->fr_timeout = time_uptime; - if (BUFFER_FRAGMENTS(frag)) { - TAILQ_REMOVE(&V_pf_fragqueue, frag, frag_next); - TAILQ_INSERT_HEAD(&V_pf_fragqueue, frag, frag_next); - } else { - TAILQ_REMOVE(&V_pf_cachequeue, frag, frag_next); - TAILQ_INSERT_HEAD(&V_pf_cachequeue, frag, frag_next); - } + TAILQ_REMOVE(&V_pf_fragqueue, frag, frag_next); + TAILQ_INSERT_HEAD(&V_pf_fragqueue, frag, frag_next); } return (frag); @@ -351,15 +300,9 @@ PF_FRAG_ASSERT(); - if (BUFFER_FRAGMENTS(frag)) { - RB_REMOVE(pf_frag_tree, &V_pf_frag_tree, frag); - TAILQ_REMOVE(&V_pf_fragqueue, frag, frag_next); - uma_zfree(V_pf_frag_z, frag); - } else { - RB_REMOVE(pf_frag_tree, &V_pf_cache_tree, frag); - TAILQ_REMOVE(&V_pf_cachequeue, frag, frag_next); - uma_zfree(V_pf_frag_z, frag); - } + RB_REMOVE(pf_frag_tree, &V_pf_frag_tree, frag); + TAILQ_REMOVE(&V_pf_fragqueue, frag, frag_next); + uma_zfree(V_pf_frag_z, frag); } static struct pf_frent * @@ -431,7 +374,6 @@ } *(struct pf_fragment_cmp *)frag = *key; - frag->fr_flags = 0; frag->fr_timeout = time_second; frag->fr_maxlen = frent->fe_len; TAILQ_INIT(&frag->fr_queue); @@ -782,312 +724,6 @@ } #endif /* INET6 */ -#ifdef INET -static struct mbuf * -pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, - int drop, int *nomem) -{ - struct mbuf *m = *m0; - struct pf_frent *frp, *fra, *cur = NULL; - int ip_len = ntohs(h->ip_len) - (h->ip_hl << 2); - u_int16_t off = ntohs(h->ip_off) << 3; - u_int16_t max = ip_len + off; - int hosed = 0; - - PF_FRAG_ASSERT(); - KASSERT((*frag == NULL || !BUFFER_FRAGMENTS(*frag)), - ("!(*frag == NULL || !BUFFER_FRAGMENTS(*frag)): %s", __FUNCTION__)); - - /* Create a new range queue for this packet */ - if (*frag == NULL) { - *frag = uma_zalloc(V_pf_frag_z, M_NOWAIT); - if (*frag == NULL) { - pf_flush_fragments(); - *frag = uma_zalloc(V_pf_frag_z, M_NOWAIT); - if (*frag == NULL) - goto no_mem; - } - - /* Get an entry for the queue */ - cur = uma_zalloc(V_pf_frent_z, M_NOWAIT); - if (cur == NULL) { - uma_zfree(V_pf_frag_z, *frag); - *frag = NULL; - goto no_mem; - } - - (*frag)->fr_flags = PFFRAG_NOBUFFER; - (*frag)->fr_max = 0; - (*frag)->fr_src.v4 = h->ip_src; - (*frag)->fr_dst.v4 = h->ip_dst; - (*frag)->fr_af = AF_INET; - (*frag)->fr_proto = h->ip_p; - (*frag)->fr_id = h->ip_id; - (*frag)->fr_timeout = time_uptime; - - cur->fe_off = off; - cur->fe_len = max; /* TODO: fe_len = max - off ? */ - TAILQ_INIT(&(*frag)->fr_queue); - TAILQ_INSERT_HEAD(&(*frag)->fr_queue, cur, fr_next); - - RB_INSERT(pf_frag_tree, &V_pf_cache_tree, *frag); - TAILQ_INSERT_HEAD(&V_pf_cachequeue, *frag, frag_next); - - DPFPRINTF(("fragcache[%d]: new %d-%d\n", h->ip_id, off, max)); - - goto pass; - } - - /* - * Find a fragment after the current one: - * - off contains the real shifted offset. - */ - frp = NULL; - TAILQ_FOREACH(fra, &(*frag)->fr_queue, fr_next) { - if (fra->fe_off > off) - break; - frp = fra; - } - - KASSERT((frp != NULL || fra != NULL), - ("!(frp != NULL || fra != NULL): %s", __FUNCTION__)); - - if (frp != NULL) { - int precut; - - precut = frp->fe_len - off; - if (precut >= ip_len) { - /* Fragment is entirely a duplicate */ - DPFPRINTF(("fragcache[%d]: dead (%d-%d) %d-%d\n", - h->ip_id, frp->fe_off, frp->fe_len, off, max)); - goto drop_fragment; - } - if (precut == 0) { - /* They are adjacent. Fixup cache entry */ - DPFPRINTF(("fragcache[%d]: adjacent (%d-%d) %d-%d\n", - h->ip_id, frp->fe_off, frp->fe_len, off, max)); - frp->fe_len = max; - } else if (precut > 0) { - /* The first part of this payload overlaps with a - * fragment that has already been passed. - * Need to trim off the first part of the payload. - * But to do so easily, we need to create another - * mbuf to throw the original header into. - */ - - DPFPRINTF(("fragcache[%d]: chop %d (%d-%d) %d-%d\n", - h->ip_id, precut, frp->fe_off, frp->fe_len, off, - max)); - - off += precut; - max -= precut; - /* Update the previous frag to encompass this one */ - frp->fe_len = max; - - if (!drop) { - /* XXX Optimization opportunity - * This is a very heavy way to trim the payload. - * we could do it much faster by diddling mbuf - * internals but that would be even less legible - * than this mbuf magic. For my next trick, - * I'll pull a rabbit out of my laptop. - */ - *m0 = m_dup(m, M_NOWAIT); - if (*m0 == NULL) - goto no_mem; - /* From KAME Project : We have missed this! */ - m_adj(*m0, (h->ip_hl << 2) - - (*m0)->m_pkthdr.len); - - KASSERT(((*m0)->m_next == NULL), - ("(*m0)->m_next != NULL: %s", - __FUNCTION__)); - m_adj(m, precut + (h->ip_hl << 2)); - m_cat(*m0, m); - m = *m0; - if (m->m_flags & M_PKTHDR) { - int plen = 0; - struct mbuf *t; - for (t = m; t; t = t->m_next) - plen += t->m_len; - m->m_pkthdr.len = plen; - } - - - h = mtod(m, struct ip *); - - KASSERT(((int)m->m_len == - ntohs(h->ip_len) - precut), - ("m->m_len != ntohs(h->ip_len) - precut: %s", - __FUNCTION__)); - h->ip_off = htons(ntohs(h->ip_off) + - (precut >> 3)); - h->ip_len = htons(ntohs(h->ip_len) - precut); - } else { - hosed++; - } - } else { - /* There is a gap between fragments */ - - DPFPRINTF(("fragcache[%d]: gap %d (%d-%d) %d-%d\n", - h->ip_id, -precut, frp->fe_off, frp->fe_len, off, - max)); - - cur = uma_zalloc(V_pf_frent_z, M_NOWAIT); - if (cur == NULL) - goto no_mem; - - cur->fe_off = off; - cur->fe_len = max; - TAILQ_INSERT_AFTER(&(*frag)->fr_queue, frp, cur, fr_next); - } - } - - if (fra != NULL) { - int aftercut; - int merge = 0; - - aftercut = max - fra->fe_off; - if (aftercut == 0) { - /* Adjacent fragments */ - DPFPRINTF(("fragcache[%d]: adjacent %d-%d (%d-%d)\n", - h->ip_id, off, max, fra->fe_off, fra->fe_len)); - fra->fe_off = off; - merge = 1; - } else if (aftercut > 0) { - /* Need to chop off the tail of this fragment */ - DPFPRINTF(("fragcache[%d]: chop %d %d-%d (%d-%d)\n", - h->ip_id, aftercut, off, max, fra->fe_off, - fra->fe_len)); - fra->fe_off = off; - max -= aftercut; - - merge = 1; - - if (!drop) { - m_adj(m, -aftercut); - if (m->m_flags & M_PKTHDR) { - int plen = 0; - struct mbuf *t; - for (t = m; t; t = t->m_next) - plen += t->m_len; - m->m_pkthdr.len = plen; - } - h = mtod(m, struct ip *); - KASSERT(((int)m->m_len == ntohs(h->ip_len) - aftercut), - ("m->m_len != ntohs(h->ip_len) - aftercut: %s", - __FUNCTION__)); - h->ip_len = htons(ntohs(h->ip_len) - aftercut); - } else { - hosed++; - } - } else if (frp == NULL) { - /* There is a gap between fragments */ - DPFPRINTF(("fragcache[%d]: gap %d %d-%d (%d-%d)\n", - h->ip_id, -aftercut, off, max, fra->fe_off, - fra->fe_len)); - - cur = uma_zalloc(V_pf_frent_z, M_NOWAIT); - if (cur == NULL) - goto no_mem; - - cur->fe_off = off; - cur->fe_len = max; - TAILQ_INSERT_HEAD(&(*frag)->fr_queue, cur, fr_next); - } - - - /* Need to glue together two separate fragment descriptors */ - if (merge) { - if (cur && fra->fe_off <= cur->fe_len) { - /* Need to merge in a previous 'cur' */ - DPFPRINTF(("fragcache[%d]: adjacent(merge " - "%d-%d) %d-%d (%d-%d)\n", - h->ip_id, cur->fe_off, cur->fe_len, off, - max, fra->fe_off, fra->fe_len)); - fra->fe_off = cur->fe_off; - TAILQ_REMOVE(&(*frag)->fr_queue, cur, fr_next); - uma_zfree(V_pf_frent_z, cur); - cur = NULL; - - } else if (frp && fra->fe_off <= frp->fe_len) { - /* Need to merge in a modified 'frp' */ - KASSERT((cur == NULL), ("cur != NULL: %s", - __FUNCTION__)); - DPFPRINTF(("fragcache[%d]: adjacent(merge " - "%d-%d) %d-%d (%d-%d)\n", - h->ip_id, frp->fe_off, frp->fe_len, off, - max, fra->fe_off, fra->fe_len)); - fra->fe_off = frp->fe_off; - TAILQ_REMOVE(&(*frag)->fr_queue, frp, fr_next); - uma_zfree(V_pf_frent_z, frp); - frp = NULL; - - } - } - } - - if (hosed) { - /* - * We must keep tracking the overall fragment even when - * we're going to drop it anyway so that we know when to - * free the overall descriptor. Thus we drop the frag late. - */ - goto drop_fragment; - } - - - pass: - /* Update maximum data size */ - if ((*frag)->fr_max < max) - (*frag)->fr_max = max; - - /* This is the last segment */ - if (!mff) - (*frag)->fr_flags |= PFFRAG_SEENLAST; - - /* Check if we are completely reassembled */ - if (((*frag)->fr_flags & PFFRAG_SEENLAST) && - TAILQ_FIRST(&(*frag)->fr_queue)->fe_off == 0 && - TAILQ_FIRST(&(*frag)->fr_queue)->fe_len == (*frag)->fr_max) { - /* Remove from fragment queue */ - DPFPRINTF(("fragcache[%d]: done 0-%d\n", h->ip_id, - (*frag)->fr_max)); - pf_free_fragment(*frag); - *frag = NULL; - } - - return (m); - - no_mem: - *nomem = 1; - - /* Still need to pay attention to !IP_MF */ - if (!mff && *frag != NULL) - (*frag)->fr_flags |= PFFRAG_SEENLAST; - - m_freem(m); - return (NULL); - - drop_fragment: - - /* Still need to pay attention to !IP_MF */ - if (!mff && *frag != NULL) - (*frag)->fr_flags |= PFFRAG_SEENLAST; - - if (drop) { - /* This fragment has been deemed bad. Don't reass */ - if (((*frag)->fr_flags & PFFRAG_DROP) == 0) - DPFPRINTF(("fragcache[%d]: dropping overall fragment\n", - h->ip_id)); - (*frag)->fr_flags |= PFFRAG_DROP; - } - - m_freem(m); - return (NULL); -} -#endif /* INET */ - #ifdef INET6 int pf_refragment6(struct ifnet *ifp, struct mbuf **m0, struct m_tag *mtag) @@ -1169,8 +805,6 @@ { struct mbuf *m = *m0; struct pf_rule *r; - struct pf_fragment *frag = NULL; - struct pf_fragment_cmp key; struct ip *h = mtod(m, struct ip *); int mff = (ntohs(h->ip_off) & IP_MF); int hlen = h->ip_hl << 2; @@ -1217,11 +851,15 @@ } /* Check for illegal packets */ - if (hlen < (int)sizeof(struct ip)) + if (hlen < (int)sizeof(struct ip)) { + REASON_SET(reason, PFRES_NORM); goto drop; + } - if (hlen > ntohs(h->ip_len)) + if (hlen > ntohs(h->ip_len)) { + REASON_SET(reason, PFRES_NORM); goto drop; + } /* Clear IP_DF if the rule uses the no-df option */ if (r->rule_flag & PFRULE_NODF && h->ip_off & htons(IP_DF)) { @@ -1260,82 +898,21 @@ } max = fragoff + ip_len; - if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0) { - - /* Fully buffer all of the fragments */ - PF_FRAG_LOCK(); - - pf_ip2key(h, dir, &key); - frag = pf_find_fragment(&key, &V_pf_frag_tree); - - /* Check if we saw the last fragment already */ - if (frag != NULL && (frag->fr_flags & PFFRAG_SEENLAST) && - max > frag->fr_max) - goto bad; - - /* Might return a completely reassembled mbuf, or NULL */ - DPFPRINTF(("reass frag %d @ %d-%d\n", h->ip_id, fragoff, max)); - verdict = pf_reassemble(m0, h, dir, reason); - PF_FRAG_UNLOCK(); - - if (verdict != PF_PASS) - return (PF_DROP); - - m = *m0; - if (m == NULL) - return (PF_DROP); - - h = mtod(m, struct ip *); - } else { - /* non-buffering fragment cache (drops or masks overlaps) */ - int nomem = 0; - - if (dir == PF_OUT && pd->pf_mtag && - pd->pf_mtag->flags & PF_TAG_FRAGCACHE) { - /* - * Already passed the fragment cache in the - * input direction. If we continued, it would - * appear to be a dup and would be dropped. - */ - goto fragment_pass; - } - - PF_FRAG_LOCK(); - pf_ip2key(h, dir, &key); - frag = pf_find_fragment(&key, &V_pf_cache_tree); - - /* Check if we saw the last fragment already */ - if (frag != NULL && (frag->fr_flags & PFFRAG_SEENLAST) && - max > frag->fr_max) { - if (r->rule_flag & PFRULE_FRAGDROP) - frag->fr_flags |= PFFRAG_DROP; - goto bad; - } + /* 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(); - *m0 = m = pf_fragcache(m0, h, &frag, mff, - (r->rule_flag & PFRULE_FRAGDROP) ? 1 : 0, &nomem); - PF_FRAG_UNLOCK(); - if (m == NULL) { - if (nomem) - goto no_mem; - goto drop; - } + if (verdict != PF_PASS) + return (PF_DROP); - if (dir == PF_IN) { - /* Use mtag from copied and trimmed mbuf chain. */ - pd->pf_mtag = pf_get_mtag(m); - if (pd->pf_mtag == NULL) { - m_freem(m); - *m0 = NULL; - goto no_mem; - } - pd->pf_mtag->flags |= PF_TAG_FRAGCACHE; - } + m = *m0; + if (m == NULL) + return (PF_DROP); - if (frag != NULL && (frag->fr_flags & PFFRAG_DROP)) - goto drop; - goto fragment_pass; - } + h = mtod(m, struct ip *); no_fragment: /* At this point, only IP_DF is allowed in ip_off */ @@ -1346,39 +923,14 @@ h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0); } - /* not missing a return here */ - - fragment_pass: pf_scrub_ip(&m, r->rule_flag, r->min_ttl, r->set_tos); - if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0) - pd->flags |= PFDESC_IP_REAS; return (PF_PASS); - no_mem: - REASON_SET(reason, PFRES_MEMORY); - if (r != NULL && r->log) - PFLOG_PACKET(kif, m, AF_INET, dir, *reason, r, NULL, NULL, pd, - 1); - return (PF_DROP); - - drop: - REASON_SET(reason, PFRES_NORM); - if (r != NULL && r->log) - PFLOG_PACKET(kif, m, AF_INET, dir, *reason, r, NULL, NULL, pd, - 1); - return (PF_DROP); - bad: DPFPRINTF(("dropping bad fragment\n")); - - /* Free associated fragments */ - if (frag != NULL) { - pf_free_fragment(frag); - PF_FRAG_UNLOCK(); - } - REASON_SET(reason, PFRES_FRAG); + drop: if (r != NULL && r->log) PFLOG_PACKET(kif, m, AF_INET, dir, *reason, r, NULL, NULL, pd, 1);