Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/netinet ip_reass_packet: finish abstraction; some clean-up.



details:   https://anonhg.NetBSD.org/src/rev/f08b87378c6e
branches:  trunk
changeset: 758447:f08b87378c6e
user:      rmind <rmind%NetBSD.org@localhost>
date:      Fri Nov 05 00:21:51 2010 +0000

description:
ip_reass_packet: finish abstraction; some clean-up.
Discussed some time ago with matt@.

diffstat:

 sys/netinet/ip_input.c |   53 +++-----------------
 sys/netinet/ip_reass.c |  128 ++++++++++++++++++++++++++++++++----------------
 sys/netinet/ip_var.h   |    4 +-
 3 files changed, 96 insertions(+), 89 deletions(-)

diffs (truncated from 337 to 300 lines):

diff -r 27c8d787a3e1 -r f08b87378c6e sys/netinet/ip_input.c
--- a/sys/netinet/ip_input.c    Thu Nov 04 23:38:18 2010 +0000
+++ b/sys/netinet/ip_input.c    Fri Nov 05 00:21:51 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip_input.c,v 1.289 2010/07/19 14:09:45 rmind Exp $     */
+/*     $NetBSD: ip_input.c,v 1.290 2010/11/05 00:21:51 rmind Exp $     */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -91,7 +91,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.289 2010/07/19 14:09:45 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.290 2010/11/05 00:21:51 rmind Exp $");
 
 #include "opt_inet.h"
 #include "opt_compat_netbsd.h"
