diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2023-05-16 22:16:12 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2023-05-16 22:16:12 +0000 |
commit | c45766fb054e3c82fe7be6cd5da2e6ff58e534e3 (patch) | |
tree | 6100eecedb57d1b1dedaa0a899f974bbca49ecb9 | |
parent | d4ce962fe33f3eca8da0b4ab2b5a81cc5359b71f (diff) |
devip: address some ipv6 issues on pkt interface
relax the maclen check as v6 neighbour disicovery might
give bigger buffers as the medium uses for the mac
address size, as the packet does not contain exact byte
count but rounds all the options to multiples of 8.
drop neighbour discovery packets coming from interfaces
with zero-length maclen.
when dialing icmpv6 protocol with link-local address
for the local ip address, filter any packets to it that
come from a different interface. otherwise ipconfig
would see router advertisements from other interfaces.
fix the locking for ipifc ctl messages: properly
acquire the wlock and check that the interface is still
bound for every ctl messages touching the interface.
make add6 ipifc ctl message work for media with
zero-length maclen by using the interface identier
from pre-existing link-local address when available.
-rw-r--r-- | sys/src/9/ip/arp.c | 6 | ||||
-rw-r--r-- | sys/src/9/ip/ethermedium.c | 4 | ||||
-rw-r--r-- | sys/src/9/ip/icmp6.c | 43 | ||||
-rw-r--r-- | sys/src/9/ip/ip.h | 2 | ||||
-rw-r--r-- | sys/src/9/ip/ipifc.c | 138 | ||||
-rw-r--r-- | sys/src/9/ip/ipv6.h | 4 |
6 files changed, 111 insertions, 86 deletions
diff --git a/sys/src/9/ip/arp.c b/sys/src/9/ip/arp.c index 1efb5093d..14d22aafa 100644 --- a/sys/src/9/ip/arp.c +++ b/sys/src/9/ip/arp.c @@ -324,7 +324,7 @@ arpresolve(Arp *arp, Arpent *a, uchar *mac, Routehint *rh) } int -arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *ia, Ipifc *ifc, int refresh) +arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int maclen, uchar *ia, Ipifc *ifc, int refresh) { Routehint rh; uchar v6ip[IPaddrlen]; @@ -333,7 +333,7 @@ arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *ia, Ipifc *if Route *r; Arp *arp; - if(ifc->m == nil || ifc->m->maclen != n || ifc->m->maclen == 0) + if(ifc->m == nil || maclen < ifc->m->maclen || ifc->m->maclen == 0) return -1; rh.r = nil; @@ -597,7 +597,7 @@ ndpsendsol(Fs *f, Arpent *a) return; send: if(!waserror()){ - icmpns6(f, src, SRC_UNI, targ, TARG_MULTI, ifc->mac); + icmpns6(f, src, SRC_UNI, targ, TARG_MULTI, ifc->mac, ifc->m->maclen); poperror(); } } diff --git a/sys/src/9/ip/ethermedium.c b/sys/src/9/ip/ethermedium.c index b2e04947a..8406542f8 100644 --- a/sys/src/9/ip/ethermedium.c +++ b/sys/src/9/ip/ethermedium.c @@ -708,7 +708,7 @@ etherareg(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *ip) return; if(!lifc->tentative){ - icmpna6(f, lifc->local, v6allnodesL, ip, ifc->mac, 1<<5); + icmpna6(f, lifc->local, v6allnodesL, ip, ifc->mac, 6, 1<<5); return; } @@ -722,7 +722,7 @@ etherareg(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *ip) remroute(f, a, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad); nexterror(); } - icmpns6(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac); + icmpns6(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac, 6); poperror(); remroute(f, a, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad); } diff --git a/sys/src/9/ip/icmp6.c b/sys/src/9/ip/icmp6.c index 62f4bda90..694c138ef 100644 --- a/sys/src/9/ip/icmp6.c +++ b/sys/src/9/ip/icmp6.c @@ -118,12 +118,9 @@ struct Ndpkt { uchar otype; uchar olen; /* length in units of 8 octets(incl type, code), * 1 for IEEE 802 addresses */ - uchar lnaddr[6]; /* link-layer address */ - uchar payload[]; + uchar lnaddr[]; /* link-layer address */ }; -#define NDPKTSZ offsetof(Ndpkt, payload[0]) - typedef struct Icmppriv6 { ulong stats[Nstats6]; @@ -310,7 +307,7 @@ icmpctl6(Conv *c, char **argv, int argc) } static void -goticmpkt6(Proto *icmp, Block *bp, int muxkey) +goticmpkt6(Proto *icmp, Ipifc *ifc, Block *bp, int muxkey) { ushort recid; uchar *addr; @@ -327,6 +324,7 @@ goticmpkt6(Proto *icmp, Block *bp, int muxkey) for(c = icmp->conv; (s = *c) != nil; c++){ if(s->lport == recid) if(ipcmp(s->laddr, p->dst) == 0 || ipcmp(s->raddr, addr) == 0) + if(!islinklocal(s->laddr) || iplocalonifc(ifc, s->laddr) != nil) qpass(s->rq, copyblock(bp, blocklen(bp))); } freeblist(bp); @@ -358,14 +356,15 @@ mkechoreply6(Block *bp, Ipifc *ifc) * and tuni == TARG_UNI => neighbor reachability. */ void -icmpns6(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac) +icmpns6(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac, int maclen) { Block *nbp; Ndpkt *np; Proto *icmp = f->t2p[ICMPv6]; Icmppriv6 *ipriv = icmp->priv; + int olen = (2+maclen+7)/8; - nbp = newIPICMP(NDPKTSZ); + nbp = newIPICMP(NDISCSZ + olen*8); np = (Ndpkt*) nbp->rp; if(suni == SRC_UNSPEC) @@ -383,10 +382,10 @@ icmpns6(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac) ipmove(np->target, targ); if(suni != SRC_UNSPEC) { np->otype = SRC_LLADDR; - np->olen = 1; /* 1+1+6 = 8 = 1 8-octet */ - memmove(np->lnaddr, mac, sizeof(np->lnaddr)); + np->olen = olen; + memmove(np->lnaddr, mac, maclen); } else - nbp->wp -= NDPKTSZ - NDISCSZ; + nbp->wp -= olen*8; set_cksum(nbp); ipriv->out[NbrSolicit]++; @@ -398,14 +397,15 @@ icmpns6(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac) * sends out an ICMPv6 neighbor advertisement. pktflags == RSO flags. */ void -icmpna6(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags) +icmpna6(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, int maclen, uchar flags) { Block *nbp; Ndpkt *np; Proto *icmp = f->t2p[ICMPv6]; Icmppriv6 *ipriv = icmp->priv; + int olen = (2+maclen+7)/8; - nbp = newIPICMP(NDPKTSZ); + nbp = newIPICMP(NDISCSZ + olen*8); np = (Ndpkt*)nbp->rp; ipmove(np->src, src); @@ -417,8 +417,8 @@ icmpna6(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags) ipmove(np->target, targ); np->otype = TARGET_LLADDR; - np->olen = 1; - memmove(np->lnaddr, mac, sizeof(np->lnaddr)); + np->olen = olen; + memmove(np->lnaddr, mac, maclen); set_cksum(nbp); ipriv->out[NbrAdvert]++; @@ -700,7 +700,7 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp) } } bp->rp -= IPICMPSZ; - goticmpkt6(icmp, bp, 0); + goticmpkt6(icmp, ifc, bp, 0); break; case TimeExceedV6: @@ -712,7 +712,7 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp) snprint(msg = m2, sizeof m2, "frag time exceeded at %I", p->src); goto Advise; } - goticmpkt6(icmp, bp, 0); + goticmpkt6(icmp, ifc, bp, 0); break; case PacketTooBigV6: @@ -722,10 +722,12 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp) case RouterAdvert: case RouterSolicit: - goticmpkt6(icmp, bp, p->type); + goticmpkt6(icmp, ifc, bp, p->type); break; case NbrSolicit: + if(ifc->m->maclen == 0) + goto raise; np = (Ndpkt*)p; pktflags = 0; if(ifc->sendra6) @@ -742,15 +744,16 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp) } else ipmove(ia, np->target); icmpna6(icmp->f, ia, (pktflags & Sflag)? np->src: v6allnodesL, - np->target, ifc->mac, pktflags); + np->target, ifc->mac, ifc->m->maclen, pktflags); break; } freeblist(bp); break; case NbrAdvert: + if(ifc->m->maclen == 0) + goto raise; np = (Ndpkt*)p; - /* * if the target address matches one of the local interface * addresses and the local interface address has tentative bit @@ -767,7 +770,7 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp) break; default: - goticmpkt6(icmp, bp, 0); + goticmpkt6(icmp, ifc, bp, 0); break; } return; diff --git a/sys/src/9/ip/ip.h b/sys/src/9/ip/ip.h index e547b685f..1a9ebe1be 100644 --- a/sys/src/9/ip/ip.h +++ b/sys/src/9/ip/ip.h @@ -667,7 +667,7 @@ extern Arpent* arpget(Arp*, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar extern void arprelease(Arp*, Arpent *a); extern void arpcontinue(Arp*, Arpent *a); extern Block* arpresolve(Arp*, Arpent *a, uchar *mac, Routehint *rh); -extern int arpenter(Fs*, int version, uchar *ip, uchar *mac, int n, uchar *ia, Ipifc *ifc, int refresh); +extern int arpenter(Fs*, int version, uchar *ip, uchar *mac, int maclen, uchar *ia, Ipifc *ifc, int refresh); extern int arpforme(Fs*, int version, uchar *targ, uchar *src, Ipifc *ifc); extern void ndpsendsol(Fs*, Arpent*); diff --git a/sys/src/9/ip/ipifc.c b/sys/src/9/ip/ipifc.c index f1fa6486c..2c401bc98 100644 --- a/sys/src/9/ip/ipifc.c +++ b/sys/src/9/ip/ipifc.c @@ -317,6 +317,10 @@ ipifcadjustburst(Ipifc *ifc) ifc->burst = burst; } +/* + * change an interface's burst delay + * ifc must be bound and wlock'd + */ static void ipifcsetdelay(Ipifc *ifc, int delay) { @@ -328,6 +332,10 @@ ipifcsetdelay(Ipifc *ifc, int delay) ipifcadjustburst(ifc); } +/* + * change an interface's baud rate + * ifc must be bound and wlock'd + */ static void ipifcsetspeed(Ipifc *ifc, int speed) { @@ -338,6 +346,20 @@ ipifcsetspeed(Ipifc *ifc, int speed) ipifcadjustburst(ifc); } +/* + * change an interface's mtu + * ifc must be bound and wlock'd + */ +static char* +ipifcsetmtu(Ipifc *ifc, int mtu) +{ + if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu) + return Ebadarg; + ifc->maxtu = mtu; + ipifcadjustburst(ifc); + return nil; +} + void ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip, Routehint *rh) { @@ -421,23 +443,6 @@ ipifcclose(Conv *c) } /* - * change an interface's mtu - */ -static char* -ipifcsetmtu(Ipifc *ifc, int mtu) -{ - Medium *m = ifc->m; - - if(m == nil) - return Eunbound; - if(mtu < m->mintu || mtu > m->maxtu) - return Ebadarg; - ifc->maxtu = mtu; - ipifcadjustburst(ifc); - return nil; -} - -/* * add an address to an interface. */ char* @@ -761,7 +766,11 @@ ipifcconnect(Conv* c, char **argv, int argc) return nil; } -char* +/* + * change ipv6 router parameters + * ifc must be bound and wlock'd + */ +static char* ipifcra6(Ipifc *ifc, char **argv, int argc) { int i, argsleft; @@ -802,7 +811,6 @@ ipifcra6(Ipifc *ifc, char **argv, int argc) rp.routerlt = atoi(argv[i+1]); else return Ebadarg; - argsleft -= 2; i += 2; } @@ -825,44 +833,45 @@ static char* ipifcctl(Conv* c, char **argv, int argc) { Ipifc *ifc = (Ipifc*)c->ptcl; + char *err = nil; - if(strcmp(argv[0], "add") == 0) - return ipifcadd(ifc, argv, argc, 0, nil); + if(strcmp(argv[0], "iprouting") == 0) + iprouting(c->p->f, argc>1? atoi(argv[1]): 1); + else if(strcmp(argv[0], "add") == 0) + err = ipifcadd(ifc, argv, argc, 0, nil); else if(strcmp(argv[0], "try") == 0) - return ipifcadd(ifc, argv, argc, 1, nil); + err = ipifcadd(ifc, argv, argc, 1, nil); else if(strcmp(argv[0], "remove") == 0) - return ipifcrem(ifc, argv, argc); + err = ipifcrem(ifc, argv, argc); else if(strcmp(argv[0], "unbind") == 0) - return ipifcunbind(ifc); - else if(strcmp(argv[0], "mtu") == 0) - return ipifcsetmtu(ifc, argc>1? strtoul(argv[1], 0, 0): 0); - else if(strcmp(argv[0], "speed") == 0){ - ipifcsetspeed(ifc, argc>1? atoi(argv[1]): 0); - return nil; - } - else if(strcmp(argv[0], "delay") == 0){ - ipifcsetdelay(ifc, argc>1? atoi(argv[1]): 0); - return nil; - } - else if(strcmp(argv[0], "iprouting") == 0){ - iprouting(c->p->f, argc>1? atoi(argv[1]): 1); - return nil; - } - else if(strcmp(argv[0], "reflect") == 0){ - ifc->reflect = argc>1? atoi(argv[1]): 1; - return nil; - } - else if(strcmp(argv[0], "reassemble") == 0){ - ifc->reassemble = argc>1? atoi(argv[1]): 1; - return nil; - } + err = ipifcunbind(ifc); else if(strcmp(argv[0], "add6") == 0) - return ipifcadd6(ifc, argv, argc); + err = ipifcadd6(ifc, argv, argc); else if(strcmp(argv[0], "remove6") == 0) - return ipifcremove6(ifc, argv, argc); - else if(strcmp(argv[0], "ra6") == 0) - return ipifcra6(ifc, argv, argc); - return "unsupported ctl"; + err = ipifcremove6(ifc, argv, argc); + else { + wlock(ifc); + if(ifc->m == nil){ + wunlock(ifc); + return Eunbound; + } + if(strcmp(argv[0], "mtu") == 0) + err = ipifcsetmtu(ifc, argc>1? strtoul(argv[1], 0, 0): 0); + else if(strcmp(argv[0], "speed") == 0) + ipifcsetspeed(ifc, argc>1? atoi(argv[1]): 0); + else if(strcmp(argv[0], "delay") == 0) + ipifcsetdelay(ifc, argc>1? atoi(argv[1]): 0); + else if(strcmp(argv[0], "reflect") == 0) + ifc->reflect = argc>1? atoi(argv[1]): 1; + else if(strcmp(argv[0], "reassemble") == 0) + ifc->reassemble = argc>1? atoi(argv[1]): 1; + else if(strcmp(argv[0], "ra6") == 0) + err = ipifcra6(ifc, argv, argc); + else + err = "unsupported ctl"; + wunlock(ifc); + } + return err; } int @@ -1661,7 +1670,6 @@ ipifcadd6(Ipifc *ifc, char **argv, int argc) char *params[3]; uchar prefix[IPaddrlen]; Iplifc lifc; - Medium *m; lifc.onlink = 1; lifc.autoflag = 1; @@ -1694,14 +1702,28 @@ ipifcadd6(Ipifc *ifc, char **argv, int argc) plen > 64 || islinklocal(prefix)) return Ebadarg; - /* issue "add" ctl msg for v6 link-local addr and prefix len */ - m = ifc->m; - if(m == nil || m->pref2addr == nil) + rlock(ifc); + if(ifc->m == nil){ + runlock(ifc); return Eunbound; - (*m->pref2addr)(prefix, ifc->mac); /* mac → v6 link-local addr */ + } + if(ifc->m->pref2addr != nil && ifc->m->maclen > 0) { + /* mac → v6 link-local addr */ + (*ifc->m->pref2addr)(prefix, ifc->mac); + } else { + /* copy from existing v6 link-local address */ + Iplifc *llifc = iplinklocalifc(ifc); + if(llifc == nil){ + runlock(ifc); + return Eunbound; + } + memmove(prefix+8, llifc->local+8, 8); + } + runlock(ifc); - sprint(addr, "%I", prefix); - sprint(preflen, "/%d", plen); + /* issue "add" ctl msg for v6 link-local addr and prefix len */ + snprint(addr, sizeof addr, "%I", prefix); + snprint(preflen, sizeof preflen, "/%d", plen); params[0] = "add"; params[1] = addr; params[2] = preflen; diff --git a/sys/src/9/ip/ipv6.h b/sys/src/9/ip/ipv6.h index 8f7a599a2..4fcd61fef 100644 --- a/sys/src/9/ip/ipv6.h +++ b/sys/src/9/ip/ipv6.h @@ -165,8 +165,8 @@ extern int v6aNpreflen; extern int v6aLpreflen; void ipv62smcast(uchar *, uchar *); -void icmpns6(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac); -void icmpna6(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags); +void icmpns6(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac, int maclen); +void icmpna6(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, int maclen, uchar flags); void icmpnohost6(Fs *f, Ipifc *ifc, Block *bp, Routehint *rh); void icmpnoconv6(Fs *f, Ipifc *ifc, Block *bp); void icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp); |