devip: fix block list handling for icmp/icmp6, use proper MinAdvise for icmp6

This commit is contained in:
cinap_lenrek 2019-03-03 09:01:23 +01:00
parent a2c0e55e68
commit a859f05837
2 changed files with 32 additions and 54 deletions

View file

@ -44,11 +44,6 @@ enum { /* Packet Types */
Maxtype = 18, Maxtype = 18,
}; };
enum
{
MinAdvise = 24, /* minimum needed for us to advise another protocol */
};
char *icmpnames[Maxtype+1] = char *icmpnames[Maxtype+1] =
{ {
[EchoReply] "EchoReply", [EchoReply] "EchoReply",
@ -70,6 +65,8 @@ enum {
IP_ICMPPROTO = 1, IP_ICMPPROTO = 1,
ICMP_IPSIZE = 20, ICMP_IPSIZE = 20,
ICMP_HDRSIZE = 8, ICMP_HDRSIZE = 8,
MinAdvise = ICMP_IPSIZE+4, /* minimum needed for us to advise another protocol */
}; };
enum enum
@ -169,8 +166,7 @@ icmpkick(void *x, Block *bp)
if(bp == nil) if(bp == nil)
return; return;
if(BLEN(bp) < ICMP_IPSIZE + ICMP_HDRSIZE){
if(blocklen(bp) < ICMP_IPSIZE + ICMP_HDRSIZE){
freeblist(bp); freeblist(bp);
return; return;
} }
@ -350,7 +346,7 @@ static char *unreachcode[] =
static void static void
icmpiput(Proto *icmp, Ipifc*, Block *bp) icmpiput(Proto *icmp, Ipifc*, Block *bp)
{ {
int n, iplen; int n;
Icmp *p; Icmp *p;
Block *r; Block *r;
Proto *pr; Proto *pr;
@ -359,42 +355,31 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
Icmppriv *ipriv; Icmppriv *ipriv;
ipriv = icmp->priv; ipriv = icmp->priv;
ipriv->stats[InMsgs]++; ipriv->stats[InMsgs]++;
p = (Icmp *)bp->rp; bp = concatblock(bp);
netlog(icmp->f, Logicmp, "icmpiput %s (%d) %d\n", n = BLEN(bp);
(p->type < nelem(icmpnames)? icmpnames[p->type]: ""),
p->type, p->code);
n = blocklen(bp);
if(n < ICMP_IPSIZE+ICMP_HDRSIZE){ if(n < ICMP_IPSIZE+ICMP_HDRSIZE){
ipriv->stats[InErrors]++; ipriv->stats[InErrors]++;
ipriv->stats[HlenErrs]++; ipriv->stats[HlenErrs]++;
netlog(icmp->f, Logicmp, "icmp hlen %d\n", n); netlog(icmp->f, Logicmp, "icmp hlen %d\n", n);
goto raise; goto raise;
} }
iplen = nhgets(p->length); if(ptclcsum(bp, ICMP_IPSIZE, n - ICMP_IPSIZE)){
if(iplen > n){
ipriv->stats[LenErrs]++;
ipriv->stats[InErrors]++;
netlog(icmp->f, Logicmp, "icmp length %d\n", iplen);
goto raise;
}
if(ptclcsum(bp, ICMP_IPSIZE, iplen - ICMP_IPSIZE)){
ipriv->stats[InErrors]++; ipriv->stats[InErrors]++;
ipriv->stats[CsumErrs]++; ipriv->stats[CsumErrs]++;
netlog(icmp->f, Logicmp, "icmp checksum error\n"); netlog(icmp->f, Logicmp, "icmp checksum error\n");
goto raise; goto raise;
} }
p = (Icmp *)bp->rp;
netlog(icmp->f, Logicmp, "icmpiput %s (%d) %d\n",
(p->type < nelem(icmpnames)? icmpnames[p->type]: ""),
p->type, p->code);
if(p->type <= Maxtype) if(p->type <= Maxtype)
ipriv->in[p->type]++; ipriv->in[p->type]++;
switch(p->type) { switch(p->type) {
case EchoRequest: case EchoRequest:
if(iplen < n)
bp = trimblock(bp, 0, iplen);
if(bp->next != nil)
bp = concatblock(bp);
r = mkechoreply(bp, icmp->f); r = mkechoreply(bp, icmp->f);
if(r == nil) if(r == nil)
goto raise; goto raise;
@ -410,7 +395,7 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
msg = unreachcode[p->code]; msg = unreachcode[p->code];
bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE; bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
if(blocklen(bp) < MinAdvise){ if(BLEN(bp) < MinAdvise){
ipriv->stats[LenErrs]++; ipriv->stats[LenErrs]++;
goto raise; goto raise;
} }
@ -420,7 +405,6 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
(*pr->advise)(pr, bp, msg); (*pr->advise)(pr, bp, msg);
return; return;
} }
bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE; bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE;
goticmpkt(icmp, bp); goticmpkt(icmp, bp);
break; break;
@ -429,7 +413,7 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
snprint(m2, sizeof m2, "ttl exceeded at %V", p->src); snprint(m2, sizeof m2, "ttl exceeded at %V", p->src);
bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE; bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
if(blocklen(bp) < MinAdvise){ if(BLEN(bp) < MinAdvise){
ipriv->stats[LenErrs]++; ipriv->stats[LenErrs]++;
goto raise; goto raise;
} }
@ -441,7 +425,6 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
} }
bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE; bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE;
} }
goticmpkt(icmp, bp); goticmpkt(icmp, bp);
break; break;
default: default:

