Date: Thu, 27 Aug 2015 21:27:48 +0000 (UTC) From: Kristof Provost <kp@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r287222 - in head: . sbin/pfctl share/man/man5 sys/net sys/netpfil/pf Message-ID: <201508272127.t7RLRmlO056289@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kp Date: Thu Aug 27 21:27:47 2015 New Revision: 287222 URL: https://svnweb.freebsd.org/changeset/base/287222 Log: pf: Remove support for 'scrub fragment crop|drop-ovl' The crop/drop-ovl fragment scrub modes are not very useful and likely to confuse users into making poor choices. It's also a fairly large amount of complex code, so just remove the support altogether. Users who have 'scrub fragment crop|drop-ovl' in their pf configuration will be implicitly converted to 'scrub fragment reassemble'. Reviewed by: gnn, eri Relnotes: yes Differential Revision: https://reviews.freebsd.org/D3466 Modified: head/UPDATING head/sbin/pfctl/parse.y head/sbin/pfctl/pfctl_parser.c head/share/man/man5/pf.conf.5 head/sys/net/pfvar.h head/sys/netpfil/pf/pf_norm.c Modified: head/UPDATING ============================================================================== --- head/UPDATING Thu Aug 27 21:16:24 2015 (r287221) +++ head/UPDATING Thu Aug 27 21:27:47 2015 (r287222) @@ -31,6 +31,11 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 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 Modified: head/sbin/pfctl/parse.y ============================================================================== --- head/sbin/pfctl/parse.y Thu Aug 27 21:16:24 2015 (r287221) +++ head/sbin/pfctl/parse.y Thu Aug 27 21:27:47 2015 (r287222) @@ -1197,8 +1197,8 @@ scrub_opt : NODF { ; 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 { Modified: head/sbin/pfctl/pfctl_parser.c ============================================================================== --- head/sbin/pfctl/pfctl_parser.c Thu Aug 27 21:16:24 2015 (r287221) +++ head/sbin/pfctl/pfctl_parser.c Thu Aug 27 21:27:47 2015 (r287222) @@ -990,12 +990,7 @@ print_rule(struct pf_rule *r, const char 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); Modified: head/share/man/man5/pf.conf.5 ============================================================================== --- head/share/man/man5/pf.conf.5 Thu Aug 27 21:16:24 2015 (r287221) +++ head/share/man/man5/pf.conf.5 Thu Aug 27 21:27:47 2015 (r287222) @@ -666,33 +666,6 @@ packet, and only the completed packet is 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 @@ state-opt = ( "max" number | "no-sy "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" | Modified: head/sys/net/pfvar.h ============================================================================== --- head/sys/net/pfvar.h Thu Aug 27 21:16:24 2015 (r287221) +++ head/sys/net/pfvar.h Thu Aug 27 21:27:47 2015 (r287222) @@ -598,8 +598,6 @@ struct pf_rule { /* 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 Modified: head/sys/netpfil/pf/pf_norm.c ============================================================================== --- head/sys/netpfil/pf/pf_norm.c Thu Aug 27 21:16:24 2015 (r287221) +++ head/sys/netpfil/pf/pf_norm.c Thu Aug 27 21:27:47 2015 (r287222) @@ -88,12 +88,6 @@ struct pf_fragment { 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_fragqueue, pf_fragment); 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 @@ static struct mbuf *pf_join_fragment(str #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 @@ pf_normalize_init(void) 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_purge_expired_fragments(void) 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_purge_expired_fragments(void) 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 @@ pf_purge_expired_fragments(void) static void pf_flush_fragments(void) { - struct pf_fragment *frag, *cache; + struct pf_fragment *frag; int goal; PF_FRAG_ASSERT(); @@ -278,10 +250,7 @@ pf_flush_fragments(void) 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_free_fragment(struct pf_fragment *fra 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 @@ pf_find_fragment(struct pf_fragment_cmp 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_remove_fragment(struct pf_fragment *f 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 @@ pf_fillup_fragment(struct pf_fragment_cm } *(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 @@ fail: } #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 @@ pf_normalize_ip(struct mbuf **m0, int di { 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 @@ pf_normalize_ip(struct mbuf **m0, int di } /* 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 @@ pf_normalize_ip(struct mbuf **m0, int di } 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 @@ pf_normalize_ip(struct mbuf **m0, int di 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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201508272127.t7RLRmlO056289>