ref: c45766fb054e3c82fe7be6cd5da2e6ff58e534e3
parent: d4ce962fe33f3eca8da0b4ab2b5a81cc5359b71f
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue May 16 18:16:12 EDT 2023
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.
--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -324,7 +324,7 @@
}
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 @@
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 @@
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();
}
}
--- a/sys/src/9/ip/ethermedium.c
+++ b/sys/src/9/ip/ethermedium.c
@@ -708,7 +708,7 @@
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 @@
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);
}
--- a/sys/src/9/ip/icmp6.c
+++ b/sys/src/9/ip/icmp6.c
@@ -118,12 +118,9 @@
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 @@
}
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 @@
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 @@
* 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 @@
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 @@
* 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 @@
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 @@
}
}
bp->rp -= IPICMPSZ;
- goticmpkt6(icmp, bp, 0);
+ goticmpkt6(icmp, ifc, bp, 0);
break;
case TimeExceedV6:
@@ -712,7 +712,7 @@
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 @@
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,7 +744,7 @@
} 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);
@@ -749,8 +751,9 @@
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 @@
break;
default:
- goticmpkt6(icmp, bp, 0);
+ goticmpkt6(icmp, ifc, bp, 0);
break;
}
return;
--- a/sys/src/9/ip/ip.h
+++ b/sys/src/9/ip/ip.h
@@ -667,7 +667,7 @@
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*);
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -317,6 +317,10 @@
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 @@
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 @@
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 @@
}
/*
- * 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 @@
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 @@
rp.routerlt = atoi(argv[i+1]);
else
return Ebadarg;
-
argsleft -= 2;
i += 2;
}
@@ -825,44 +833,45 @@
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 @@
char *params[3];
uchar prefix[IPaddrlen];
Iplifc lifc;
- Medium *m;
lifc.onlink = 1;
lifc.autoflag = 1;
@@ -1694,14 +1702,28 @@
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;
--- a/sys/src/9/ip/ipv6.h
+++ b/sys/src/9/ip/ipv6.h
@@ -165,8 +165,8 @@
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);