Source-Changes-HG archive

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

[src/trunk]: src/sys/netinet6 do not use m_pulldown() to parse intermediate e...



details:   https://anonhg.NetBSD.org/src/rev/0998982d1c74
branches:  trunk
changeset: 547168:0998982d1c74
user:      itojun <itojun%NetBSD.org@localhost>
date:      Wed May 14 14:34:14 2003 +0000

description:
do not use m_pulldown() to parse intermediate extension headers (like routing).
we don't want to drop packets due to extension header parsing.  KAME rev 1.59.
(performance may suck, but it is slowpath anyways)

diffstat:

 sys/netinet6/ip6_input.c |  130 +++++++++++++++++++++++++++++++++++-----------
 1 files changed, 99 insertions(+), 31 deletions(-)

diffs (213 lines):

diff -r 2db338ace9b9 -r 0998982d1c74 sys/netinet6/ip6_input.c
--- a/sys/netinet6/ip6_input.c  Wed May 14 14:31:48 2003 +0000
+++ b/sys/netinet6/ip6_input.c  Wed May 14 14:34:14 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ip6_input.c,v 1.61 2003/05/14 06:47:41 itojun Exp $    */
+/*     $NetBSD: ip6_input.c,v 1.62 2003/05/14 14:34:14 itojun Exp $    */
 /*     $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $     */
 
 /*
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.61 2003/05/14 06:47:41 itojun Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.62 2003/05/14 14:34:14 itojun Exp $");
 
 #include "opt_inet.h"
 #include "opt_ipsec.h"
@@ -149,6 +149,7 @@
 static void ip6_init2 __P((void *));
 
 static int ip6_hopopts_input __P((u_int32_t *, u_int32_t *, struct mbuf **, int *));
+static struct mbuf *ip6_pullexthdr __P((struct mbuf *, size_t, int));
 
 /*
  * IP6 initialization: fill in IP6 protocol switch table.
@@ -1075,17 +1076,18 @@
                if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
                        struct ip6_hbh *hbh;
                        int hbhlen;
+                       struct mbuf *ext;
 
-                       IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
-                               sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));
-                       if (hbh == NULL) {
+                       ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr),
+                           ip6->ip6_nxt);
+                       if (ext == NULL) {
                                ip6stat.ip6s_tooshort++;
                                return;
                        }
+                       hbh = mtod(ext, struct ip6_hbh *);
                        hbhlen = (hbh->ip6h_len + 1) << 3;
-                       IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
-                               sizeof(struct ip6_hdr), hbhlen);
-                       if (hbh == NULL) {
+                       if (hbhlen != ext->m_len) {
+                               m_freem(ext);
                                ip6stat.ip6s_tooshort++;
                                return;
                        }
@@ -1100,6 +1102,7 @@
                                              IPV6_HOPOPTS, IPPROTO_IPV6);
                        if (*mp)
                                mp = &(*mp)->m_next;
+                       m_freem(ext);
                }
        }
 
@@ -1116,28 +1119,43 @@
                 * the chain of ancillary data.
                 */
                while (1) {     /* is explicit loop prevention necessary? */
-                       struct ip6_ext *ip6e;
+                       struct ip6_ext *ip6e = NULL;
                        int elen;
+                       struct mbuf *ext = NULL;
 
-                       IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off,
-                               sizeof(struct ip6_ext));
-                       if (ip6e == NULL) {
+                       /*
+                        * if it is not an extension header, don't try to
+                        * pull it from the chain.
+                        */
+                       switch (nxt) {
+                       case IPPROTO_DSTOPTS:
+                       case IPPROTO_ROUTING:
+                       case IPPROTO_HOPOPTS:
+                       case IPPROTO_AH: /* is it possible? */
+                               break;
+                       default:
+                               goto loopend;
+                       }
+
+                       ext = ip6_pullexthdr(m, off, nxt);
+                       if (ext == NULL) {
                                ip6stat.ip6s_tooshort++;
                                return;
                        }
+                       ip6e = mtod(ext, struct ip6_ext *);
                        if (nxt == IPPROTO_AH)
                                elen = (ip6e->ip6e_len + 2) << 2;
                        else
                                elen = (ip6e->ip6e_len + 1) << 3;
-                       IP6_EXTHDR_GET(ip6e, struct ip6_ext *, m, off, elen);
-                       if (ip6e == NULL) {
+                       if (elen != ext->m_len) {
+                               m_freem(ext);
                                ip6stat.ip6s_tooshort++;
                                return;
                        }
                        KASSERT(IP6_HDR_ALIGNED_P(ip6e));
 
                        switch (nxt) {
-                       case IPPROTO_DSTOPTS:
+                       case IPPROTO_DSTOPTS:
                                if (!in6p->in6p_flags & IN6P_DSTOPTS)
                                        break;
 
@@ -1167,36 +1185,86 @@
                                        mp = &(*mp)->m_next;
                                break;
 
-                       case IPPROTO_UDP:
-                       case IPPROTO_TCP:
-                       case IPPROTO_ICMPV6:
-                       default:
-                               /*
-                                * stop search if we encounter an upper
-                                * layer protocol headers.
-                                */
-                               goto loopend;
-
                        case IPPROTO_HOPOPTS:
                        case IPPROTO_AH: /* is it possible? */
                                break;
+
+                       default:
+                               /*
+                                * other cases have been filtered in the above.
+                                * none will visit this case.  here we supply
+                                * the code just in case (nxt overwritten or
+                                * other cases).
+                                */
+                               m_freem(ext);
+                               goto loopend;
+
                        }
 
                        /* proceed with the next header. */
                        off += elen;
                        nxt = ip6e->ip6e_nxt;
+                       ip6e = NULL;
+                       m_freem(ext);
+                       ext = NULL;
                }
          loopend:
-               ;
+               ;
        }
