--- /sys/src/9k/ip/arp.c +++ /sys/src/9k/ip/arp.c @@ -523,10 +523,10 @@ enum char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n"; static void -convmac(char *p, uchar *mac, int n) +convmac(char *p, char *ep, uchar *mac, int n) { while(n-- > 0) - p += sprint(p, "%2.2ux", *mac++); + p = seprint(p, ep, "%2.2ux", *mac++); } int @@ -552,8 +552,9 @@ arpread(Arp *arp, char *p, ulong offset, int len) } len--; qlock(arp); - convmac(mac, a->mac, a->type->maclen); - n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac); + convmac(mac, &mac[sizeof mac], a->mac, a->type->maclen); + n += snprint(p+n, Alinelen+1, aformat, a->type->name, + arpstate[a->state], a->ip, mac); /* +1 for NUL */ qunlock(arp); } --- /sys/src/9k/ip/chandial.c +++ /sys/src/9k/ip/chandial.c @@ -66,7 +66,7 @@ call(char *clone, char *dest, DS *ds) name[n] = 0; for(p = name; *p == ' '; p++) ; - sprint(name, "%lud", strtoul(p, 0, 0)); + snprint(name, sizeof name, "%lud", strtoul(p, 0, 0)); p = strrchr(clone, '/'); *p = 0; if(ds->dir) --- /sys/src/9k/ip/ethermedium.c +++ /sys/src/9k/ip/ethermedium.c @@ -9,6 +9,8 @@ #include "ip.h" #include "ipv6.h" +#include "etherif.h" + typedef struct Etherhdr Etherhdr; struct Etherhdr { @@ -94,9 +96,6 @@ struct Etherrock */ enum { - ETARP = 0x0806, - ETIP4 = 0x0800, - ETIP6 = 0x86DD, ARPREQUEST = 1, ARPREPLY = 2, }; @@ -415,7 +414,7 @@ etheraddmulti(Ipifc *ifc, uchar *a, uchar *) int version; version = multicastea(mac, a); - sprint(buf, "addmulti %E", mac); + snprint(buf, sizeof buf, "addmulti %E", mac); switch(version){ case V4: er->cchan4->dev->write(er->cchan4, buf, strlen(buf), 0); @@ -437,7 +436,7 @@ etherremmulti(Ipifc *ifc, uchar *a, uchar *) int version; version = multicastea(mac, a); - sprint(buf, "remmulti %E", mac); + snprint(buf, sizeof buf, "remmulti %E", mac); switch(version){ case V4: er->cchan4->dev->write(er->cchan4, buf, strlen(buf), 0); --- /sys/src/9k/ip/icmp.c +++ /sys/src/9k/ip/icmp.c @@ -368,7 +368,7 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp) case EchoRequest: if (iplen < n) bp = trimblock(bp, 0, iplen); - r = mkechoreply(bp); + r = mkechoreply(concatblock(bp)); ipriv->out[EchoReply]++; ipoput4(icmp->f, r, 0, MAXTTL, DFLTTOS, nil); break; @@ -395,7 +395,7 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp) break; case TimeExceed: if(p->code == 0){ - sprint(m2, "ttl exceeded at %V", p->src); + snprint(m2, sizeof m2, "ttl exceeded at %V", p->src); bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE; if(blocklen(bp) < MinAdvise){ --- /sys/src/9k/ip/icmp6.c +++ /sys/src/9k/ip/icmp6.c @@ -418,39 +418,37 @@ icmpna(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags) ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil); } +/* if free is true, freeblist(bp) before return. */ extern void icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free) { - int osz = BLEN(bp); - int sz = MIN(IPICMPSZ + osz, v6MINTU); + int osz, sz; Block *nbp; IPICMP *np; + Icmppriv6 *ipriv; Ip6hdr *p; - Proto *icmp = f->t2p[ICMPv6]; - Icmppriv6 *ipriv = icmp->priv; + Proto *icmp; + osz = BLEN(bp); + sz = MIN(IPICMPSZ + osz, v6MINTU); + icmp = f->t2p[ICMPv6]; + ipriv = icmp->priv; p = (Ip6hdr *)bp->rp; - if(isv6mcast(p->src)) - goto clean; - + goto freebl; nbp = newIPICMP(sz); np = (IPICMP *)nbp->rp; rlock(ifc); - if(ipv6anylocal(ifc, np->src)) - netlog(f, Logicmp, "send icmphostunr -> src %I dst %I\n", - p->src, p->dst); - else { + if(!ipv6anylocal(ifc, np->src)){ netlog(f, Logicmp, "icmphostunr fail -> src %I dst %I\n", p->src, p->dst); + runlock(ifc); freeblist(nbp); - if(free) - goto clean; - else - return; + goto freebl; } + netlog(f, Logicmp, "send icmphostunr -> src %I dst %I\n", p->src, p->dst); memmove(np->dst, p->src, IPaddrlen); np->type = UnreachableV6; np->code = code; @@ -462,14 +460,12 @@ icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free) if(free) ipiput6(f, ifc, nbp); - else { + else ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil); - return; - } - -clean: runlock(ifc); - freeblist(bp); +freebl: + if(free) + freeblist(bp); } extern void @@ -484,13 +480,11 @@ icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp) Icmppriv6 *ipriv = icmp->priv; p = (Ip6hdr *)bp->rp; - if(isv6mcast(p->src)) return; nbp = newIPICMP(sz); np = (IPICMP *) nbp->rp; - if(ipv6anylocal(ifc, np->src)) netlog(f, Logicmp, "send icmpttlexceeded6 -> src %I dst %I\n", p->src, p->dst); @@ -523,13 +517,11 @@ icmppkttoobig6(Fs *f, Ipifc *ifc, Block *bp) Icmppriv6 *ipriv = icmp->priv; p = (Ip6hdr *)bp->rp; - if(isv6mcast(p->src)) return; nbp = newIPICMP(sz); np = (IPICMP *)nbp->rp; - if(ipv6anylocal(ifc, np->src)) netlog(f, Logicmp, "send icmppkttoobig6 -> src %I dst %I\n", p->src, p->dst); @@ -555,15 +547,13 @@ icmppkttoobig6(Fs *f, Ipifc *ifc, Block *bp) * RFC 2461, pages 39-40, pages 57-58. */ 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 pktsz = BLEN(bp); - uchar *packet = bp->rp; - IPICMP *p = (IPICMP *) packet; + int sz, osz, unsp, n, ttl, iplen, pktsz; + uchar *packet; + IPICMP *p; Ndpkt *np; - USED(ifc); n = blocklen(bp); if(n < IPICMPSZ) { ipriv->stats[HlenErrs6]++; @@ -571,6 +561,9 @@ valid(Proto *icmp, Ipifc *ifc, Block *bp, Icmppriv6 *ipriv) goto err; } + packet = bp->rp; + p = (IPICMP *)packet; + pktsz = BLEN(bp); iplen = nhgets(p->ploadlen); if(iplen > n - IP6HDR) { ipriv->stats[LenErrs6]++; @@ -597,91 +590,78 @@ valid(Proto *icmp, Ipifc *ifc, Block *bp, Icmppriv6 *ipriv) p->ttl = ttl; /* additional tests for some pkt types */ - if (p->type == NbrSolicit || p->type == NbrAdvert || - p->type == RouterAdvert || p->type == RouterSolicit || - p->type == RedirectV6) { - if(p->ttl != HOP_LIMIT) { - ipriv->stats[HoplimErrs6]++; + if (p->type != NbrSolicit && p->type != NbrAdvert && + p->type != RouterAdvert && p->type != RouterSolicit && + p->type != RedirectV6) + return 1; /* TODO: unknown, presumed valid; why? */ + if(p->ttl != HOP_LIMIT) { + ipriv->stats[HoplimErrs6]++; + goto err; + } + if(p->code != 0) { + ipriv->stats[IcmpCodeErrs6]++; + goto err; + } + + switch (p->type) { + case NbrSolicit: + case NbrAdvert: + np = (Ndpkt*) p; + if(isv6mcast(np->target)) { + ipriv->stats[TargetErrs6]++; goto err; } - if(p->code != 0) { - ipriv->stats[IcmpCodeErrs6]++; + if(optexsts(np) && np->olen == 0) { + ipriv->stats[OptlenErrs6]++; goto err; } - - switch (p->type) { - case NbrSolicit: - case NbrAdvert: - np = (Ndpkt*) p; - if(isv6mcast(np->target)) { - ipriv->stats[TargetErrs6]++; + if (p->type == NbrSolicit && ipcmp(np->src, v6Unspecified) == 0) + if(!issmcast(np->dst) || optexsts(np)) { + ipriv->stats[AddrmxpErrs6]++; goto err; } - if(optexsts(np) && np->olen == 0) { + if(p->type == NbrAdvert && isv6mcast(np->dst) && + nhgets(np->icmpid) & Sflag){ + ipriv->stats[AddrmxpErrs6]++; + goto err; + } + break; + case RouterAdvert: + if(pktsz - IP6HDR < 16) { + ipriv->stats[HlenErrs6]++; + goto err; + } + if(!islinklocal(p->src)) { + ipriv->stats[RouterAddrErrs6]++; + goto err; + } + for (sz = IPICMPSZ + 8; sz+1 < pktsz; sz += 8*osz) { + osz = packet[sz+1]; + if(osz <= 0) { ipriv->stats[OptlenErrs6]++; goto err; } - - if (p->type == NbrSolicit && - ipcmp(np->src, v6Unspecified) == 0) - if(!issmcast(np->dst) || optexsts(np)) { - ipriv->stats[AddrmxpErrs6]++; - goto err; - } - - if(p->type == NbrAdvert) - if(isv6mcast(np->dst) && - (nhgets(np->icmpid) & Sflag)){ - ipriv->stats[AddrmxpErrs6]++; - goto err; - } - break; - - case RouterAdvert: - if(pktsz - IP6HDR < 16) { - ipriv->stats[HlenErrs6]++; - goto err; - } - if(!islinklocal(p->src)) { - ipriv->stats[RouterAddrErrs6]++; - goto err; - } - sz = IPICMPSZ + 8; - while (sz+1 < pktsz) { - osz = packet[sz+1]; - if(osz <= 0) { - ipriv->stats[OptlenErrs6]++; - goto err; - } - sz += 8*osz; - } - break; - - case RouterSolicit: - if(pktsz - IP6HDR < 8) { - ipriv->stats[HlenErrs6]++; + } + break; + case RouterSolicit: + if(pktsz - IP6HDR < 8) { + ipriv->stats[HlenErrs6]++; + goto err; + } + unsp = (ipcmp(p->src, v6Unspecified) == 0); + for (sz = IPICMPSZ + 8; sz+1 < pktsz; sz += 8*osz) { + osz = packet[sz+1]; + if(osz <= 0 || (unsp && packet[sz] == SRC_LLADDR)) { + ipriv->stats[OptlenErrs6]++; goto err; } - unsp = (ipcmp(p->src, v6Unspecified) == 0); - sz = IPICMPSZ + 8; - while (sz+1 < pktsz) { - osz = packet[sz+1]; - if(osz <= 0 || - (unsp && packet[sz] == SRC_LLADDR)) { - ipriv->stats[OptlenErrs6]++; - goto err; - } - sz += 8*osz; - } - break; - - case RedirectV6: - /* to be filled in */ - break; - - default: - goto err; } + break; + case RedirectV6: + /* TODO: fill in */ + break; + default: + goto err; } return 1; err: @@ -712,35 +692,39 @@ targettype(Fs *f, Ipifc *ifc, uchar *target) return 0; } +/* bp needs to be freed with freeblist or passed on. */ static void icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp) { - int refresh = 1; + int type; char *msg, m2[128]; uchar pktflags; - uchar *packet = bp->rp; + uchar *packet, *src; uchar lsrc[IPaddrlen]; Block *r; - IPICMP *p = (IPICMP *)packet; - Icmppriv6 *ipriv = icmp->priv; + IPICMP *p; + Icmppriv6 *ipriv; Iplifc *lifc; Ndpkt* np; Proto *pr; - if(!valid(icmp, ipifc, bp, ipriv) || p->type > Maxtype6) + packet = bp->rp; + p = (IPICMP *)packet; + type = p->type; + ipriv = icmp->priv; + if(!valid(icmp, ipifc, bp, ipriv) || type > Maxtype6) goto raise; - ipriv->in[p->type]++; - - switch(p->type) { + ipriv->in[type]++; + switch(type) { case EchoRequestV6: + bp = concatblock(bp); r = mkechoreply6(bp, ipifc); if(r == nil) goto raise; ipriv->out[EchoReply]++; ipoput6(icmp->f, r, 0, MAXTTL, DFLTTOS, nil); break; - case UnreachableV6: if(p->code >= nelem(unreachcode)) msg = unreachcode[Icmp6_unknown]; @@ -762,11 +746,9 @@ icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp) bp->rp -= IPICMPSZ; goticmpkt6(icmp, bp, 0); break; - case TimeExceedV6: if(p->code == 0){ - sprint(m2, "ttl exceeded at %I", p->src); - + snprint(m2, sizeof m2, "ttl exceeded at %I", p->src); bp->rp += IPICMPSZ; if(blocklen(bp) < 8){ ipriv->stats[LenErrs6]++; @@ -780,10 +762,8 @@ icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp) } bp->rp -= IPICMPSZ; } - goticmpkt6(icmp, bp, 0); break; - case RouterAdvert: case RouterSolicit: /* using lsrc as a temp, munge hdr for goticmp6 */ @@ -792,43 +772,39 @@ icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp) memmove(p->src, p->dst, IPaddrlen); memmove(p->dst, lsrc, IPaddrlen); } - goticmpkt6(icmp, bp, p->type); + goticmpkt6(icmp, bp, type); break; - case NbrSolicit: - np = (Ndpkt*) p; + np = (Ndpkt*)p; /* within bp */ pktflags = 0; switch (targettype(icmp->f, ipifc, np->target)) { case Tunirany: pktflags |= Oflag; /* fall through */ - case Tuniproxy: if(ipcmp(np->src, v6Unspecified) != 0) { arpenter(icmp->f, V6, np->src, np->lnaddr, 8*np->olen-2, 0); pktflags |= Sflag; } - if(ipv6local(ipifc, lsrc)) - icmpna(icmp->f, lsrc, - (ipcmp(np->src, v6Unspecified) == 0? - v6allnodesL: np->src), - np->target, ipifc->mac, pktflags); - else - freeblist(bp); + if(ipv6local(ipifc, lsrc)) { + src = np->src; + if(ipcmp(src, v6Unspecified) == 0) + src = v6allnodesL; + icmpna(icmp->f, lsrc, src, np->target, + ipifc->mac, pktflags); + } break; - case Tunitent: - /* not clear what needs to be done. send up - * an icmp mesg saying don't use this address? */ - default: - freeblist(bp); + /* + * not clear what needs to be done. send up + * an icmp mesg saying `don't use this address'? + */ + break; } + freeblist(bp); break; - case NbrAdvert: - np = (Ndpkt*) p; - /* * if the target address matches one of the local interface * addresses and the local interface address has tentative bit @@ -836,20 +812,19 @@ icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp) * detection part of ipconfig can discover duplication through * the arp table. */ + np = (Ndpkt*)p; /* within bp */ lifc = iplocalonifc(ipifc, np->target); - if(lifc && lifc->tentative) - refresh = 0; arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, - refresh); + lifc && lifc->tentative); freeblist(bp); break; - case PacketTooBigV6: default: goticmpkt6(icmp, bp, 0); break; } return; + raise: freeblist(bp); } @@ -870,14 +845,12 @@ icmpstats6(Proto *icmp6, char *buf, int len) if(icmpnames6[i]) p = seprint(p, e, "%s: %lud %lud\n", icmpnames6[i], priv->in[i], priv->out[i]); -/* else + else if (0) p = seprint(p, e, "%d: %lud %lud\n", i, priv->in[i], priv->out[i]); - */ return p - buf; } - /* import from icmp.c */ extern int icmpstate(Conv *c, char *state, int n); extern char* icmpannounce(Conv *c, char **argv, int argc); --- /sys/src/9k/ip/ip.c +++ /sys/src/9k/ip/ip.c @@ -215,7 +215,8 @@ ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c) return 0; } -if((eh->frag[0] & (IP_DF>>8)) && !gating) print("%V: DF set\n", eh->dst); + if((eh->frag[0] & (IP_DF>>8)) && !gating) + print("%V: DF set\n", eh->dst); if(eh->frag[0] & (IP_DF>>8)){ ip->stats[FragFails]++; --- /sys/src/9k/ip/ip.h +++ /sys/src/9k/ip/ip.h @@ -38,7 +38,7 @@ enum Addrlen= 64, Maxproto= 20, Nhash= 64, - Maxincall= 128, + Maxincall= 128, /* max. conn.s in listen q not accepted yet */ Nchans= 1024, MAClen= 16, /* longest mac address */ --- /sys/src/9k/ip/ipifc.c +++ /sys/src/9k/ip/ipifc.c @@ -16,6 +16,7 @@ enum { NHASH = 1<<6, NCACHE = 256, QMAX = 192*1024-1, + Maxv6repr = (128/(4*4))*(4+1), /* limit of xxxx:xxxx:⋯ notation */ }; Medium *media[Maxmedia] = { 0 }; @@ -1611,7 +1612,7 @@ ipifcadd6(Ipifc *ifc, char**argv, int argc) { int plen = 64; long origint = NOW / 1000, preflt = ~0L, validlt = ~0L; - char addr[40], preflen[6]; + char addr[Maxv6repr], preflen[6]; char *params[3]; uchar autoflag = 1, onlink = 1; uchar prefix[IPaddrlen]; @@ -1639,9 +1640,17 @@ ipifcadd6(Ipifc *ifc, char**argv, int argc) return Ebadarg; } - if (parseip(prefix, argv[1]) != 6 || validlt < preflt || plen < 0 || - plen > 64 || islinklocal(prefix)) - return Ebadarg; + if (parseip(prefix, argv[1]) != 6) + return "bad ipv6 address"; + if (validlt < preflt) + return "valid ipv6 lifetime less than preferred lifetime"; + if (plen < 0) + return "negative ipv6 prefix length"; + /* i think that this length limit is bogus - geoff */ +// if (plen > 64) +// return "ipv6 prefix length greater than 64; + if (islinklocal(prefix)) + return "ipv6 prefix is link-local"; lifc = smalloc(sizeof(Iplifc)); lifc->onlink = (onlink != 0); @@ -1652,10 +1661,10 @@ ipifcadd6(Ipifc *ifc, char**argv, int argc) /* issue "add" ctl msg for v6 link-local addr and prefix len */ if(!ifc->medium->pref2addr) - return Ebadarg; + return "no pref2addr on interface"; ifc->medium->pref2addr(prefix, ifc->mac); /* mac → v6 link-local addr */ - sprint(addr, "%I", prefix); - sprint(preflen, "/%d", plen); + snprint(addr, sizeof addr, "%I", prefix); + snprint(preflen, sizeof preflen, "/%d", plen); params[0] = "add"; params[1] = addr; params[2] = preflen; --- /sys/src/9k/ip/ipv6.c +++ /sys/src/9k/ip/ipv6.c @@ -259,7 +259,7 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp) tentative = iptentative(f, v6dst); if(tentative && h->proto != ICMPv6) { - print("tentative addr, drop\n"); + print("ipv6 non-icmp tentative addr %I, drop\n", v6dst); freeblist(bp); return; } --- /sys/src/9k/ip/ipv6.h +++ /sys/src/9k/ip/ipv6.h @@ -20,10 +20,6 @@ #define optexsts(np) (nhgets((np)->ploadlen) > 24) #define issmcast(addr) (memcmp((addr), v6solicitednode, 13) == 0) -#ifndef MIN -#define MIN(a, b) ((a) <= (b)? (a): (b)) -#endif - enum { /* Header Types */ HBH = 0, /* hop-by-hop multicast routing protocol */ ICMP = 1, --- /sys/src/9k/k10/etherif.h +++ /sys/src/9k/k10/etherif.h @@ -5,6 +5,11 @@ enum ETHERMAXTU = 1514, /* maximum transmit size */ ETHERHDRSIZE = 14, /* size of an ethernet header */ + /* ethernet packet types */ + ETARP = 0x0806, + ETIP4 = 0x0800, + ETIP6 = 0x86DD, + MaxEther = 48, Ntypes = 8, };