diff options
-rw-r--r-- | sys/net/pf_norm.c | 515 |
1 files changed, 284 insertions, 231 deletions
diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c index de3dabd9d3c..875bbb1b261 100644 --- a/sys/net/pf_norm.c +++ b/sys/net/pf_norm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_norm.c,v 1.128 2011/02/01 16:10:31 bluhm Exp $ */ +/* $OpenBSD: pf_norm.c,v 1.129 2011/03/23 18:34:17 bluhm Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> @@ -63,24 +63,45 @@ #include <net/pfvar.h> struct pf_frent { - LIST_ENTRY(pf_frent) fr_next; - struct ip *fr_ip; - struct mbuf *fr_m; + TAILQ_ENTRY(pf_frent) fr_next; + struct mbuf *fe_m; + u_int16_t fe_hdrlen; /* ipv4 header lenght with ip options + ipv6, extension, fragment header */ + u_int16_t fe_extoff; /* last extension header offset or 0 */ + u_int16_t fe_len; /* fragment length */ + u_int16_t fe_off; /* fragment offset */ + u_int16_t fe_mff; /* more fragment flag */ }; -#define PFFRAG_SEENLAST 0x0001 /* Seen the last fragment for this */ +/* keep synced with struct pf_fragment, used in RB_FIND */ +struct pf_fragment_cmp { + struct pf_addr fr_src; + struct pf_addr fr_dst; + u_int32_t fr_id; + sa_family_t fr_af; + u_int8_t fr_proto; + u_int8_t fr_direction; +}; struct pf_fragment { + struct pf_addr fr_src; /* ip source address */ + struct pf_addr fr_dst; /* ip destination address */ + u_int32_t fr_id; /* fragment id for reassemble */ + sa_family_t fr_af; /* address family */ + u_int8_t fr_proto; /* protocol of this fragment */ + u_int8_t fr_direction; /* pf packet direction */ + RB_ENTRY(pf_fragment) fr_entry; TAILQ_ENTRY(pf_fragment) frag_next; - struct in_addr fr_src; - struct in_addr fr_dst; - u_int8_t fr_p; /* protocol of this fragment */ - u_int8_t fr_flags; /* status flags */ - u_int16_t fr_id; /* fragment id for reassemble */ - u_int16_t fr_max; /* fragment data max */ u_int32_t fr_timeout; - LIST_HEAD(pf_fragq, pf_frent) fr_queue; + u_int16_t fr_maxlen; /* maximum length of single fragment */ + TAILQ_HEAD(pf_fragq, pf_frent) fr_queue; +}; + +struct pf_fragment_tag { + u_int16_t ft_hdrlen; /* header lenght of reassembled pkt */ + u_int16_t ft_extoff; /* last extension header offset or 0 */ + u_int16_t ft_maxlen; /* maximum fragment payload length */ }; TAILQ_HEAD(pf_fragqueue, pf_fragment) pf_fragqueue; @@ -92,13 +113,18 @@ RB_PROTOTYPE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare); RB_GENERATE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare); /* Private prototypes */ -void pf_ip2key(struct pf_fragment *, struct ip *); void pf_remove_fragment(struct pf_fragment *); void pf_flush_fragments(void); void pf_free_fragment(struct pf_fragment *); -struct pf_fragment *pf_find_fragment(struct ip *, struct pf_frag_tree *); -int pf_reassemble(struct mbuf **, struct pf_fragment **, - struct pf_frent *, int, u_short *); +struct pf_fragment *pf_find_fragment(struct pf_fragment_cmp *, + struct pf_frag_tree *); +struct pf_frent *pf_create_fragment(u_short *); +struct pf_fragment *pf_fillup_fragment(struct pf_fragment_cmp *, + struct pf_frent *, u_short *); +int pf_isfull_fragment(struct pf_fragment *); +struct mbuf *pf_join_fragment(struct pf_fragment *); +int pf_reassemble(struct mbuf **, struct ip *, int, + u_short *); /* Globals */ struct pool pf_frent_pl, pf_frag_pl; @@ -126,18 +152,16 @@ pf_frag_compare(struct pf_fragment *a, struct pf_fragment *b) { int diff; - if ((diff = a->fr_id - b->fr_id)) + if ((diff = a->fr_id - b->fr_id) != 0) return (diff); - else if ((diff = a->fr_p - b->fr_p)) + if ((diff = a->fr_proto - b->fr_proto) != 0) + return (diff); + if ((diff = a->fr_af - b->fr_af) != 0) + return (diff); + if ((diff = pf_addr_compare(&a->fr_src, &b->fr_src, a->fr_af)) != 0) + return (diff); + if ((diff = pf_addr_compare(&a->fr_dst, &b->fr_dst, a->fr_af)) != 0) return (diff); - else if (a->fr_src.s_addr < b->fr_src.s_addr) - return (-1); - else if (a->fr_src.s_addr > b->fr_src.s_addr) - return (1); - else if (a->fr_dst.s_addr < b->fr_dst.s_addr) - return (-1); - else if (a->fr_dst.s_addr > b->fr_dst.s_addr) - return (1); return (0); } @@ -186,11 +210,11 @@ pf_free_fragment(struct pf_fragment *frag) struct pf_frent *frent; /* Free all fragments */ - for (frent = LIST_FIRST(&frag->fr_queue); frent; - frent = LIST_FIRST(&frag->fr_queue)) { - LIST_REMOVE(frent, fr_next); + 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->fr_m); + m_freem(frent->fe_m); pool_put(&pf_frent_pl, frent); pf_nfrents--; } @@ -198,24 +222,12 @@ pf_free_fragment(struct pf_fragment *frag) pf_remove_fragment(frag); } -void -pf_ip2key(struct pf_fragment *key, struct ip *ip) -{ - key->fr_p = ip->ip_p; - key->fr_id = ip->ip_id; - key->fr_src.s_addr = ip->ip_src.s_addr; - key->fr_dst.s_addr = ip->ip_dst.s_addr; -} - struct pf_fragment * -pf_find_fragment(struct ip *ip, struct pf_frag_tree *tree) +pf_find_fragment(struct pf_fragment_cmp *key, struct pf_frag_tree *tree) { - struct pf_fragment key; struct pf_fragment *frag; - pf_ip2key(&key, ip); - - frag = RB_FIND(pf_frag_tree, tree, &key); + frag = RB_FIND(pf_frag_tree, tree, (struct pf_fragment *)key); if (frag != NULL) { /* XXX Are we sure we want to update the timeout? */ frag->fr_timeout = time_second; @@ -236,196 +248,297 @@ pf_remove_fragment(struct pf_fragment *frag) pool_put(&pf_frag_pl, frag); } -#define FR_IP_OFF(fr) ((ntohs((fr)->fr_ip->ip_off) & IP_OFFMASK) << 3) -int -pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, - struct pf_frent *frent, int mff, u_short *reason) +struct pf_frent * +pf_create_fragment(u_short *reason) { - struct mbuf *m = *m0, *m2; - struct pf_frent *frea, *next; - struct pf_frent *frep = NULL; - struct ip *ip = frent->fr_ip; - int hlen = ip->ip_hl << 2; - u_int16_t off = (ntohs(ip->ip_off) & IP_OFFMASK) << 3; - u_int16_t ip_len = ntohs(ip->ip_len) - ip->ip_hl * 4; - u_int16_t max = ip_len + off; - - /* Strip off ip header */ - m->m_data += hlen; - m->m_len -= hlen; + struct pf_frent *frent; + + frent = pool_get(&pf_frent_pl, PR_NOWAIT); + if (frent == NULL) { + pf_flush_fragments(); + frent = pool_get(&pf_frent_pl, PR_NOWAIT); + if (frent == NULL) { + REASON_SET(reason, PFRES_MEMORY); + return (NULL); + } + } + pf_nfrents++; + + return (frent); +} + +struct pf_fragment * +pf_fillup_fragment(struct pf_fragment_cmp *key, struct pf_frent *frent, + u_short *reason) +{ + struct pf_frent *after, *next, *prev; + struct pf_fragment *frag; + u_int16_t total; + + /* No empty fragments */ + if (frent->fe_len == 0) { + DPFPRINTF(LOG_NOTICE, "bad fragment: len 0"); + goto bad_fragment; + } + + /* All fragments are 8 byte aligned */ + if (frent->fe_mff && (frent->fe_len & 0x7)) { + DPFPRINTF(LOG_NOTICE, "bad fragment: mff and len %d", + frent->fe_len); + goto bad_fragment; + } + + /* Respect maximum length, IP_MAXPACKET == IPV6_MAXPACKET */ + if (frent->fe_off + frent->fe_len > IP_MAXPACKET) { + DPFPRINTF(LOG_NOTICE, "bad fragment: max packet %d", + frent->fe_off + frent->fe_len); + goto bad_fragment; + } + + DPFPRINTF(LOG_NOTICE, key->fr_af == AF_INET ? + "reass frag %d @ %d-%d" : "reass frag %#08x @ %d-%d", + key->fr_id, frent->fe_off, frent->fe_off + frent->fe_len); + + /* Fully buffer all of the fragments in this fragment queue */ + frag = pf_find_fragment(key, &pf_frag_tree); /* Create a new reassembly queue for this packet */ - if (*frag == NULL) { - *frag = pool_get(&pf_frag_pl, PR_NOWAIT); - if (*frag == NULL) { + if (frag == NULL) { + frag = pool_get(&pf_frag_pl, PR_NOWAIT); + if (frag == NULL) { pf_flush_fragments(); - *frag = pool_get(&pf_frag_pl, PR_NOWAIT); - if (*frag == NULL) { + frag = pool_get(&pf_frag_pl, PR_NOWAIT); + if (frag == NULL) { REASON_SET(reason, PFRES_MEMORY); goto drop_fragment; } } - (*frag)->fr_flags = 0; - (*frag)->fr_max = 0; - (*frag)->fr_src = frent->fr_ip->ip_src; - (*frag)->fr_dst = frent->fr_ip->ip_dst; - (*frag)->fr_p = frent->fr_ip->ip_p; - (*frag)->fr_id = frent->fr_ip->ip_id; - (*frag)->fr_timeout = time_second; - LIST_INIT(&(*frag)->fr_queue); + *(struct pf_fragment_cmp *)frag = *key; + frag->fr_timeout = time_second; + frag->fr_maxlen = frent->fe_len; + TAILQ_INIT(&frag->fr_queue); - RB_INSERT(pf_frag_tree, &pf_frag_tree, *frag); - TAILQ_INSERT_HEAD(&pf_fragqueue, *frag, frag_next); + RB_INSERT(pf_frag_tree, &pf_frag_tree, frag); + TAILQ_INSERT_HEAD(&pf_fragqueue, frag, frag_next); /* We do not have a previous fragment */ - frep = NULL; - goto insert; + TAILQ_INSERT_HEAD(&frag->fr_queue, frent, fr_next); + + return (frag); } - /* - * Find a fragment after the current one: - * - off contains the real shifted offset. - */ - LIST_FOREACH(frea, &(*frag)->fr_queue, fr_next) { - if (FR_IP_OFF(frea) > off) + KASSERT(!TAILQ_EMPTY(&frag->fr_queue)); + + /* Remember maximum fragment len for refragmentation */ + if (frent->fe_len > frag->fr_maxlen) + frag->fr_maxlen = frent->fe_len; + + /* Maximum data we have seen already */ + total = TAILQ_LAST(&frag->fr_queue, pf_fragq)->fe_off + + TAILQ_LAST(&frag->fr_queue, pf_fragq)->fe_len; + + /* Non terminal fragments must have more fragments flag */ + if (frent->fe_off + frent->fe_len < total && !frent->fe_mff) + goto bad_fragment; + + /* Check if we saw the last fragment already */ + if (!TAILQ_LAST(&frag->fr_queue, pf_fragq)->fe_mff) { + if (frent->fe_off + frent->fe_len > total || + (frent->fe_off + frent->fe_len == total && frent->fe_mff)) + goto bad_fragment; + } else { + if (frent->fe_off + frent->fe_len == total && !frent->fe_mff) + goto bad_fragment; + } + + /* Find a fragment after the current one */ + prev = NULL; + TAILQ_FOREACH(after, &frag->fr_queue, fr_next) { + if (after->fe_off > frent->fe_off) break; - frep = frea; + prev = after; } - KASSERT(frep != NULL || frea != NULL); + KASSERT(prev != NULL || after != NULL); - if (frep != NULL && - FR_IP_OFF(frep) + ntohs(frep->fr_ip->ip_len) - frep->fr_ip->ip_hl * - 4 > off) - { + if (prev != NULL && prev->fe_off + prev->fe_len > frent->fe_off) { u_int16_t precut; - precut = FR_IP_OFF(frep) + ntohs(frep->fr_ip->ip_len) - - frep->fr_ip->ip_hl * 4 - off; - if (precut >= ip_len) + precut = prev->fe_off + prev->fe_len - frent->fe_off; + if (precut >= frent->fe_len) goto bad_fragment; - m_adj(frent->fr_m, precut); DPFPRINTF(LOG_NOTICE, "overlap -%d", precut); - /* Enforce 8 byte boundaries */ - ip->ip_off = htons(ntohs(ip->ip_off) + (precut >> 3)); - off = (ntohs(ip->ip_off) & IP_OFFMASK) << 3; - ip_len -= precut; - ip->ip_len = htons(ip_len); + m_adj(frent->fe_m, precut); + frent->fe_off += precut; + frent->fe_len -= precut; } - for (; frea != NULL && ip_len + off > FR_IP_OFF(frea); - frea = next) + for (; after != NULL && frent->fe_off + frent->fe_len > after->fe_off; + after = next) { u_int16_t aftercut; - aftercut = ip_len + off - FR_IP_OFF(frea); + aftercut = frent->fe_off + frent->fe_len - after->fe_off; DPFPRINTF(LOG_NOTICE, "adjust overlap %d", aftercut); - if (aftercut < ntohs(frea->fr_ip->ip_len) - frea->fr_ip->ip_hl - * 4) - { - frea->fr_ip->ip_len = - htons(ntohs(frea->fr_ip->ip_len) - aftercut); - frea->fr_ip->ip_off = htons(ntohs(frea->fr_ip->ip_off) + - (aftercut >> 3)); - m_adj(frea->fr_m, aftercut); + if (aftercut < after->fe_len) { + m_adj(after->fe_m, aftercut); + after->fe_off += aftercut; + after->fe_len -= aftercut; break; } /* This fragment is completely overlapped, lose it */ - next = LIST_NEXT(frea, fr_next); - m_freem(frea->fr_m); - LIST_REMOVE(frea, fr_next); - pool_put(&pf_frent_pl, frea); + next = TAILQ_NEXT(after, fr_next); + m_freem(after->fe_m); + TAILQ_REMOVE(&frag->fr_queue, after, fr_next); + pool_put(&pf_frent_pl, after); pf_nfrents--; } - insert: - /* 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; - - if (frep == NULL) - LIST_INSERT_HEAD(&(*frag)->fr_queue, frent, fr_next); + if (prev == NULL) + TAILQ_INSERT_HEAD(&frag->fr_queue, frent, fr_next); else - LIST_INSERT_AFTER(frep, frent, fr_next); + TAILQ_INSERT_AFTER(&frag->fr_queue, prev, frent, fr_next); - /* The mbuf is part of the fragment entry, no direct free or access */ - m = *m0 = NULL; + return (frag); + + bad_fragment: + REASON_SET(reason, PFRES_FRAG); + drop_fragment: + pool_put(&pf_frent_pl, frent); + pf_nfrents--; + return (NULL); +} + +int +pf_isfull_fragment(struct pf_fragment *frag) +{ + struct pf_frent *frent, *next; + u_int16_t off, total; /* Check if we are completely reassembled */ - if (!((*frag)->fr_flags & PFFRAG_SEENLAST)) - return (PF_PASS); + if (TAILQ_LAST(&frag->fr_queue, pf_fragq)->fe_mff) + return (0); + + /* Maximum data we have seen already */ + total = TAILQ_LAST(&frag->fr_queue, pf_fragq)->fe_off + + TAILQ_LAST(&frag->fr_queue, pf_fragq)->fe_len; /* Check if we have all the data */ off = 0; - for (frep = LIST_FIRST(&(*frag)->fr_queue); frep; frep = next) { - next = LIST_NEXT(frep, fr_next); + for (frent = TAILQ_FIRST(&frag->fr_queue); frent; frent = next) { + next = TAILQ_NEXT(frent, fr_next); - off += ntohs(frep->fr_ip->ip_len) - frep->fr_ip->ip_hl * 4; - if (off < (*frag)->fr_max && - (next == NULL || FR_IP_OFF(next) != off)) - { + off += frent->fe_len; + if (off < total && (next == NULL || next->fe_off != off)) { DPFPRINTF(LOG_NOTICE, - "missing fragment at %d, next %d, max %d", - off, next == NULL ? -1 : FR_IP_OFF(next), - (*frag)->fr_max); - return (PF_PASS); + "missing fragment at %d, next %d, total %d", + off, next == NULL ? -1 : next->fe_off, total); + return (0); } } - DPFPRINTF(LOG_NOTICE, "%d < %d?", off, (*frag)->fr_max); - if (off < (*frag)->fr_max) - return (PF_PASS); + DPFPRINTF(LOG_NOTICE, "%d < %d?", off, total); + if (off < total) + return (0); + KASSERT(off == total); - /* We have all the data */ - frent = LIST_FIRST(&(*frag)->fr_queue); - KASSERT(frent != NULL); - next = LIST_NEXT(frent, fr_next); + return (1); +} + +struct mbuf * +pf_join_fragment(struct pf_fragment *frag) +{ + struct mbuf *m, *m2; + struct pf_frent *frent, *next; + + frent = TAILQ_FIRST(&frag->fr_queue); + next = TAILQ_NEXT(frent, fr_next); /* Magic from ip_input */ - ip = frent->fr_ip; - m = frent->fr_m; + m = frent->fe_m; m2 = m->m_next; m->m_next = NULL; m_cat(m, m2); pool_put(&pf_frent_pl, frent); pf_nfrents--; for (frent = next; frent != NULL; frent = next) { - next = LIST_NEXT(frent, fr_next); + next = TAILQ_NEXT(frent, fr_next); - m2 = frent->fr_m; + m2 = frent->fe_m; + /* Strip off ip header */ + m_adj(m2, frent->fe_hdrlen); pool_put(&pf_frent_pl, frent); pf_nfrents--; m_cat(m, m2); } - ip->ip_src = (*frag)->fr_src; - ip->ip_dst = (*frag)->fr_dst; - /* Remove from fragment queue */ - pf_remove_fragment(*frag); - *frag = NULL; - *m0 = m; + pf_remove_fragment(frag); + + return (m); +} + +int +pf_reassemble(struct mbuf **m0, struct ip *ip, int dir, u_short *reason) +{ + struct mbuf *m = *m0; + struct pf_frent *frent; + struct pf_fragment *frag; + struct pf_fragment_cmp key; + u_int16_t total, hdrlen; + + /* Get an entry for the fragment queue */ + if ((frent = pf_create_fragment(reason)) == NULL) + return (PF_DROP); + + frent->fe_m = m; + frent->fe_hdrlen = ip->ip_hl << 2; + frent->fe_extoff = 0; + frent->fe_len = ntohs(ip->ip_len) - (ip->ip_hl << 2); + frent->fe_off = (ntohs(ip->ip_off) & IP_OFFMASK) << 3; + frent->fe_mff = ntohs(ip->ip_off) & IP_MF; + + key.fr_src.v4 = ip->ip_src; + key.fr_dst.v4 = ip->ip_dst; + key.fr_af = AF_INET; + key.fr_proto = ip->ip_p; + key.fr_id = ip->ip_id; + key.fr_direction = dir; + + if ((frag = pf_fillup_fragment(&key, frent, reason)) == NULL) + return (PF_DROP); + + /* The mbuf is part of the fragment entry, no direct free or access */ + m = *m0 = NULL; + + if (!pf_isfull_fragment(frag)) + return (PF_PASS); /* drop because *m0 is NULL, no error */ + + /* We have all the data */ + frent = TAILQ_FIRST(&frag->fr_queue); + KASSERT(frent != NULL); + total = TAILQ_LAST(&frag->fr_queue, pf_fragq)->fe_off + + TAILQ_LAST(&frag->fr_queue, pf_fragq)->fe_len; + hdrlen = frent->fe_hdrlen; - hlen = ip->ip_hl << 2; - ip->ip_len = htons(off + hlen); - m->m_len += hlen; - m->m_data -= hlen; + m = *m0 = pf_join_fragment(frag); + frag = NULL; - /* some debugging cruft by sklower, below, will go away soon */ - /* XXX this should be done elsewhere */ if (m->m_flags & M_PKTHDR) { int plen = 0; - for (m2 = m; m2; m2 = m2->m_next) - plen += m2->m_len; + for (m = *m0; m; m = m->m_next) + plen += m->m_len; + m = *m0; m->m_pkthdr.len = plen; } - if (hlen + off > IP_MAXPACKET) { - DPFPRINTF(LOG_NOTICE, "drop: too big: %d", off); + ip = mtod(m, struct ip *); + ip->ip_len = htons(hdrlen + total); + ip->ip_off &= ~(IP_MF|IP_OFFMASK); + + if (hdrlen + total > IP_MAXPACKET) { + DPFPRINTF(LOG_NOTICE, "drop: too big: %d", total); ip->ip_len = 0; REASON_SET(reason, PFRES_SHORT); /* PF_DROP requires a valid mbuf *m0 in pf_test() */ @@ -434,31 +547,17 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, DPFPRINTF(LOG_NOTICE, "complete: %p(%d)", m, ntohs(ip->ip_len)); return (PF_PASS); - - bad_fragment: - REASON_SET(reason, PFRES_FRAG); - drop_fragment: - /* Oops - fail safe - drop packet */ - pool_put(&pf_frent_pl, frent); - pf_nfrents--; - /* PF_DROP requires a valid mbuf *m0 in pf_test(), will free later */ - return (PF_DROP); } int -pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, - struct pf_pdesc *pd) +pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, + u_short *reason, struct pf_pdesc *pd) { struct mbuf *m = *m0; - struct pf_frent *frent; - struct pf_fragment *frag = NULL; struct ip *h = mtod(m, struct ip *); - int mff = (ntohs(h->ip_off) & IP_MF); int hlen = h->ip_hl << 2; u_int16_t fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3; - u_int16_t max; - int ip_len; - int ip_off; + u_int16_t mff = (ntohs(h->ip_off) & IP_MF); /* Check for illegal packets */ if (hlen < (int)sizeof(struct ip)) @@ -484,48 +583,13 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, * no-df above, fine. Otherwise drop it. */ if (h->ip_off & htons(IP_DF)) { - DPFPRINTF(LOG_NOTICE, "IP_DF"); - goto bad; - } - - ip_len = ntohs(h->ip_len) - hlen; - ip_off = (ntohs(h->ip_off) & IP_OFFMASK) << 3; - - /* All fragments are 8 byte aligned */ - if (mff && (ip_len & 0x7)) { - DPFPRINTF(LOG_NOTICE, "mff and %d", ip_len); - goto bad; - } - - /* Respect maximum length */ - if (fragoff + ip_len > IP_MAXPACKET) { - DPFPRINTF(LOG_NOTICE, "max packet %d", fragoff + ip_len); - goto bad; - } - max = fragoff + ip_len; - - /* Fully buffer all of the fragments */ - frag = pf_find_fragment(h, &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; - - /* Get an entry for the fragment queue */ - frent = pool_get(&pf_frent_pl, PR_NOWAIT); - if (frent == NULL) { - REASON_SET(reason, PFRES_MEMORY); + DPFPRINTF(LOG_NOTICE, "bad fragment: IP_DF"); + REASON_SET(reason, PFRES_FRAG); return (PF_DROP); } - pf_nfrents++; - frent->fr_ip = h; - frent->fr_m = m; /* Returns PF_DROP or *m0 is NULL or completely reassembled mbuf */ - DPFPRINTF(LOG_NOTICE, - "reass frag %d @ %d-%d", h->ip_id, fragoff, max); - if (pf_reassemble(m0, &frag, frent, mff, reason) != PF_PASS) + if (pf_reassemble(m0, h, dir, reason) != PF_PASS) return (PF_DROP); m = *m0; if (m == NULL) @@ -548,17 +612,6 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, drop: REASON_SET(reason, PFRES_NORM); return (PF_DROP); - - bad: - DPFPRINTF(LOG_NOTICE, "dropping bad fragment"); - - /* Free associated fragments */ - if (frag != NULL) - pf_free_fragment(frag); - - REASON_SET(reason, PFRES_FRAG); - - return (PF_DROP); } #ifdef INET6 |