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 *)⁡
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 *)⁡
bpf_mtap(sc->sc_if.if_bpf, &m0);
- }
+ }
#endif /*NBPFILTER > 0*/
ifq = &ipintrq;