ref: dac42bd005cb2d7701ee27547a3a62feb4a08835
parent: c2dd9b1da7659c9ac42e7612e5621e9426956c73
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Apr 8 17:16:29 EDT 2018
ip/ipconfig: fix v6 ndp code, use source specific default routes
--- a/sys/src/cmd/ip/ipconfig/ipconfig.h
+++ b/sys/src/cmd/ip/ipconfig/ipconfig.h
@@ -8,7 +8,7 @@
char *dev;
char mpoint[32];
int cfd; /* ifc control channel */
- int dfd; /* ifc data channel (for ppp) */
+ int rfd; /* iproute control channel */
char *cputype;
uchar hwa[32]; /* hardware address */
int hwatype;
@@ -46,9 +46,6 @@
* IPv6
*/
- /* solicitation specific - XXX add support for IPv6 leases */
-// ulong solicit_retries;
-
/* router-advertisement related */
uchar sendra;
uchar recvra;
@@ -86,7 +83,6 @@
extern int debug;
extern int dodhcp;
extern int dolog;
-extern int nip;
extern int plan9;
extern int dupl_disc;
@@ -94,45 +90,18 @@
extern int myifc;
extern char *vs;
-void adddefroute(char*, uchar*);
-void binddevice(void);
-void bootprequest(void);
-void controldevice(void);
-void dhcpquery(int, int);
-void dhcprecv(void);
-void dhcpsend(int);
-void dhcptimer(void);
-void dhcpwatch(int);
+void adddefroute(uchar*, uchar*, uchar*, uchar*);
+void removedefroute(int, uchar*, uchar*);
+
void doadd(int);
void doremove(void);
void dounbind(void);
int isether(void);
long jitter(void);
-void lookforip(char*);
void mklladdr(void);
-void mkclientid(void);
-int nipifcs(char*);
-int openlisten(void);
-uchar *optaddaddr(uchar*, int, uchar*);
-uchar *optaddbyte(uchar*, int, int);
-uchar *optaddstr(uchar*, int, char*);
-uchar *optadd(uchar*, int, void*, int);
-uchar *optaddulong(uchar*, int, ulong);
-uchar *optaddvec(uchar*, int, uchar*, int);
-int optgetaddrs(uchar*, int, uchar*, int);
-int optgetaddr(uchar*, int, uchar*);
-int optgetbyte(uchar*, int);
-int optgetstr(uchar*, int, char*, int);
-uchar *optget(uchar*, int, int*);
-ulong optgetulong(uchar*, int);
-int optgetvec(uchar*, int, uchar*, int);
-int parseoptions(uchar *p, int n);
-int parseverb(char*);
void procsetname(char *fmt, ...);
-void putndb(void);
void refresh(void);
ulong randint(ulong low, ulong hi);
-void usage(void);
int validip(uchar*);
void warning(char *fmt, ...);
@@ -141,9 +110,7 @@
*/
void doipv6(int);
-void recvra6(void);
-void sendra6(void);
-void v6paraminit(Conf *);
+void v6paraminit(Conf*);
typedef struct Headers Headers;
typedef struct Ip4hdr Ip4hdr;
@@ -186,6 +153,7 @@
OCMASK = 1 << 6,
OLMASK = 1 << 7,
AFMASK = 1 << 6,
+ RFMASK = 1 << 5,
};
enum {
--- a/sys/src/cmd/ip/ipconfig/ipv6.c
+++ b/sys/src/cmd/ip/ipconfig/ipv6.c
@@ -151,7 +151,7 @@
syslog(debug, RALOG, msg);
}
-extern void
+void
ea2lla(uchar *lla, uchar *ea)
{
assert(IPaddrlen == 16);
@@ -158,7 +158,7 @@
memset(lla, 0, IPaddrlen);
lla[0] = 0xFE;
lla[1] = 0x80;
- lla[8] = ea[0] | 0x2;
+ lla[8] = ea[0] ^ 0x2;
lla[9] = ea[1];
lla[10] = ea[2];
lla[11] = 0xFF;
@@ -168,7 +168,7 @@
lla[15] = ea[5];
}
-extern void
+void
ipv62smcast(uchar *smcast, uchar *a)
{
assert(IPaddrlen == 16);
@@ -208,7 +208,7 @@
{
static char buf[32];
- if (opt >= nelem(icmp6opts) || icmp6opts[opt] == nil) {
+ if(opt >= nelem(icmp6opts) || icmp6opts[opt] == nil) {
snprint(buf, sizeof buf, "unknown option %d", opt);
return buf;
} else
@@ -218,12 +218,12 @@
static char*
opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe)
{
- int otype, osz, pktsz;
+ int otype, osz, pktlen;
uchar *a;
char *p = sps, *e = spe;
a = ps;
- for (pktsz = pe - ps; pktsz > 0; pktsz -= osz) {
+ for (pktlen = pe - ps; pktlen > 0; pktlen -= osz) {
otype = a[0];
osz = a[1] * 8;
@@ -232,7 +232,7 @@
return seprint(p, e, " option=%s ", optname(otype));
case V6nd_srclladdr:
case V6nd_targlladdr:
- if (pktsz < osz || osz != 8)
+ if(pktlen < osz || osz != 8)
return seprint(p, e, " option=%s bad size=%d",
optname(otype), osz);
p = seprint(p, e, " option=%s maddr=%E", optname(otype),
@@ -239,7 +239,7 @@
a+2);
break;
case V6nd_pfxinfo:
- if (pktsz < osz || osz != 32)
+ if(pktlen < osz || osz != 32)
return seprint(p, e, " option=%s: bad size=%d",
optname(otype), osz);
@@ -259,56 +259,6 @@
}
static void
-pkt2str(uchar *ps, uchar *pe, char *sps, char *spe)
-{
- int pktlen;
- char *tn, *p, *e;
- uchar *a;
- Hdr *h;
-
- h = (Hdr*)ps;
- a = ps + 4;
- p = sps;
- e = spe;
-
- pktlen = pe - ps;
- if(pktlen < ICMP6LEN) {
- seprint(sps, spe, "short pkt");
- return;
- }
-
- tn = icmpmsg6[h->type];
- if(tn == nil)
- p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type,
- h->code, (ushort)NetS(h->cksum));
- else
- p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn,
- h->code, (ushort)NetS(h->cksum));
-
- switch(h->type){
- case RouterSolicit:
- ps += 8;
- p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0);
- opt_seprint(ps, pe, p, e);
- break;
- case RouterAdvert:
- ps += 16;
- p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d"
- " unused=%1.1d routerlt=%d reachtime=%d rxmtimer=%d",
- a[0],
- (*(a+1) & (1 << 7)) != 0,
- (*(a+1) & (1 << 6)) != 0,
- (*(a+1) & 63) != 0,
- NetS(a+2), NetL(a+4), NetL(a+8));
- opt_seprint(ps, pe, p, e);
- break;
- default:
- seprint(p, e, " unexpected icmp6 pkt type");
- break;
- }
-}
-
-static void
catch(void *a, char *msg)
{
USED(a);
@@ -318,51 +268,112 @@
noted(NDFLT);
}
-int
-dialicmp(uchar *dst, int dport, int *ctlfd)
+static int
+dialicmpv6(uchar *ip, int port)
{
- int fd, cfd, n, m;
- char cmsg[100], name[128], connind[40];
- char hdrs[] = "headers";
+ char addr[128], local[128];
+ int fd, cfd;
- snprint(name, sizeof name, "%s/icmpv6/clone", conf.mpoint);
- cfd = open(name, ORDWR);
- if(cfd < 0)
- sysfatal("dialicmp: can't open %s: %r", name);
+ snprint(addr, sizeof(addr), "%s/icmpv6!%I!%d!r", conf.mpoint, ip, port);
+ snprint(local, sizeof(local), "%I!%d", conf.laddr, port);
+ if((fd = dial(addr, local, nil, &cfd)) < 0)
+ sysfatal("dialicmp6: %r");
+ fprint(cfd, "headers");
+ fprint(cfd, "ignoreadvice");
+ if(ISIPV6MCAST(ip))
+ fprint(cfd, "addmulti %I", conf.laddr);
+ close(cfd);
+ return fd;
+}
- n = snprint(cmsg, sizeof cmsg, "connect %I!%d!r %d", dst, dport, dport);
- m = write(cfd, cmsg, n);
- if (m < n)
- sysfatal("dialicmp: can't write %s to %s: %r", cmsg, name);
+static int
+arpenter(uchar *ip, uchar *mac)
+{
+ char buf[256];
+ int fd, n;
- seek(cfd, 0, 0);
- n = read(cfd, connind, sizeof connind);
- if (n < 0)
- connind[0] = 0;
- else if (n < sizeof connind)
- connind[n] = 0;
- else
- connind[sizeof connind - 1] = 0;
+ if(!validip(ip))
+ return 0;
+ snprint(buf, sizeof buf, "%s/arp", conf.mpoint);
+ if((fd = open(buf, OWRITE)) < 0){
+ warning("couldn't open %s: %r", buf);
+ return -1;
+ }
+ n = snprint(buf, sizeof buf, "add %s %I %E %I\n", conf.type, ip, mac, conf.laddr);
+ if(write(fd, buf, n) != n) {
+ warning("arpenter: %s: %r", buf);
+ close(fd);
+ return 0;
+ }
+ close(fd);
+ return 1;
+}
- snprint(name, sizeof name, "%s/icmpv6/%s/data", conf.mpoint, connind);
- fd = open(name, ORDWR);
- if(fd < 0)
- sysfatal("dialicmp: can't open %s: %r", name);
+static int
+arpcheck(uchar *ip)
+{
+ char buf[256], *f[5], *p;
+ uchar addr[IPaddrlen];
+ Biobuf *bp;
+ int rv;
- n = sizeof hdrs - 1;
- if(write(cfd, hdrs, n) < n)
- sysfatal("dialicmp: can't write `%s' to %s: %r", hdrs, name);
- *ctlfd = cfd;
- return fd;
+ snprint(buf, sizeof buf, "%s/arp", conf.mpoint);
+ bp = Bopen(buf, OREAD);
+ if(bp == nil){
+ warning("couldn't open %s: %r", buf);
+ return -1;
+ }
+ rv = 0;
+ while((p = Brdline(bp, '\n')) != nil){
+ p[Blinelen(bp)-1] = 0;
+ if(tokenize(p, f, nelem(f)) < 3)
+ continue;
+ if(parseip(addr, f[2]) != -1)
+ continue;
+ if(ipcmp(addr, ip) == 0){
+ rv = 1;
+ break;
+ }
+ }
+ Bterm(bp);
+ return rv;
}
+static int
+masklen(uchar *mask)
+{
+ int len;
+
+ for(len=0; len < 128; len += 8){
+ if(*mask != 255)
+ break;
+ mask++;
+ }
+ while(len < 128 && (*mask & (0x80 >> (len & 7))) != 0)
+ len++;
+ return len;
+}
+
+static void
+genipmkask(uchar *mask, int len)
+{
+ memset(mask, 0, IPaddrlen);
+ if(len < 0)
+ len = 0;
+ else if(len > 128)
+ len = 128;
+ for(; len >= 8; len -= 8)
+ *mask++ = 255;
+ if(len > 0)
+ *mask = ~((1<<(8-len))-1);
+}
+
/* add ipv6 addr to an interface */
int
ip6cfg(void)
{
- int tentative, dupfound = 0, n;
- char *p, buf[256];
- Biobuf *bp;
+ int tentative, n;
+ char buf[256];
if(!validip(conf.laddr) || isv4(conf.laddr))
return -1;
@@ -370,7 +381,7 @@
tentative = dupl_disc;
Again:
- if (tentative)
+ if(tentative)
n = sprint(buf, "try");
else
n = sprint(buf, "add");
@@ -390,30 +401,15 @@
return -1;
}
- if (!tentative)
+ if(!tentative){
+ if(validip(conf.gaddr) && !isv4(conf.gaddr))
+ adddefroute(conf.gaddr, conf.laddr, conf.laddr, conf.mask);
return 0;
-
- sleep(3000);
-
- /* read arp table, look for addr duplication */
- snprint(buf, sizeof buf, "%s/arp", conf.mpoint);
- bp = Bopen(buf, OREAD);
- if (bp == 0) {
- warning("couldn't open %s: %r", buf);
- return -1;
}
- snprint(buf, sizeof buf, "%I", conf.laddr);
- while(p = Brdline(bp, '\n')){
- p[Blinelen(bp)-1] = 0;
- if(cistrstr(p, buf) != 0) {
- dupfound = 1;
- break;
- }
- }
- Bterm(bp);
+ sleep(1000);
- if (!dupfound) {
+ if(arpcheck(conf.laddr) <= 0) {
tentative = 0;
goto Again;
}
@@ -426,31 +422,57 @@
static int
recvra6on(Ipifc *ifc)
{
- if (ifc == nil)
+ if(ifc == nil)
return 0;
- else if (ifc->sendra6 > 0)
+ else if(ifc->sendra6 > 0)
return IsRouter;
- else if (ifc->recvra6 > 0)
+ else if(ifc->recvra6 > 0)
return IsHostRecv;
else
return IsHostNoRecv;
}
-/* send icmpv6 router solicitation to multicast address for all routers */
+static int
+findllip(uchar *ip, Ipifc *ifc)
+{
+ Iplifc *lifc;
+
+ for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
+ if(ISIPV6LINKLOCAL(lifc->ip)){
+ ipmove(ip, lifc->ip);
+ return 1;
+ }
+ }
+ ipmove(ip, v6Unspecified);
+ return 0;
+}
+
static void
-sendrs(int fd)
+sendrs(int fd, uchar *dst)
{
Routersol *rs;
- uchar buff[sizeof *rs];
+ Lladdropt *llao;
+ uchar buf[1024];
+ int pktlen;
- memset(buff, 0, sizeof buff);
- rs = (Routersol *)buff;
- memmove(rs->dst, v6allroutersL, IPaddrlen);
- memmove(rs->src, v6Unspecified, IPaddrlen);
+ memset(buf, 0, sizeof buf);
+
+ rs = (Routersol *)buf;
rs->type = ICMP6_RS;
+ ipmove(rs->dst, dst);
+ ipmove(rs->src, conf.laddr);
+ pktlen = sizeof *rs;
- if(write(fd, rs, sizeof buff) < sizeof buff)
- ralog("sendrs: write failed, pkt size %d", sizeof buff);
+ if(conf.hwalen > 0){
+ llao = (Lladdropt *)&buf[pktlen];
+ llao->type = V6nd_srclladdr;
+ llao->len = (2+7+conf.hwalen)/8;
+ memmove(llao->lladdr, conf.hwa, conf.hwalen);
+ pktlen += 8 * llao->len;
+ }
+
+ if(write(fd, rs, pktlen) != pktlen)
+ ralog("sendrs: write failed, pkt size %d", pktlen);
else
ralog("sendrs: sent solicitation to %I from %I on %s",
rs->dst, rs->src, conf.dev);
@@ -477,8 +499,11 @@
{
int n;
+ if(fd < 0)
+ return;
+
n = strlen(str);
- if (write(fd, str, n) != n)
+ if(write(fd, str, n) != n)
ralog("write(%s) failed: %r", str);
}
@@ -522,9 +547,7 @@
static void
recvrahost(uchar buf[], int pktlen)
{
- int arpfd, m, n;
- char abuf[100];
- uchar optype;
+ int m, n, optype;
Lladdropt *llao;
Mtuopt *mtuo;
Prefixopt *prfo;
@@ -531,7 +554,14 @@
Routeradv *ra;
static int first = 1;
+ m = sizeof *ra;
ra = (Routeradv*)buf;
+ if(pktlen < m)
+ return;
+
+ if(!ISIPV6LINKLOCAL(ra->src))
+ return;
+
conf.ttl = ra->cttl;
conf.mflag = (MFMASK & ra->mor);
conf.oflag = (OCMASK & ra->mor);
@@ -538,87 +568,64 @@
conf.routerlt = nhgets(ra->routerlt);
conf.reachtime = nhgetl(ra->rchbltime);
conf.rxmitra = nhgetl(ra->rxmtimer);
-
- if (fprint(conf.cfd, "ra6 recvra 1") < 0)
- ralog("write(ra6 recvra 1) failed: %r");
issuebasera6(&conf);
- m = sizeof *ra;
- while (pktlen - m > 0) {
- optype = buf[m];
+ while(pktlen - m >= 8) {
+ n = m;
+ optype = buf[n];
+ m += 8 * buf[n+1];
+ if(pktlen < m)
+ return;
+
switch (optype) {
case V6nd_srclladdr:
- llao = (Lladdropt *)&buf[m];
- m += 8 * buf[m+1];
- if (llao->len != 1) {
- ralog("recvrahost: illegal len (%d) for source "
- "link layer address option", llao->len);
- return;
- }
- if (!ISIPV6LINKLOCAL(ra->src)) {
- ralog("recvrahost: non-link-local src addr for "
- "router adv %I", ra->src);
- return;
- }
- snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
- arpfd = open(abuf, OWRITE);
- if (arpfd < 0) {
- ralog("recvrahost: couldn't open %s to write: %r",
- abuf);
- return;
- }
-
- n = snprint(abuf, sizeof abuf, "add ether %I %E",
- ra->src, llao->lladdr);
- if (write(arpfd, abuf, n) < n)
- ralog("recvrahost: couldn't write to %s/arp",
- conf.mpoint);
- close(arpfd);
+ llao = (Lladdropt *)&buf[n];
+ if(llao->len == 1 && conf.hwalen == 6)
+ arpenter(ra->src, llao->lladdr);
break;
- case V6nd_targlladdr:
- case V6nd_redirhdr:
- m += 8 * buf[m+1];
- ralog("ignoring unexpected option type `%s' in Routeradv",
- optname(optype));
- break;
case V6nd_mtu:
- mtuo = (Mtuopt*)&buf[m];
- m += 8 * mtuo->len;
+ mtuo = (Mtuopt*)&buf[n];
conf.linkmtu = nhgetl(mtuo->mtu);
break;
case V6nd_pfxinfo:
- prfo = (Prefixopt*)&buf[m];
- m += 8 * prfo->len;
- if (prfo->len != 4) {
- ralog("illegal len (%d) for prefix option",
- prfo->len);
+ prfo = (Prefixopt*)&buf[n];
+ if(prfo->len != 4) {
+ ralog("illegal len (%d) for prefix option", prfo->len);
return;
}
- memmove(conf.v6pref, prfo->pref, IPaddrlen);
- conf.prefixlen = prfo->plen;
+ if((prfo->plen & 127) == 0
+ || !validip(prfo->pref)
+ || isv4(prfo->pref)
+ || ipcmp(prfo->pref, v6loopback) == 0
+ || ISIPV6MCAST(prfo->pref)
+ || ISIPV6LINKLOCAL(prfo->pref)){
+ ralog("igoring bogus prefix from %I on %s; pfx %I /%d",
+ ra->src, conf.dev, prfo->pref, prfo->plen);
+ break;
+ }
+ if(first) {
+ first = 0;
+ ralog("got initial RA from %I on %s; pfx %I /%d",
+ ra->src, conf.dev, prfo->pref, prfo->plen);
+ }
+ conf.prefixlen = prfo->plen & 127;
+ genipmkask(conf.mask, conf.prefixlen);
+ maskip(prfo->pref, conf.mask, conf.v6pref);
conf.onlink = ((prfo->lar & OLMASK) != 0);
conf.autoflag = ((prfo->lar & AFMASK) != 0);
conf.validlt = nhgetl(prfo->validlt);
conf.preflt = nhgetl(prfo->preflt);
issueadd6(&conf);
- if (first) {
- first = 0;
- ralog("got initial RA from %I on %s; pfx %I",
- ra->src, conf.dev, prfo->pref);
- }
+ if(conf.routerlt == 0)
+ break;
+ if((prfo->lar & RFMASK) != 0)
+ ipmove(conf.gaddr, prfo->pref);
+ else
+ ipmove(conf.gaddr, ra->src);
+ adddefroute(conf.gaddr, conf.laddr, conf.v6pref, conf.mask);
break;
- case V6nd_srcaddrs:
- /* netsbd sends this, so quietly ignore it for now */
- m += 8 * buf[m+1];
- break;
- default:
- m += 8 * buf[m+1];
- ralog("ignoring optype %d in Routeradv", optype);
- break;
}
}
- if(conf.routerlt != 0 && ISIPV6LINKLOCAL(ra->src))
- adddefroute(conf.mpoint, ra->src);
}
/*
@@ -627,57 +634,62 @@
void
recvra6(void)
{
- int fd, cfd, n, sendrscnt, sleepfor;
+ int fd, n, sendrscnt, recvracnt, sleepfor;
uchar buf[4096];
- Ipifc *ifc = nil;
+ Ipifc *ifc;
- /* TODO: why not v6allroutersL? */
- fd = dialicmp(v6allnodesL, ICMP6_RA, &cfd);
- if (fd < 0)
+ ifc = readipifc(conf.mpoint, nil, myifc);
+ if(ifc == nil)
+ sysfatal("can't read ipifc: %r");
+
+ if(!findllip(conf.laddr, ifc))
+ sysfatal("no link local address");
+
+ fd = dialicmpv6(v6allnodesL, ICMP6_RA);
+ if(fd < 0)
sysfatal("can't open icmp_ra connection: %r");
notify(catch);
sendrscnt = Maxv6rss;
+ recvracnt = 0;
switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
case -1:
sysfatal("can't fork: %r");
default:
+ close(fd);
return;
case 0:
break;
}
- procsetname("recvra6 on %s", conf.dev);
+ procsetname("recvra6 on %s %I", conf.dev, conf.laddr);
ralog("recvra6 on %s", conf.dev);
- sleepfor = jitter();
+ sleepfor = Minv6interradelay;
for (;;) {
- /*
- * We only get 3 (Maxv6rss) tries, so make sure we
- * wait long enough to be certain that at least one RA
- * will be transmitted.
- */
- if (sleepfor < 7000)
- sleepfor = 7000;
alarm(sleepfor);
n = read(fd, buf, sizeof buf);
- alarm(0);
+ sleepfor = alarm(0);
- ifc = readipifc(conf.mpoint, ifc, myifc);
- if (ifc == nil) {
- ralog("recvra6: can't read router params on %s",
- conf.mpoint);
+ /* wait for alarm to expire */
+ if(sendrscnt < 0 && sleepfor > 100)
continue;
+
+ ifc = readipifc(conf.mpoint, ifc, myifc);
+ if(ifc == nil) {
+ ralog("recvra6: can't read router params on %s, quitting on %s",
+ conf.mpoint, conf.dev);
+ exits(nil);
}
- if (n <= 0) {
- if (sendrscnt > 0) {
+ if(n <= 0) {
+ if(sendrscnt > 0) {
sendrscnt--;
- if (recvra6on(ifc) == IsHostRecv)
- sendrs(fd);
+ if(recvra6on(ifc) == IsHostRecv)
+ sendrs(fd, v6allroutersL);
sleepfor = V6rsintvl + nrand(100);
}
- if (sendrscnt == 0) {
+ if(sendrscnt == 0) {
sendrscnt--;
sleepfor = 0;
ralog("recvra6: no router advs after %d sols on %s",
@@ -686,8 +698,15 @@
continue;
}
+ /* got at least initial ra; no whining */
+ sendrscnt = -1;
sleepfor = 0;
- sendrscnt = -1; /* got at least initial ra; no whining */
+
+ if(++recvracnt >= Maxv6initras){
+ recvracnt = 0;
+ sleepfor = Maxv6radelay;
+ }
+
switch (recvra6on(ifc)) {
case IsRouter:
recvrarouter(buf, n);
@@ -697,8 +716,7 @@
break;
case IsHostNoRecv:
ralog("recvra6: recvra off, quitting on %s", conf.dev);
- close(fd);
- exits(0);
+ exits(nil);
}
}
}
@@ -711,45 +729,29 @@
int
recvrs(uchar *buf, int pktlen, uchar *sol)
{
- int n, optsz, arpfd;
- char abuf[256];
+ int n;
Routersol *rs;
Lladdropt *llao;
+ n = sizeof *rs + sizeof *llao;
rs = (Routersol *)buf;
- n = sizeof *rs;
- optsz = pktlen - n;
- pkt2str(buf, buf+pktlen, abuf, abuf+nelem(abuf));
+ if(pktlen < n)
+ return 0;
- if (optsz != sizeof *llao)
+ llao = (Lladdropt *)&buf[sizeof *rs];
+ if(llao->type != V6nd_srclladdr || llao->len != 1 || conf.hwalen != 6)
return 0;
- if (buf[n] != V6nd_srclladdr || 8*buf[n+1] != sizeof *llao) {
- ralog("rs opt err %s", abuf);
- return -1;
- }
- ralog("rs recv %s", abuf);
-
- if (memcmp(rs->src, v6Unspecified, IPaddrlen) == 0)
+ if(!validip(rs->src)
+ || isv4(rs->src)
+ || ipcmp(rs->src, v6loopback) == 0
+ || ISIPV6MCAST(rs->src))
return 0;
- snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
- arpfd = open(abuf, OWRITE);
- if (arpfd < 0) {
- ralog("recvrs: can't open %s/arp to write: %r", conf.mpoint);
- return -1;
- }
+ if((n = arpenter(rs->src, llao->lladdr)) <= 0)
+ return n;
- llao = (Lladdropt *)buf[n];
- n = snprint(abuf, sizeof abuf, "add ether %I %E", rs->src, llao->lladdr);
- if (write(arpfd, abuf, n) < n) {
- ralog("recvrs: can't write to %s/arp: %r", conf.mpoint);
- close(arpfd);
- return -1;
- }
-
- memmove(sol, rs->src, IPaddrlen);
- close(arpfd);
+ ipmove(sol, rs->src);
return 1;
}
@@ -756,78 +758,68 @@
void
sendra(int fd, uchar *dst, int rlt, Ipifc *ifc)
{
- int pktsz, preflen;
- char abuf[1024], tmp[40];
- uchar buf[1024], macaddr[6], src[IPaddrlen];
- Iplifc *lifc, *nlifc;
+ uchar buf[1024];
+ Iplifc *lifc;
Lladdropt *llao;
Prefixopt *prfo;
Routeradv *ra;
+ int pktlen;
memset(buf, 0, sizeof buf);
- ra = (Routeradv *)buf;
- myetheraddr(macaddr, conf.dev);
- ea2lla(src, macaddr);
- memmove(ra->src, src, IPaddrlen);
- memmove(ra->dst, dst, IPaddrlen);
+ ra = (Routeradv *)buf;
+ ipmove(ra->dst, dst);
+ ipmove(ra->src, conf.laddr);
ra->type = ICMP6_RA;
ra->cttl = conf.ttl;
-
- if (conf.mflag > 0)
+ if(conf.mflag > 0)
ra->mor |= MFMASK;
- if (conf.oflag > 0)
+ if(conf.oflag > 0)
ra->mor |= OCMASK;
- if (rlt > 0)
+ if(rlt > 0)
hnputs(ra->routerlt, conf.routerlt);
else
hnputs(ra->routerlt, 0);
hnputl(ra->rchbltime, conf.reachtime);
hnputl(ra->rxmtimer, conf.rxmitra);
+ pktlen = sizeof *ra;
- pktsz = sizeof *ra;
-
- /* include all global unicast prefixes on interface in prefix options */
- for (lifc = (ifc? ifc->lifc: nil); lifc; lifc = nlifc) {
- nlifc = lifc->next;
- prfo = (Prefixopt *)(buf + pktsz);
- /* global unicast address? */
- if (!ISIPV6LINKLOCAL(lifc->ip) && !ISIPV6MCAST(lifc->ip) &&
- memcmp(lifc->ip, IPnoaddr, IPaddrlen) != 0 &&
- memcmp(lifc->ip, v6loopback, IPaddrlen) != 0 &&
- !isv4(lifc->ip)) {
- memmove(prfo->pref, lifc->net, IPaddrlen);
-
- /* hack to find prefix length */
- snprint(tmp, sizeof tmp, "%M", lifc->mask);
- preflen = atoi(&tmp[1]);
- prfo->plen = preflen & 0xff;
- if (prfo->plen == 0)
- continue;
-
- prfo->type = V6nd_pfxinfo;
- prfo->len = 4;
- prfo->lar = AFMASK|OLMASK;
- hnputl(prfo->validlt, lifc->validlt);
- hnputl(prfo->preflt, lifc->preflt);
- pktsz += sizeof *prfo;
- }
- }
/*
* include link layer address (mac address for now) in
* link layer address option
*/
- llao = (Lladdropt *)(buf + pktsz);
- llao->type = V6nd_srclladdr;
- llao->len = 1;
- memmove(llao->lladdr, macaddr, sizeof macaddr);
- pktsz += sizeof *llao;
+ if(conf.hwalen > 0){
+ llao = (Lladdropt *)&buf[pktlen];
+ llao->type = V6nd_srclladdr;
+ llao->len = (2+7+conf.hwalen)/8;
+ memmove(llao->lladdr, conf.hwa, conf.hwalen);
+ pktlen += 8 * llao->len;
+ }
- pkt2str(buf+40, buf+pktsz, abuf, abuf+1024);
- if(write(fd, buf, pktsz) < pktsz)
- ralog("sendra fail %s: %r", abuf);
- else if (debug)
- ralog("sendra succ %s", abuf);
+ /* include all global unicast prefixes on interface in prefix options */
+ for (lifc = (ifc != nil? ifc->lifc: nil); lifc != nil; lifc = lifc->next) {
+ if(pktlen > sizeof buf - 4*8)
+ break;
+ if(!validip(lifc->ip)
+ || isv4(lifc->ip)
+ || ipcmp(lifc->ip, v6loopback) == 0
+ || ISIPV6MCAST(lifc->ip)
+ || ISIPV6LINKLOCAL(lifc->ip))
+ continue;
+ prfo = (Prefixopt *)&buf[pktlen];
+ prfo->type = V6nd_pfxinfo;
+ prfo->len = 4;
+ prfo->plen = masklen(lifc->mask) & 127;
+ if(prfo->plen == 0)
+ continue;
+ ipmove(prfo->pref, lifc->net);
+ prfo->lar = AFMASK|OLMASK;
+ hnputl(prfo->validlt, lifc->validlt);
+ hnputl(prfo->preflt, lifc->preflt);
+ pktlen += 8 * prfo->len;
+ }
+
+ write(fd, buf, pktlen);
}
/*
@@ -836,17 +828,22 @@
void
sendra6(void)
{
- int fd, cfd, n, dstknown = 0, sendracnt, sleepfor, nquitmsgs;
- long lastra, now;
+ int fd, n, sleepfor, nquitmsgs;
uchar buf[4096], dst[IPaddrlen];
- Ipifc *ifc = nil;
+ Ipifc *ifc;
- fd = dialicmp(v6allnodesL, ICMP6_RS, &cfd);
- if (fd < 0)
+ ifc = readipifc(conf.mpoint, nil, myifc);
+ if(ifc == nil)
+ sysfatal("can't read ipifc: %r");
+
+ if(!findllip(conf.laddr, ifc))
+ sysfatal("no link local address");
+
+ fd = dialicmpv6(v6allroutersL, ICMP6_RS);
+ if(fd < 0)
sysfatal("can't open icmp_rs connection: %r");
notify(catch);
- sendracnt = Maxv6initras;
nquitmsgs = Maxv6finalras;
switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
@@ -853,63 +850,46 @@
case -1:
sysfatal("can't fork: %r");
default:
+ close(fd);
return;
case 0:
break;
}
- procsetname("sendra6 on %s", conf.dev);
+ procsetname("sendra6 on %s %I", conf.dev, conf.laddr);
ralog("sendra6 on %s", conf.dev);
- sleepfor = jitter();
+ sleepfor = 100 + jitter();
for (;;) {
- lastra = time(0);
- if (sleepfor < 0)
- sleepfor = 0;
alarm(sleepfor);
n = read(fd, buf, sizeof buf);
- alarm(0);
+ sleepfor = alarm(0);
- ifc = readipifc(conf.mpoint, ifc, myifc);
- if (ifc == nil) {
- ralog("sendra6: can't read router params on %s",
- conf.mpoint);
+ if(n > 0 && recvrs(buf, n, dst) > 0)
+ sendra(fd, dst, 1, ifc);
+
+ /* wait for alarm to expire */
+ if(sleepfor > 100)
continue;
- }
+ sleepfor = Minv6interradelay;
- if (ifc->sendra6 <= 0)
- if (nquitmsgs > 0) {
- sendra(fd, v6allnodesL, 0, ifc);
+ ifc = readipifc(conf.mpoint, ifc, myifc);
+ if(ifc == nil) {
+ ralog("sendra6: can't read router params on %s, quitting on %s",
+ conf.mpoint, conf.dev);
+ exits(nil);
+ }
+ if(ifc->sendra6 <= 0){
+ if(nquitmsgs > 0) {
nquitmsgs--;
- sleepfor = Minv6interradelay + jitter();
+ sendra(fd, v6allnodesL, 0, ifc);
continue;
} else {
- ralog("sendra6: sendra off, quitting on %s",
- conf.dev);
- exits(0);
+ ralog("sendra6: sendra off, quitting on %s", conf.dev);
+ exits(nil);
}
-
- nquitmsgs = Maxv6finalras;
-
- if (n <= 0) { /* no RS */
- if (sendracnt > 0)
- sendracnt--;
- } else { /* respond to RS */
- dstknown = recvrs(buf, n, dst);
- now = time(0);
-
- if (now - lastra < Minv6interradelay) {
- /* too close, skip */
- sleepfor = lastra + Minv6interradelay +
- jitter() - now;
- continue;
- }
- sleep(jitter());
}
+ sendra(fd, v6allnodesL, 1, ifc);
sleepfor = randint(ifc->rp.minraint, ifc->rp.maxraint);
- if (dstknown > 0)
- sendra(fd, dst, 1, ifc);
- else
- sendra(fd, v6allnodesL, 1, ifc);
}
}
@@ -918,16 +898,18 @@
{
static char routeon[] = "iprouting 1";
- if (conf.recvra > 0)
+ mklladdr();
+
+ if(conf.recvra > 0)
recvra6();
- if (conf.sendra > 0) {
- if (write(conf.cfd, routeon, sizeof routeon - 1) < 0) {
+ if(conf.sendra > 0) {
+ if(write(conf.cfd, routeon, sizeof routeon - 1) < 0) {
warning("write (iprouting 1) failed: %r");
return;
}
sendra6();
- if (conf.recvra <= 0)
+ if(conf.recvra <= 0)
recvra6();
}
}
@@ -935,12 +917,7 @@
void
doipv6(int what)
{
- nip = nipifcs(conf.mpoint);
- if(!noconfig){
- lookforip(conf.mpoint);
- controldevice();
- binddevice();
- }
+ fprint(conf.rfd, "tag ra6");
switch (what) {
default:
--- a/sys/src/cmd/ip/ipconfig/main.c
+++ b/sys/src/cmd/ip/ipconfig/main.c
@@ -153,7 +153,6 @@
int myifc = -1;
char *dbfile;
char *ndboptions;
-int nip;
int noconfig;
int nodhcpwatch;
char optmagic[4] = { 0x63, 0x82, 0x53, 0x63 };
@@ -177,10 +176,8 @@
[Vpkt] "pkt",
};
-void adddefroute(char*, uchar*);
int addoption(char*);
void binddevice(void);
-void bootprequest(void);
void controldevice(void);
void dhcpquery(int, int);
void dhcprecv(void);
@@ -193,10 +190,8 @@
void getoptions(uchar*);
int ip4cfg(void);
int ip6cfg(void);
-void lookforip(char*);
void mkclientid(void);
void ndbconfig(void);
-int nipifcs(char*);
int openlisten(void);
uchar* optaddaddr(uchar*, int, uchar*);
uchar* optaddbyte(uchar*, int, int);
@@ -218,8 +213,6 @@
int parseverb(char*);
void pppbinddev(void);
void putndb(void);
-void usage(void);
-int validip(uchar*);
void
usage(void)
@@ -381,6 +374,19 @@
return dev;
}
+static int
+findifc(char *net, char *dev)
+{
+ Ipifc *nifc;
+
+ ifc = readipifc(net, ifc, -1);
+ for(nifc = ifc; nifc != nil; nifc = nifc->next)
+ if(strcmp(nifc->dev, dev) == 0)
+ return nifc->index;
+
+ return -1;
+}
+
static void
init(void)
{
@@ -391,6 +397,9 @@
fmtinstall('V', eipfmt);
nsec(); /* make sure time file is open before forking */
+ conf.cfd = -1;
+ conf.rfd = -1;
+
setnetmtpt(conf.mpoint, sizeof conf.mpoint, nil);
conf.cputype = getenv("cputype");
if(conf.cputype == nil)
@@ -574,10 +583,36 @@
argv0 = "ipconfig"; /* boot invokes us as tcp? */
action = parseargs(argc, argv);
+
+ myifc = findifc(conf.mpoint, conf.dev);
+ if(myifc < 0) {
+ switch(action){
+ default:
+ if(noconfig)
+ break;
+ /* bind new interface */
+ controldevice();
+ binddevice();
+ myifc = findifc(conf.mpoint, conf.dev);
+ case Vremove:
+ case Vunbind:
+ break;
+ }
+ if(myifc < 0)
+ sysfatal("interface not found for: %s", conf.dev);
+ } else {
+ /* open old interface */
+ binddevice();
+ }
+
switch(action){
case Vadd:
doadd(retry);
break;
+ case Vaddpref6:
+ case Vra6:
+ doipv6(action);
+ break;
case Vremove:
doremove();
break;
@@ -584,30 +619,14 @@
case Vunbind:
dounbind();
break;
- case Vaddpref6:
- case Vra6:
- doipv6(action);
- break;
}
- exits(0);
+ exits(nil);
}
void
doadd(int retry)
{
- /* get number of preexisting interfaces */
- nip = nipifcs(conf.mpoint);
- if(beprimary == -1 && nip == 0)
- beprimary = 1;
-
- /* get ipifc into name space and condition device for ip */
- if(!noconfig){
- lookforip(conf.mpoint);
- controldevice();
- binddevice();
- }
-
- if(!validip(conf.laddr))
+ if(!validip(conf.laddr)){
if(dondbconfig)
ndbconfig();
else if(ipv6auto){
@@ -615,9 +634,12 @@
dodhcp = 0;
} else
dodhcp = 1;
+ }
/* run dhcp if we need something */
if(dodhcp){
+ fprint(conf.rfd, "tag dhcp");
+
mkclientid();
dhcpquery(!noconfig, Sselecting);
}
@@ -654,84 +676,70 @@
void
doremove(void)
{
- char file[128];
- int cfd;
- Ipifc *nifc;
- Iplifc *lifc;
-
if(!validip(conf.laddr))
sysfatal("remove requires an address");
- ifc = readipifc(conf.mpoint, ifc, -1);
- for(nifc = ifc; nifc != nil; nifc = nifc->next){
- if(strcmp(nifc->dev, conf.dev) != 0)
- continue;
- for(lifc = nifc->lifc; lifc != nil; lifc = lifc->next){
- if(ipcmp(conf.laddr, lifc->ip) != 0)
- continue;
- if (validip(conf.mask) &&
- ipcmp(conf.mask, lifc->mask) != 0)
- continue;
- if (validip(conf.raddr) &&
- ipcmp(conf.raddr, lifc->net) != 0)
- continue;
-
- snprint(file, sizeof file, "%s/ipifc/%d/ctl",
- conf.mpoint, nifc->index);
- cfd = open(file, ORDWR);
- if(cfd < 0){
- warning("can't open %s: %r", conf.mpoint);
- continue;
- }
- if(fprint(cfd, "remove %I %M", lifc->ip, lifc->mask) < 0)
- warning("can't remove %I %M from %s: %r",
- lifc->ip, lifc->mask, file);
- }
- }
+ if(fprint(conf.cfd, "remove %I %M", conf.laddr, conf.mask) < 0)
+ warning("can't remove %I %M: %r", conf.laddr, conf.mask);
}
void
dounbind(void)
{
- Ipifc *nifc;
- char file[128];
- int cfd;
+ if(fprint(conf.cfd, "unbind") < 0)
+ warning("can't unbind %s: %r", conf.dev);
+}
- ifc = readipifc(conf.mpoint, ifc, -1);
- for(nifc = ifc; nifc != nil; nifc = nifc->next){
- if(strcmp(nifc->dev, conf.dev) == 0){
- snprint(file, sizeof file, "%s/ipifc/%d/ctl",
- conf.mpoint, nifc->index);
- cfd = open(file, ORDWR);
- if(cfd < 0){
- warning("can't open %s: %r", conf.mpoint);
- break;
- }
- if(fprint(cfd, "unbind") < 0)
- warning("can't unbind from %s: %r", file);
- break;
- }
- }
+int
+issrcspec(uchar *src, uchar *smask)
+{
+ return isv4(src)? memcmp(smask+IPv4off, IPnoaddr+IPv4off, 4): ipcmp(smask, IPnoaddr);
}
+void
+addroute(uchar *dst, uchar *mask, uchar *gate, uchar *laddr, uchar *src, uchar *smask)
+{
+ char *cmd;
-/* set the default route */
+ if(issrcspec(src, smask))
+ cmd = "add %I %M %I %I %I %M";
+ else
+ cmd = "add %I %M %I %I";
+ fprint(conf.rfd, cmd, dst, mask, gate, laddr, src, smask);
+}
void
-adddefroute(char *mpoint, uchar *gaddr)
+removeroute(uchar *dst, uchar *mask, uchar *src, uchar *smask)
{
- char buf[256];
- int cfd;
+ char *cmd;
- sprint(buf, "%s/iproute", mpoint);
- cfd = open(buf, ORDWR);
- if(cfd < 0)
- return;
-
- if(isv4(gaddr))
- fprint(cfd, "add 0 0 %I", gaddr);
+ if(issrcspec(src, smask))
+ cmd = "remove %I %M %I %M";
else
- fprint(cfd, "add 2000:: /3 %I", gaddr);
- close(cfd);
+ cmd = "remove %I %M";
+ fprint(conf.rfd, cmd, dst, mask, src, smask);
}
+void
+adddefroute(uchar *gaddr, uchar *laddr, uchar *src, uchar *smask)
+{
+ uchar dst[IPaddrlen], mask[IPaddrlen];
+ if(isv4(gaddr)){
+ parseip(dst, "0.0.0.0");
+ parseipmask(mask, "0.0.0.0");
+ if(src == nil)
+ src = dst;
+ if(smask == nil)
+ smask = mask;
+ } else {
+ parseip(dst, "2000::");
+ parseipmask(mask, "/3");
+ if(src == nil)
+ src = IPnoaddr;
+ if(smask == nil)
+ smask = IPnoaddr;
+ }
+ addroute(dst, mask, gaddr, laddr, src, smask);
+}
+
+
int
isether(void)
{
@@ -742,8 +750,13 @@
void
mklladdr(void)
{
- if(!isether() || myetheraddr(conf.hwa, conf.dev) != 0)
+ if(isether() && myetheraddr(conf.hwa, conf.dev) == 0){
+ conf.hwalen = 6;
+ conf.hwatype = 1;
+ } else {
genrandom(conf.hwa, sizeof(conf.hwa));
+ conf.hwatype = -1;
+ }
ea2lla(conf.laddr, conf.hwa);
}
@@ -765,18 +778,6 @@
}
}
-/* bind ip into the namespace */
-void
-lookforip(char *net)
-{
- char proto[64];
-
- snprint(proto, sizeof proto, "%s/ipifc", net);
- if(access(proto, 0) == 0)
- return;
- sysfatal("no ip stack bound onto %s", net);
-}
-
/* send some ctls to a device */
void
controldevice(void)
@@ -807,9 +808,15 @@
{
char buf[256];
- if(strcmp(conf.type, "ppp") == 0)
+ if(myifc >= 0){
+ /* open the old interface */
+ snprint(buf, sizeof buf, "%s/ipifc/%d/ctl", conf.mpoint, myifc);
+ conf.cfd = open(buf, ORDWR);
+ if(conf.cfd < 0)
+ sysfatal("open %s: %r", buf);
+ } else if(strcmp(conf.type, "ppp") == 0)
pppbinddev();
- else if(myifc < 0){
+ else {
/* get a new ip interface */
snprint(buf, sizeof buf, "%s/ipifc/clone", conf.mpoint);
conf.cfd = open(buf, ORDWR);
@@ -819,14 +826,9 @@
/* specify medium as ethernet, bind the interface to it */
if(fprint(conf.cfd, "bind %s %s", conf.type, conf.dev) < 0)
sysfatal("%s: bind %s %s: %r", buf, conf.type, conf.dev);
- } else {
- /* open the old interface */
- snprint(buf, sizeof buf, "%s/ipifc/%d/ctl", conf.mpoint, myifc);
- conf.cfd = open(buf, ORDWR);
- if(conf.cfd < 0)
- sysfatal("open %s: %r", buf);
}
-
+ snprint(buf, sizeof buf, "%s/iproute", conf.mpoint);
+ conf.rfd = open(buf, OWRITE);
}
/* add a logical interface to the ip stack */
@@ -857,8 +859,8 @@
return -1;
}
- if(beprimary==1 && validip(conf.gaddr))
- adddefroute(conf.mpoint, conf.gaddr);
+ if(validip(conf.gaddr) && isv4(conf.gaddr))
+ adddefroute(conf.gaddr, conf.laddr, conf.laddr, conf.mask);
return 0;
}
@@ -867,20 +869,15 @@
void
ipunconfig(void)
{
- char buf[256];
- int n;
-
if(!validip(conf.laddr))
return;
+
DEBUG("couldn't renew IP lease, releasing %I", conf.laddr);
- n = sprint(buf, "remove");
- n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
if(!validip(conf.mask))
ipmove(conf.mask, defmask(conf.laddr));
- n += snprint(buf+n, sizeof buf-n, " %I", conf.mask);
- write(conf.cfd, buf, n);
+ doremove();
ipmove(conf.laddr, IPnoaddr);
ipmove(conf.raddr, IPnoaddr);
@@ -1172,10 +1169,8 @@
break;
case Offer:
DEBUG("got offer from %V ", bp->siaddr);
- if(conf.state != Sselecting){
-// DEBUG("");
+ if(conf.state != Sselecting)
break;
- }
lease = optgetulong(bp->optdata, ODlease);
if(lease == 0){
/*
@@ -1731,33 +1726,6 @@
return;
write(fd, buf, p-buf);
close(fd);
-}
-
-/* return number of networks */
-int
-nipifcs(char *net)
-{
- int n;
- Ipifc *nifc;
- Iplifc *lifc;
-
- n = 0;
- ifc = readipifc(net, ifc, -1);
- for(nifc = ifc; nifc != nil; nifc = nifc->next){
- /*
- * ignore loopback devices when trying to
- * figure out if we're the primary interface.
- */
- if(strcmp(nifc->dev, "/dev/null") != 0)
- for(lifc = nifc->lifc; lifc != nil; lifc = lifc->next)
- if(validip(lifc->ip)){
- n++;
- break;
- }
- if(strcmp(nifc->dev, conf.dev) == 0)
- myifc = nifc->index;
- }
- return n;
}
/* return true if this is a valid v4 address */