Subject: Re: AH + GRE works; ESP + GRE doesn't
To: None <itojun@iijlab.net>
From: Curt Sampson <cjs@cynic.net>
List: tech-net
Date: 04/21/2003 17:07:57
On Mon, 21 Apr 2003 itojun@iijlab.net wrote:

> 	any interesting values on netstat -sn?

Ah, an excellent thought! The ip "with data size < data length" one is
incrementing for every packet that comes back via the GRE. I wonder if
I screwed up the patch somehow? I've appended a diff; perhaps you could
look it over and see if I missed something.

cjs
-- 
Curt Sampson  <cjs@cynic.net>   +81 90 7737 2974   http://www.netbsd.org
    Don't you know, in this new Dark Age, we're all light.  --XTC


Index: ip_gre.c
===================================================================
RCS file: /u/netbsd/cvsroot/src/sys/netinet/ip_gre.c,v
retrieving revision 1.17
diff -u -r1.17 ip_gre.c
--- ip_gre.c	13 Nov 2001 00:32:37 -0000	1.17
+++ ip_gre.c	21 Apr 2003 08:07:16 -0000
@@ -150,7 +150,7 @@
 int
 gre_input2(struct mbuf *m ,int hlen,u_char proto)
 {
-	struct greip *gip = mtod(m, struct greip *);
+	struct greip *gip;
 	int s;
 	struct ifqueue *ifq;
 	struct gre_softc *sc;
@@ -161,12 +161,19 @@
 		return (0);
 	}

+	if (m->m_len < sizeof(*gip)) {
+		m = m_pullup(m, sizeof(*gip));
+		if (m == NULL)
+			return (ENOBUFS);
+	}
+	gip = mtod(m, struct greip *);
+
 	sc->sc_if.if_ipackets++;
 	sc->sc_if.if_ibytes += m->m_pkthdr.len;

 	switch (proto) {
 	case IPPROTO_GRE:
-		hlen += sizeof (struct gre_h);
+		hlen += sizeof(struct gre_h);

 		/* process GRE flags as packet can be of variable len */
 		flags = ntohs(gip->gi_flags);
@@ -180,7 +187,7 @@
 		if (flags & GRE_KP)
 			hlen += 4;
 		if (flags & GRE_SP)
-			hlen +=4;
+			hlen += 4;

 		switch (ntohs(gip->gi_ptype)) { /* ethertypes */
 		case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as */
@@ -209,8 +216,11 @@
 		return(0);
 	}

-	m->m_data += hlen;
-	m->m_len -= hlen;
+	if (hlen > m->m_pkthdr.len) {
+		m_free(m);
+		return (EINVAL);
+	}
+	m_adj(m, hlen);
 	m->m_pkthdr.len -= hlen;

 #if NBPFILTER > 0
@@ -223,7 +233,7 @@
 		m0.m_data = (char *)&af;

 		bpf_mtap(sc->sc_if.if_bpf, &m0);
-		}
+	}
 #endif /*NBPFILTER > 0*/

 	m->m_pkthdr.rcvif = &sc->sc_if;
@@ -256,8 +266,8 @@
         va_dcl
 #endif
 {
-	struct ip *ip = mtod(m, struct ip *);
-	struct mobip_h *mip = mtod(m, struct mobip_h *);
+	struct ip *ip;
+	struct mobip_h *mip;
 	struct ifqueue *ifq;
 	struct gre_softc *sc;
 	int hlen,s;
@@ -275,20 +285,37 @@
 		return;
 	}

+	if (m->m_len < sizeof(*mip)) {
+		m = m_pullup(m, sizeof(*mip));
+		if (m == NULL)
+			return;
+	}
+	ip = mtod(m, struct ip *);
+	mip = mtod(m, struct mobip_h *);
+
 	sc->sc_if.if_ipackets++;
 	sc->sc_if.if_ibytes += m->m_pkthdr.len;

-	if(ntohs(mip->mh.proto) & MOB_H_SBIT) {
+	if (ntohs(mip->mh.proto) & MOB_H_SBIT) {
 		osrc=1;
 		msiz=MOB_H_SIZ_L;
 		mip->mi.ip_src.s_addr=mip->mh.osrc;
 	} else {
 		msiz=MOB_H_SIZ_S;
 	}
+
+	if (m->m_len < msiz) {
+		m = m_pullup(m, msiz);
+		if (m == NULL)
+			return;
+		ip = mtod(m, struct ip *);
+		mip = mtod(m, struct mobip_h *);
+	}
+
 	mip->mi.ip_dst.s_addr=mip->mh.odst;
 	mip->mi.ip_p=(ntohs(mip->mh.proto) >> 8);

-	if (gre_in_cksum((u_short*)&mip->mh,msiz)!=0) {
+	if (gre_in_cksum((u_short*)&mip->mh, msiz)!=0) {
 		m_freem(m);
 		return;
 	}
@@ -313,7 +340,7 @@
 		m0.m_data = (char *)&af;

 		bpf_mtap(sc->sc_if.if_bpf, &m0);
-		}
+	}
 #endif /*NBPFILTER > 0*/

 	ifq = &ipintrq;