Hi,

In IPIP input rename the variable ipo to ip as it is used for inner
and outer header.  Reset values depending on the the mbuf when the
mbuf is adjusted.  Check the length of the inner IP header with the
correct size in case of IPv6.  Check the IPv4 header size including
IP options.  For the IPIP statistics the inner header length must
be subtracted from the packet size as the outer header has already
been stripped off.

ok?

bluhm

Index: netinet/ip_ipip.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipip.c,v
retrieving revision 1.78
diff -u -p -r1.78 ip_ipip.c
--- netinet/ip_ipip.c   18 May 2017 10:56:45 -0000      1.78
+++ netinet/ip_ipip.c   19 May 2017 13:15:37 -0000
@@ -120,11 +120,10 @@ ipip_input_gif(struct mbuf **mp, int *of
     struct ifnet *gifp)
 {
        struct mbuf *m = *mp;
-       int iphlen = *offp;
        struct sockaddr_in *sin;
        struct ifnet *ifp;
        struct niqueue *ifq = NULL;
-       struct ip *ipo;
+       struct ip *ip;
 #ifdef INET6
        struct sockaddr_in6 *sin6;
        struct ip6_hdr *ip6;
@@ -166,8 +165,8 @@ ipip_input_gif(struct mbuf **mp, int *of
        /* Keep outer ecn field. */
        switch (v >> 4) {
        case 4:
-               ipo = mtod(m, struct ip *);
-               otos = ipo->ip_tos;
+               ip = mtod(m, struct ip *);
+               otos = ip->ip_tos;
                break;
 #ifdef INET6
        case 6:
@@ -180,14 +179,13 @@ ipip_input_gif(struct mbuf **mp, int *of
        }
 
        /* Remove outer IP header */
-       m_adj(m, iphlen);
-
-       /* Sanity check */
-       if (m->m_pkthdr.len < sizeof(struct ip)) {
-               ipipstat_inc(ipips_hdrops);
-               m_freem(m);
-               return IPPROTO_DONE;
-       }
+       KASSERT(*offp > 0);
+       m_adj(m, *offp);
+       *offp = 0;
+       ip = NULL;
+#ifdef INET6
+       ip6 = NULL;
+#endif
 
        switch (proto) {
        case IPPROTO_IPV4:
@@ -205,6 +203,13 @@ ipip_input_gif(struct mbuf **mp, int *of
                return IPPROTO_DONE;
        }
 
+       /* Sanity check */
+       if (m->m_pkthdr.len < hlen) {
+               ipipstat_inc(ipips_hdrops);
+               m_freem(m);
+               return IPPROTO_DONE;
+       }
+
        /*
         * Bring the inner header into the first mbuf, if not there already.
         */
@@ -225,31 +230,30 @@ ipip_input_gif(struct mbuf **mp, int *of
        /* Some sanity checks in the inner IP header */
        switch (proto) {
        case IPPROTO_IPV4:
-               ipo = mtod(m, struct ip *);
-#ifdef INET6
-               ip6 = NULL;
-#endif
-               itos = ipo->ip_tos;
+               ip = mtod(m, struct ip *);
+               hlen = ip->ip_hl << 2;
+               if (m->m_pkthdr.len < hlen) {
+                       ipipstat_inc(ipips_hdrops);
+                       m_freem(m);
+                       return IPPROTO_DONE;
+               }
+               itos = ip->ip_tos;
                mode = m->m_flags & (M_AUTH|M_CONF) ?
                    ECN_ALLOWED_IPSEC : ECN_ALLOWED;
-               if (!ip_ecn_egress(mode, &otos, &ipo->ip_tos)) {
+               if (!ip_ecn_egress(mode, &otos, &ip->ip_tos)) {
                        DPRINTF(("%s: ip_ecn_egress() failed\n", __func__));
                        ipipstat_inc(ipips_pdrops);
                        m_freem(m);
                        return IPPROTO_DONE;
                }
                /* re-calculate the checksum if ip_tos was changed */
-               if (itos != ipo->ip_tos) {
-                       hlen = ipo->ip_hl << 2;
-                       if (m->m_pkthdr.len >= hlen) {
-                               ipo->ip_sum = 0;
-                               ipo->ip_sum = in_cksum(m, hlen);
-                       }
+               if (itos != ip->ip_tos) {
+                       ip->ip_sum = 0;
+                       ip->ip_sum = in_cksum(m, hlen);
                }
                break;
 #ifdef INET6
        case IPPROTO_IPV6:
-               ipo = NULL;
                ip6 = mtod(m, struct ip6_hdr *);
                itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
                if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos)) {
@@ -262,11 +266,6 @@ ipip_input_gif(struct mbuf **mp, int *of
                ip6->ip6_flow |= htonl((u_int32_t) itos << 20);
                break;
 #endif
-       default:
-               ipo = NULL;
-#ifdef INET6
-               ip6 = NULL;
-#endif
        }
 
        /* Check for local address spoofing. */
@@ -280,11 +279,11 @@ ipip_input_gif(struct mbuf **mp, int *of
 
                memset(&ss, 0, sizeof(ss));
 
-               if (ipo) {
+               if (ip) {
                        sin = (struct sockaddr_in *)&ss;
                        sin->sin_family = AF_INET;
                        sin->sin_len = sizeof(*sin);
-                       sin->sin_addr = ipo->ip_src;
+                       sin->sin_addr = ip->ip_src;
 #ifdef INET6
                } else if (ip6) {
                        sin6 = (struct sockaddr_in6 *)&ss;
@@ -306,7 +305,7 @@ ipip_input_gif(struct mbuf **mp, int *of
        }
 
        /* Statistics */
-       ipipstat_add(ipips_ibytes, m->m_pkthdr.len - iphlen);
+       ipipstat_add(ipips_ibytes, m->m_pkthdr.len - hlen);
 
        /*
         * Interface pointer stays the same; if no IPsec processing has

Reply via email to