-       if ((in6p->in6p_flags & IN6P_HOPOPTS) && privileged) {
-               /* to be done */
+}
+
+/*
+ * pull single extension header from mbuf chain.  returns single mbuf that
+ * contains the result, or NULL on error.
+ */
+static struct mbuf *
+ip6_pullexthdr(m, off, nxt)
+       struct mbuf *m;
+       size_t off;
+       int nxt;
+{
+       struct ip6_ext ip6e;
+       size_t elen;
+       struct mbuf *n;
+
+#ifdef DIAGNOSTIC
+       switch (nxt) {
+       case IPPROTO_DSTOPTS:
+       case IPPROTO_ROUTING:
+       case IPPROTO_HOPOPTS:
+       case IPPROTO_AH: /* is it possible? */
+               break;
+       default:
+               printf("ip6_pullexthdr: invalid nxt=%d\n", nxt);
        }
-       if ((in6p->in6p_flags & IN6P_DSTOPTS) && privileged) {
-               /* to be done */
+#endif
+
+       m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
+       if (nxt == IPPROTO_AH)
+               elen = (ip6e.ip6e_len + 2) << 2;
+       else
+               elen = (ip6e.ip6e_len + 1) << 3;
+
+       MGET(n, M_DONTWAIT, MT_DATA);
+       if (n && elen >= MLEN) {
+               MCLGET(n, M_DONTWAIT);
+               if ((n->m_flags & M_EXT) == 0) {
+                       m_free(n);
+                       n = NULL;
+               }
        }
-       /* IN6P_RTHDR - to be done */
+       if (!n)
+               return NULL;
 
+       n->m_len = 0;
+       if (elen >= M_TRAILINGSPACE(n)) {
+               m_free(n);
+               return NULL;
+       }
+
+       m_copydata(m, off, elen, mtod(n, caddr_t));
+       n->m_len = elen;
+       return n;
 }
 
 /*



Home | Main Index | Thread Index | Old Index