@@ -806,58 +806,21 @@
         * If offset or IP_MF are set, must reassemble.
         */
        if (ip->ip_off & ~htons(IP_DF|IP_RF)) {
-               struct mbuf *m_final;
-               u_int off, flen;
-               bool mff;
-
-               /*
-                * Prevent TCP blind data attacks by not allowing non-initial
-                * fragments to start at less than 68 bytes (minimal fragment
-                * size) and making sure the first fragment is at least 68
-                * bytes.
-                */
-               off = (ntohs(ip->ip_off) & IP_OFFMASK) << 3;
-               if ((off > 0 ? off + hlen : len) < IP_MINFRAGSIZE - 1) {
-                       IP_STATINC(IP_STAT_BADFRAGS);
-                       goto bad;
-               }
-
-               /* Fragment length and MF flag. */
-               flen = ntohs(ip->ip_len) - hlen;
-               mff = (ip->ip_off & htons(IP_MF)) != 0;
-               if (mff) {
-                       /*
-                        * Make sure that fragments have a data length
-                        * which is non-zero and multiple of 8 bytes.
-                        */
-                       if (flen == 0 || (flen & 0x7) != 0) {
-                               IP_STATINC(IP_STAT_BADFRAGS);
-                               goto bad;
-                       }
-               }
-
-               /*
-                * Adjust total IP length to not reflect header and convert
-                * offset of this to bytes.  XXX: clobbers struct ip.
-                */
-               ip->ip_len = htons(flen);
-               ip->ip_off = htons(off);
-
                /*
                 * Pass to IP reassembly mechanism.
                 */
-               if (ip_reass_packet(m, ip, mff, &m_final) != 0) {
+               if (ip_reass_packet(&m, ip) != 0) {
                        /* Failed; invalid fragment(s) or packet. */
                        goto bad;
                }
-               if (m_final == NULL) {
+               if (m == NULL) {
                        /* More fragments should come; silently return. */
                        return;
                }
-               /* Reassembly is done, we have the final packet. */
-               m = m_final;
-
-               /* Updated local variable(s). */
+               /*
+                * Reassembly is done, we have the final packet.
+                * Updated cached data in local variable(s).
+                */
                ip = mtod(m, struct ip *);
                hlen = ip->ip_hl << 2;
        }
diff -r 27c8d787a3e1 -r f08b87378c6e sys/netinet/ip_reass.c
--- a/sys/netinet/ip_reass.c    Thu Nov 04 23:38:18 2010 +0000
+++ b/sys/netinet/ip_reass.c    Fri Nov 05 00:21:51 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip_reass.c,v 1.6 2010/10/07 03:15:49 yamt Exp $        */
+/*     $NetBSD: ip_reass.c,v 1.7 2010/11/05 00:21:51 rmind Exp $       */
 
 /*
  * Copyright (c) 1982, 1986, 1988, 1993
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip_reass.c,v 1.6 2010/10/07 03:15:49 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip_reass.c,v 1.7 2010/11/05 00:21:51 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -86,9 +86,11 @@
        bool                    ipqe_mff;
 } ipfr_qent_t;
 
+TAILQ_HEAD(ipfr_qent_head, ipfr_qent);
+
 typedef struct ipfr_queue {
        LIST_ENTRY(ipfr_queue)  ipq_q;          /* to other reass headers */
-       TAILQ_HEAD(, ipfr_qent) ipq_fragq;      /* queue of fragment entries */
+       struct ipfr_qent_head   ipq_fragq;      /* queue of fragment entries */
        uint8_t                 ipq_ttl;        /* time for reass q to live */
        uint8_t                 ipq_p;          /* protocol of this fragment */
        uint16_t                ipq_id;         /* sequence id for reassembly */
@@ -221,10 +223,10 @@
 struct mbuf *
 ip_reass(ipfr_qent_t *ipqe, ipfr_queue_t *fp, const u_int hash)
 {
-       const int hlen = ipqe->ipqe_ip->ip_hl << 2;
+       struct ip *ip = ipqe->ipqe_ip, *qip;
+       const int hlen = ip->ip_hl << 2;
        struct mbuf *m = ipqe->ipqe_m, *t;
        ipfr_qent_t *nq, *p, *q;
-       struct ip *ip;
        int i, next;
 
        KASSERT(mutex_owned(&ipfr_lock));
@@ -270,15 +272,15 @@
                if (fp == NULL) {
                        goto dropfrag;
                }
-               LIST_INSERT_HEAD(&ip_frags[hash], fp, ipq_q);
+               TAILQ_INIT(&fp->ipq_fragq);
                fp->ipq_nfrags = 1;
                fp->ipq_ttl = IPFRAGTTL;
-               fp->ipq_p = ipqe->ipqe_ip->ip_p;
-               fp->ipq_id = ipqe->ipqe_ip->ip_id;
-               fp->ipq_tos = ipqe->ipqe_ip->ip_tos;
-               TAILQ_INIT(&fp->ipq_fragq);
-               fp->ipq_src = ipqe->ipqe_ip->ip_src;
-               fp->ipq_dst = ipqe->ipqe_ip->ip_dst;
+               fp->ipq_p = ip->ip_p;
+               fp->ipq_id = ip->ip_id;
+               fp->ipq_tos = ip->ip_tos;
+               fp->ipq_src = ip->ip_src;
+               fp->ipq_dst = ip->ip_dst;
+               LIST_INSERT_HEAD(&ip_frags[hash], fp, ipq_q);
                p = NULL;
                goto insert;
        } else {
@@ -288,10 +290,15 @@
        /*
         * Find a segment which begins after this one does.
         */
-       for (p = NULL, q = TAILQ_FIRST(&fp->ipq_fragq); q != NULL;
-           p = q, q = TAILQ_NEXT(q, ipqe_q))
-               if (ntohs(q->ipqe_ip->ip_off) > ntohs(ipqe->ipqe_ip->ip_off))
+       TAILQ_FOREACH(q, &fp->ipq_fragq, ipqe_q) {
+               if (ntohs(q->ipqe_ip->ip_off) > ntohs(ip->ip_off))
                        break;
+       }
+       if (q != NULL) {
+               p = TAILQ_PREV(q, ipfr_qent_head, ipqe_q);
+       } else {
+               p = TAILQ_LAST(&fp->ipq_fragq, ipfr_qent_head);
+       }
 
        /*
         * If there is a preceding segment, it may provide some of our
@@ -300,16 +307,14 @@
         */
        if (p != NULL) {
                i = ntohs(p->ipqe_ip->ip_off) + ntohs(p->ipqe_ip->ip_len) -
-                   ntohs(ipqe->ipqe_ip->ip_off);
+                   ntohs(ip->ip_off);
                if (i > 0) {
-                       if (i >= ntohs(ipqe->ipqe_ip->ip_len)) {
+                       if (i >= ntohs(ip->ip_len)) {
                                goto dropfrag;
                        }
                        m_adj(ipqe->ipqe_m, i);
-                       ipqe->ipqe_ip->ip_off =
-                           htons(ntohs(ipqe->ipqe_ip->ip_off) + i);
-                       ipqe->ipqe_ip->ip_len =
-                           htons(ntohs(ipqe->ipqe_ip->ip_len) - i);
+                       ip->ip_off = htons(ntohs(ip->ip_off) + i);
+                       ip->ip_len = htons(ntohs(ip->ip_len) - i);
                }
        }
 
@@ -317,16 +322,18 @@
         * While we overlap succeeding segments trim them or, if they are
         * completely covered, dequeue them.
         */
-       for (; q != NULL &&
-           ntohs(ipqe->ipqe_ip->ip_off) + ntohs(ipqe->ipqe_ip->ip_len) >
-           ntohs(q->ipqe_ip->ip_off); q = nq) {
-               i = (ntohs(ipqe->ipqe_ip->ip_off) +
-                   ntohs(ipqe->ipqe_ip->ip_len)) - ntohs(q->ipqe_ip->ip_off);
-               if (i < ntohs(q->ipqe_ip->ip_len)) {
-                       q->ipqe_ip->ip_len =
-                           htons(ntohs(q->ipqe_ip->ip_len) - i);
-                       q->ipqe_ip->ip_off =
-                           htons(ntohs(q->ipqe_ip->ip_off) + i);
+       while (q != NULL) {
+               size_t end;
+
+               qip = q->ipqe_ip;
+               end = ntohs(ip->ip_off) + ntohs(ip->ip_len);
+               if (end <= ntohs(qip->ip_off)) {
+                       break;
+               }
+               i = end - ntohs(qip->ip_off);
+               if (i < ntohs(qip->ip_len)) {
+                       qip->ip_len = htons(ntohs(qip->ip_len) - i);
+                       qip->ip_off = htons(ntohs(qip->ip_off) + i);
                        m_adj(q->ipqe_m, i);
                        break;
                }
@@ -336,6 +343,7 @@
                pool_cache_put(ipfren_cache, q);
                fp->ipq_nfrags--;
                ip_nfrags--;
+               q = nq;
        }
 
 insert:
@@ -348,18 +356,20 @@
                TAILQ_INSERT_AFTER(&fp->ipq_fragq, p, ipqe, ipqe_q);
        }
        next = 0;
-       for (p = NULL, q = TAILQ_FIRST(&fp->ipq_fragq); q != NULL;
-           p = q, q = TAILQ_NEXT(q, ipqe_q)) {
-               if (ntohs(q->ipqe_ip->ip_off) != next) {
+       TAILQ_FOREACH(q, &fp->ipq_fragq, ipqe_q) {
+               qip = q->ipqe_ip;
+               if (ntohs(qip->ip_off) != next) {
                        mutex_exit(&ipfr_lock);
                        return NULL;
                }
-               next += ntohs(q->ipqe_ip->ip_len);
+               next += ntohs(qip->ip_len);
        }
+       p = TAILQ_LAST(&fp->ipq_fragq, ipfr_qent_head);
        if (p->ipqe_mff) {
                mutex_exit(&ipfr_lock);
                return NULL;
        }
+
        /*
         * Reassembly is complete.  Check for a bogus message size.
         */
@@ -602,15 +612,49 @@
  * => Passed fragment should have IP_MF flag and/or offset set.
  * => Fragment should not have other than IP_MF flags set.
  *
- * => Returns 0 on success or error otherwise.  When reassembly is complete,
- *    m_final representing a constructed final packet is set.
+ * => Returns 0 on success or error otherwise.
+ * => On complete, m0 represents a constructed final packet.
  */
 int
-ip_reass_packet(struct mbuf *m, struct ip *ip, bool mff, struct mbuf **m_final)
+ip_reass_packet(struct mbuf **m0, struct ip *ip)
 {
+       const int hlen = ip->ip_hl << 2;
+       const int len = ntohs(ip->ip_len);
+       struct mbuf *m = *m0;
        ipfr_queue_t *fp;
        ipfr_qent_t *ipqe;
-       u_int hash;
+       u_int hash, off, flen;
+       bool mff;
+
+       /*
+        * Prevent TCP blind data attacks by not allowing non-initial
+        * fragments to start at less than 68 bytes (minimal fragment
+        * size) and making sure the first fragment is at least 68
+        * bytes.
+        */
+       off = (ntohs(ip->ip_off) & IP_OFFMASK) << 3;
+       if ((off > 0 ? off + hlen : len) < IP_MINFRAGSIZE - 1) {
+               IP_STATINC(IP_STAT_BADFRAGS);
+               return EINVAL;
+       }
+
+       /*
+        * Fragment length and MF flag.  Make sure that fragments have
+        * a data length which is non-zero and multiple of 8 bytes.
+        */
+       flen = ntohs(ip->ip_len) - hlen;
+       mff = (ip->ip_off & htons(IP_MF)) != 0;
+       if (mff && (flen == 0 || (flen & 0x7) != 0)) {
+               IP_STATINC(IP_STAT_BADFRAGS);
+               return EINVAL;
+       }
+
+       /*
+        * Adjust total IP length to not reflect header and convert
+        * offset of this to bytes.  XXX: clobbers struct ip.



Home | Main Index | Thread Index | Old Index