View file

@ -67,6 +67,10 @@ enum {
Maxtype6 = 137, Maxtype6 = 137,
}; };
enum {
MinAdvise = IP6HDR+4, /* minimum needed for us to advise another protocol */
};
/* on-the-wire packet formats */ /* on-the-wire packet formats */
typedef struct IPICMP IPICMP; typedef struct IPICMP IPICMP;
typedef struct Ndpkt Ndpkt; typedef struct Ndpkt Ndpkt;
@ -189,13 +193,14 @@ static void
set_cksum(Block *bp) set_cksum(Block *bp)
{ {
IPICMP *p = (IPICMP *)(bp->rp); IPICMP *p = (IPICMP *)(bp->rp);
int n = blocklen(bp);
hnputl(p->vcf, 0); /* borrow IP header as pseudoheader */ hnputl(p->vcf, 0); /* borrow IP header as pseudoheader */
hnputs(p->ploadlen, blocklen(bp) - IP6HDR); hnputs(p->ploadlen, n - IP6HDR);
p->proto = 0; p->proto = 0;
p->ttl = ICMPv6; /* ttl gets set later */ p->ttl = ICMPv6; /* ttl gets set later */
hnputs(p->cksum, 0); hnputs(p->cksum, 0);
hnputs(p->cksum, ptclcsum(bp, 0, blocklen(bp))); hnputs(p->cksum, ptclcsum(bp, 0, n));
p->proto = ICMPv6; p->proto = ICMPv6;
} }
@ -259,7 +264,7 @@ icmpkick6(void *x, Block *bp)
bp = padblock(bp, IP6HDR); bp = padblock(bp, IP6HDR);
} }
if(blocklen(bp) < IPICMPSZ){ if(BLEN(bp) < IPICMPSZ){
freeblist(bp); freeblist(bp);
return; return;
} }
@ -524,26 +529,17 @@ icmppkttoobig6(Fs *f, Ipifc *ifc, Block *bp)
* RFC 2461, pages 39-40, pages 57-58. * RFC 2461, pages 39-40, pages 57-58.
*/ */
static int static int
valid(Proto *icmp, Ipifc *ifc, Block *bp, Icmppriv6 *ipriv) valid(Proto *icmp, Ipifc *, Block *bp, Icmppriv6 *ipriv)
{ {
int sz, osz, unsp, n, ttl, iplen; int sz, osz, unsp, ttl;
int pktsz = BLEN(bp); int pktsz = BLEN(bp);
uchar *packet = bp->rp; uchar *packet = bp->rp;
IPICMP *p = (IPICMP *) packet; IPICMP *p = (IPICMP *) packet;
Ndpkt *np; Ndpkt *np;
USED(ifc); if(pktsz < IPICMPSZ) {
n = blocklen(bp);
if(n < IPICMPSZ) {
ipriv->stats[HlenErrs6]++; ipriv->stats[HlenErrs6]++;
netlog(icmp->f, Logicmp, "icmp hlen %d\n", n); netlog(icmp->f, Logicmp, "icmp hlen %d\n", pktsz);
goto err;
}
iplen = nhgets(p->ploadlen);
if(iplen > n - IP6HDR) {
ipriv->stats[LenErrs6]++;
netlog(icmp->f, Logicmp, "icmp length %d\n", iplen);
goto err; goto err;
} }
@ -557,7 +553,7 @@ valid(Proto *icmp, Ipifc *ifc, Block *bp, Icmppriv6 *ipriv)
ttl = p->ttl; ttl = p->ttl;
p->ttl = p->proto; p->ttl = p->proto;
p->proto = 0; p->proto = 0;
if(ptclcsum(bp, 0, iplen + IP6HDR)) { if(ptclcsum(bp, 0, pktsz)) {
ipriv->stats[CsumErrs6]++; ipriv->stats[CsumErrs6]++;
netlog(icmp->f, Logicmp, "icmp checksum error\n"); netlog(icmp->f, Logicmp, "icmp checksum error\n");
goto err; goto err;
@ -678,15 +674,17 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp)
{ {
char *msg, m2[128]; char *msg, m2[128];
uchar pktflags; uchar pktflags;
uchar *packet = bp->rp;
uchar ia[IPaddrlen]; uchar ia[IPaddrlen];
Block *r; Block *r;
IPICMP *p = (IPICMP *)packet; IPICMP *p;
Icmppriv6 *ipriv = icmp->priv; Icmppriv6 *ipriv = icmp->priv;
Iplifc *lifc; Iplifc *lifc;
Ndpkt* np; Ndpkt* np;
Proto *pr; Proto *pr;
bp = concatblock(bp);
p = (IPICMP*)bp->rp;
if(!valid(icmp, ifc, bp, ipriv) || p->type > Maxtype6) if(!valid(icmp, ifc, bp, ipriv) || p->type > Maxtype6)
goto raise; goto raise;
@ -694,8 +692,6 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp)
switch(p->type) { switch(p->type) {
case EchoRequestV6: case EchoRequestV6:
if(bp->next != nil)
bp = concatblock(bp);
r = mkechoreply6(bp, ifc); r = mkechoreply6(bp, ifc);
if(r == nil) if(r == nil)
goto raise; goto raise;
@ -710,7 +706,7 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp)
msg = unreachcode[p->code]; msg = unreachcode[p->code];
bp->rp += IPICMPSZ; bp->rp += IPICMPSZ;
if(blocklen(bp) < 8){ if(BLEN(bp) < MinAdvise){
ipriv->stats[LenErrs6]++; ipriv->stats[LenErrs6]++;
goto raise; goto raise;
} }
@ -720,7 +716,6 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp)
(*pr->advise)(pr, bp, msg); (*pr->advise)(pr, bp, msg);
return; return;
} }
bp->rp -= IPICMPSZ; bp->rp -= IPICMPSZ;
goticmpkt6(icmp, bp, 0); goticmpkt6(icmp, bp, 0);
break; break;
@ -730,7 +725,7 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp)
sprint(m2, "ttl exceeded at %I", p->src); sprint(m2, "ttl exceeded at %I", p->src);
bp->rp += IPICMPSZ; bp->rp += IPICMPSZ;
if(blocklen(bp) < 8){ if(BLEN(bp) < MinAdvise){
ipriv->stats[LenErrs6]++; ipriv->stats[LenErrs6]++;
goto raise; goto raise;
} }