diff --git a/sys/man/8/ipconfig b/sys/man/8/ipconfig index a8e750979..2e054abfd 100644 --- a/sys/man/8/ipconfig +++ b/sys/man/8/ipconfig @@ -16,6 +16,8 @@ ipconfig, rip, linklocal \- Internet configuration and routing .IR gateway ] .RB [ -h .IR host ] +.BR [ -i +.IR ipnet ] .RB [ -m .IR mtu ] .RB [ -o @@ -192,6 +194,15 @@ the hostname to add to DHCP requests. Some DHCP servers, such as the one used by Comcast, will not respond unless a correct hostname is in the request. .TP +.B i +when writing +.B /net/ndb +configuration, create an +.B ipnet= +tuple with the value of +.I ipnet +and the gathered network attributes. +.TP .B m the maximum IP packet size to use on this interface. .TP diff --git a/sys/src/cmd/ip/ipconfig/dhcpv6.c b/sys/src/cmd/ip/ipconfig/dhcpv6.c index 013ea4e10..0fe57b299 100644 --- a/sys/src/cmd/ip/ipconfig/dhcpv6.c +++ b/sys/src/cmd/ip/ipconfig/dhcpv6.c @@ -63,15 +63,59 @@ openlisten(void) } static int -transaction(int fd, int type, int timeout) +findopt(int id, uchar **sp, uchar *e) +{ + uchar *p; + int opt; + int len; + + p = *sp; + while(p + 4 <= e) { + opt = (int)p[0] << 8 | p[1]; + len = (int)p[2] << 8 | p[3]; + p += 4; + if(p + len > e) + break; + if(opt == id){ + *sp = p; + return len; + } + p += len; + } + return -1; +} + +static int +badstatus(int type, int opt, uchar *p, uchar *e) +{ + int len, status; + + len = findopt(13, &p, e); + if(len < 0) + return 0; + if(len < 2) + return 1; + status = (int)p[0] << 8 | p[1]; + if(status == 0) + return 0; + warning("dhcpv6: bad status in request/response type %x, option %d, status %d: %.*s", + type, opt, status, len - 2, (char*)p + 2); + return status; +} + +static int +transaction(int fd, int type, int irt, int retrans, int timeout) { union { Udphdr; uchar buf[4096]; } ipkt, opkt; + int tra, opt, len, status, sleepfor, jitter; uchar *p, *e, *x; - int tra, opt, len, sleepfor; + ulong t1, apflt; + + conf.lease = ~0UL; /* infinity */ tra = lrand() & 0xFFFFFF; @@ -98,8 +142,8 @@ transaction(int fd, int type, int timeout) /* IA for non-temporary address */ len = 12; - if(validip(conf.laddr)) - len += 4 + IPaddrlen + 2*4; + if(validv6prefix(conf.laddr)) + len += 4 + IPaddrlen+2*4; *p++ = 0x00; *p++ = 0x03; *p++ = len >> 8; *p++ = len; @@ -110,19 +154,53 @@ transaction(int fd, int type, int timeout) *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; if(len > 12){ *p++ = 0x00; *p++ = 0x05; - *p++ = 0x00; *p++ = IPaddrlen + 2*4; + *p++ = 0x00; *p++ = IPaddrlen+2*4; memmove(p, conf.laddr, IPaddrlen); p += IPaddrlen; memset(p, 0xFF, 2*4); p += 2*4; } + /* IA for prefix delegation */ + len = 12; + if(validv6prefix(conf.v6pref)) + len += 4 + 2*4+1+IPaddrlen; + *p++ = 0x00; *p++ = 0x19; + *p++ = len >> 8; + *p++ = len; + /* IAID */ + *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x02; /* lies */ + /* T1, T2 */ + *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; + *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; + if(len > 12){ + *p++ = 0x00; *p++ = 0x1a; + *p++ = 0x00; *p++ = 2*4+1+IPaddrlen; + + *p++ = conf.preflt >> 24; + *p++ = conf.preflt >> 16; + *p++ = conf.preflt >> 8; + *p++ = conf.preflt; + + *p++ = conf.validlt >> 24; + *p++ = conf.validlt >> 16; + *p++ = conf.validlt >> 8; + *p++ = conf.validlt; + + *p++ = conf.prefixlen; + + ipmove(p, conf.v6pref); + p += IPaddrlen; + } + /* Option Request */ *p++ = 0x00; *p++ = 0x06; *p++ = 0x00; *p++ = 0x02; *p++ = 0x00; *p++ = 0x17; /* DNS servers */ - if(sidlen > 0){ + /* server identifier */ + if(sidlen > 0 + && type != SOLICIT && type != CONFIRM && type != REBIND){ *p++ = 0x00; *p++ = 0x02; /* len */ *p++ = sidlen >> 8; @@ -132,9 +210,13 @@ transaction(int fd, int type, int timeout) } len = -1; - for(sleepfor = 500; timeout > 0; sleepfor <<= 1){ + for(sleepfor = irt; timeout > 0; sleepfor <<= 1){ DEBUG("sending dhcpv6 request %x", opkt.buf[Udphdrsize]); + jitter = sleepfor / 10; + if(jitter > 1) + sleepfor += nrand(jitter); + alarm(sleepfor); if(len < 0) write(fd, opkt.buf, p - opkt.buf); @@ -144,9 +226,14 @@ transaction(int fd, int type, int timeout) timeout -= sleepfor; if(len == 0) break; - + if(len < 0){ + if(--retrans == 0) + break; + continue; + } if(len < Udphdrsize+4) continue; + if(ipkt.buf[Udphdrsize+1] != ((tra>>16)&0xFF) || ipkt.buf[Udphdrsize+2] != ((tra>>8)&0xFF) || ipkt.buf[Udphdrsize+3] != ((tra>>0)&0xFF)) @@ -158,6 +245,8 @@ transaction(int fd, int type, int timeout) switch(type){ case ADVERTISE << 8 | SOLICIT: case REPLY << 8 | REQUEST: + case REPLY << 8 | RENEW: + case REPLY << 8 | REBIND: goto Response; default: return -1; @@ -177,74 +266,174 @@ Response: if (x > e) return -1; - DEBUG("got dhcpv6 option %x: [%d] %.*H", opt, len, len, p); + DEBUG("got dhcpv6 option %d: [%d] %.*H", opt, len, len, p); switch(opt){ - case 0x01: /* client identifier */ + case 1: /* client identifier */ continue; - case 0x02: /* server identifier */ + case 2: /* server identifier */ if(len < 1 || len > sizeof(sid)) break; sidlen = len; memmove(sid, p, sidlen); continue; - case 0x03: /* IA for non-temporary address */ + case 3: /* IA for non-temporary address */ if(p+12 > x) break; + + t1 = (ulong)p[4] << 24 | + (ulong)p[5] << 16 | + (ulong)p[6] << 8 | + (ulong)p[7]; + /* skip IAID, T1, T2 */ p += 12; - /* find IA Address option */ - while(p + 4 <= x) { - opt = (int)p[0] << 8 | p[1]; - len = (int)p[2] << 8 | p[3]; - p += 4; - if(p + len > x) - break; - if(opt == 5) - break; - p += len; - } + + status = badstatus(type, opt, p, x); + if(status != 0) + return -status; + /* IA Addresss */ - if(opt != 5) + if(findopt(5, &p, x) < IPaddrlen + 2*4) break; - if(len < IPaddrlen) - break; - memmove(conf.laddr, p, IPaddrlen); + + ipmove(conf.laddr, p); + memset(conf.mask, 0xFF, IPaddrlen); + p += IPaddrlen; + + /* preferred lifetime of IA Address */ + apflt = (ulong)p[0] << 24 | + (ulong)p[1] << 16 | + (ulong)p[2] << 8 | + (ulong)p[3]; + + /* adjust lease */ + if(t1 != 0 && t1 < conf.lease) + conf.lease = t1; + if(apflt != 0 && apflt < conf.lease) + conf.lease = apflt; + continue; - case 0x17: /* dns servers */ + case 13: /* status */ + status = badstatus(type, opt, p - 4, x); + if(status != 0) + return -status; + continue; + case 23: /* dns servers */ if(len % IPaddrlen) break; addaddrs(conf.dns, sizeof(conf.dns), p, len); + continue; + case 25: /* IA for prefix delegation */ + if(p+12 > x) + break; + + t1 = (ulong)p[4] << 24 | + (ulong)p[5] << 16 | + (ulong)p[6] << 8 | + (ulong)p[7]; + + /* skip IAID, T1, T2 */ + p += 12; + + status = badstatus(type, opt, p, x); + if(status != 0){ + if(type == (ADVERTISE << 8 | SOLICIT)) + continue; + return -status; + } + + /* IA Prefix */ + if(findopt(26, &p, x) < 2*4+1+IPaddrlen) + break; + + conf.preflt = (ulong)p[0] << 24 | + (ulong)p[1] << 16 | + (ulong)p[2] << 8 | + (ulong)p[3]; + conf.validlt = (ulong)p[4] << 24 | + (ulong)p[5] << 16 | + (ulong)p[6] << 8 | + (ulong)p[7]; + p += 8; + if(conf.preflt > conf.validlt) + break; + + conf.prefixlen = *p++ & 127; + genipmask(conf.v6mask, conf.prefixlen); + maskip(p, conf.v6mask, conf.v6pref); + + /* adjust lease */ + if(t1 != 0 && t1 < conf.lease) + conf.lease = t1; + if(conf.preflt != 0 && conf.preflt < conf.lease) + conf.lease = conf.preflt; + continue; default: - DEBUG("unknown dhcpv6 option %x", opt); + DEBUG("unknown dhcpv6 option: %d", opt); continue; } - warning("dhcpv6: malformed option %x: [%d] %.*H", opt, len, len, x-len); + warning("dhcpv6: malformed option %d: [%d] %.*H", opt, len, len, x-len); } - return 0; } -void -dhcpv6query(void) +int +dhcpv6query(int renew) { int fd; - ipmove(conf.laddr, IPnoaddr); - memset(conf.mask, 0xFF, IPaddrlen); + if(!renew){ + ipmove(conf.laddr, IPnoaddr); + ipmove(conf.v6pref, IPnoaddr); + ipmove(conf.v6mask, IPnoaddr); + conf.prefixlen = 0; + conf.preflt = 0; + conf.validlt = 0; + conf.autoflag = 0; + conf.onlink = 0; + } if(conf.duidlen <= 0) - return; + return -1; + fd = openlisten(); if(fd < 0) - return; - if(transaction(fd, SOLICIT, 5000) < 0) - goto out; - if(!validip(conf.laddr)) - goto out; - if(transaction(fd, REQUEST, 10000) < 0) - goto out; -out: + return -1; + + if(renew){ + if(!validv6prefix(conf.laddr)) + goto fail; + /* + * the standard says 600 seconds for maxtimeout, + * but this seems ridiculous. better start over. + */ + if(transaction(fd, RENEW, 10*1000, 0, 30*1000) < 0){ + if(!validv6prefix(conf.laddr)) + goto fail; + if(transaction(fd, REBIND, 10*1000, 0, 30*1000) < 0) + goto fail; + } + } else { + /* + * the standard says SOL_MAX_RT is 3600 seconds, + * but it is better to fail quickly here and wait + * for the next router advertisement. + */ + if(transaction(fd, SOLICIT, 1000, 0, 10*1000) < 0) + goto fail; + if(!validv6prefix(conf.laddr)) + goto fail; + if(transaction(fd, REQUEST, 1000, 10, 30*1000) < 0) + goto fail; + } + if(!validv6prefix(conf.laddr)) + goto fail; close(fd); + return 0; +fail: + close(fd); + return -1; + } diff --git a/sys/src/cmd/ip/ipconfig/ipconfig.h b/sys/src/cmd/ip/ipconfig/ipconfig.h index 706f81310..4bb1144a1 100644 --- a/sys/src/cmd/ip/ipconfig/ipconfig.h +++ b/sys/src/cmd/ip/ipconfig/ipconfig.h @@ -45,6 +45,7 @@ struct Conf uchar laddr[IPaddrlen]; uchar mask[IPaddrlen]; uchar raddr[IPaddrlen]; + uchar dns[8*IPaddrlen]; uchar fs[2*IPaddrlen]; uchar auth[2*IPaddrlen]; @@ -69,6 +70,7 @@ struct Conf /* * IPv6 */ + uchar v6router[IPaddrlen]; /* router-advertisement related */ uchar sendra; @@ -86,6 +88,7 @@ struct Conf /* prefix related */ uchar lladdr[IPaddrlen]; uchar v6pref[IPaddrlen]; + uchar v6mask[IPaddrlen]; int prefixlen; uchar onlink; /* flag: address is `on-link' */ uchar autoflag; /* flag: autonomous */ @@ -118,13 +121,14 @@ extern int dupl_disc; extern int nodhcpwatch; extern int sendhostname; extern char *ndboptions; +extern char *ipnet; /* put ipnet= tuple in ndb for raddr */ void usage(void); int ip4cfg(void); void ipunconfig(void); -void adddefroute(uchar*, uchar*, uchar*, uchar*); -void deldefroute(uchar*, uchar*, uchar*, uchar*); +void adddefroute(uchar*, uchar*, uchar*, uchar*, uchar*); +void deldefroute(uchar*, uchar*, uchar*, uchar*, uchar*); int myip(Ipifc*, uchar*); int isether(void); @@ -163,9 +167,10 @@ void doipv6(int); void ea2lla(uchar *lla, uchar *ea); int findllip(uchar *ip, Ipifc *ifc); int ip6cfg(void); +int validv6prefix(uchar *ip); +void genipmask(uchar *mask, int len); /* * DHCPv6 */ -void dhcpv6init(void); -void dhcpv6query(void); +int dhcpv6query(int); diff --git a/sys/src/cmd/ip/ipconfig/ipv6.c b/sys/src/cmd/ip/ipconfig/ipv6.c index cdf5ad8e9..4fe6c02c1 100644 --- a/sys/src/cmd/ip/ipconfig/ipv6.c +++ b/sys/src/cmd/ip/ipconfig/ipv6.c @@ -198,6 +198,7 @@ parse6pref(int argc, char **argv) sysfatal("bad address %s", argv[0]); break; } + genipmask(conf.v6mask, conf.prefixlen); DEBUG("parse6pref: pref %I len %d", conf.v6pref, conf.prefixlen); } @@ -391,7 +392,7 @@ Again: if(validip(conf.gaddr) && !isv4(conf.gaddr) && ipcmp(conf.gaddr, conf.laddr) != 0 && ipcmp(conf.gaddr, conf.lladdr) != 0) - adddefroute(conf.gaddr, conf.laddr, conf.laddr, conf.mask); + adddefroute(conf.gaddr, conf.laddr, conf.laddr, conf.raddr, conf.mask); return 0; } @@ -530,8 +531,8 @@ masklen(uchar *mask) return len; } -static void -genipmkask(uchar *mask, int len) +void +genipmask(uchar *mask, int len) { memset(mask, 0, IPaddrlen); if(len < 0) @@ -563,11 +564,27 @@ struct Route static Route *routelist; +int +validv6prefix(uchar *ip) +{ + if(!validip(ip)) + return 0; + if(isv4(ip)) + return 0; + if(ipcmp(ip, v6loopback) == 0) + return 0; + if(ISIPV6MCAST(ip)) + return 0; + if(ISIPV6LINKLOCAL(ip)) + return 0; + return 1; +} + /* * host receiving a router advertisement calls this */ static int -recvrahost(uchar buf[], int pktlen) +recvrahost(uchar buf[], int pktlen, ulong now) { char dnsdomain[sizeof(conf.dnsdomain)]; int m, n, optype, seen; @@ -576,9 +593,9 @@ recvrahost(uchar buf[], int pktlen) Prefixopt *prfo; Ipaddrsopt *addrso; Routeradv *ra; + uchar raddr[IPaddrlen]; uchar hash[SHA1dlen]; Route *r, **rr; - ulong now; m = sizeof *ra; ra = (Routeradv*)buf; @@ -590,6 +607,13 @@ recvrahost(uchar buf[], int pktlen) DEBUG("got RA from %I on %s; flags %x", ra->src, conf.dev, ra->mor); + /* + * ignore all non-managed-flag router-advertisements + * when dhcpv6 is active so we do not trash conf data. + */ + if(dodhcp && conf.state && (MFMASK & ra->mor) == 0) + return -1; + conf.ttl = ra->cttl; conf.mflag = (MFMASK & ra->mor) != 0; conf.oflag = (OCMASK & ra->mor) != 0; @@ -598,6 +622,8 @@ recvrahost(uchar buf[], int pktlen) conf.rxmitra = nhgetl(ra->rxmtimer); conf.linkmtu = DEFMTU; + ipmove(conf.v6router, conf.routerlt? ra->src: IPnoaddr); + memset(conf.dns, 0, sizeof(conf.dns)); memset(conf.fs, 0, sizeof(conf.fs)); memset(conf.auth, 0, sizeof(conf.auth)); @@ -657,8 +683,6 @@ recvrahost(uchar buf[], int pktlen) issuebasera6(&conf); - now = time(nil); - /* remove expired default routes */ m = 0; for(rr = &routelist; (r = *rr) != nil;){ @@ -667,8 +691,10 @@ recvrahost(uchar buf[], int pktlen) || r->routerlt != ~0UL && r->routerlt < now-r->time){ DEBUG("purging RA from %I on %s; pfx %I %M", r->src, conf.dev, r->laddr, r->mask); - if(!noconfig && validip(r->gaddr)) - deldefroute(r->gaddr, conf.lladdr, r->laddr, r->mask); + if(validip(r->gaddr)){ + maskip(r->laddr, r->mask, raddr); + deldefroute(r->gaddr, conf.lladdr, r->laddr, raddr, r->mask); + } *rr = r->next; free(r); continue; @@ -680,6 +706,10 @@ recvrahost(uchar buf[], int pktlen) /* remove expired prefixes */ issuedel6(&conf); + /* managed netork: prefixes are acquired with dhcpv6 */ + if(dodhcp && conf.mflag) + return 0; + /* process new prefixes */ m = sizeof *ra; while(pktlen - m >= 8) { @@ -704,18 +734,15 @@ recvrahost(uchar buf[], int pktlen) || conf.prefixlen > 64) continue; - genipmkask(conf.mask, conf.prefixlen); - maskip(prfo->pref, conf.mask, conf.v6pref); - if(!validip(conf.v6pref) - || isv4(conf.v6pref) - || ipcmp(conf.v6pref, v6loopback) == 0 - || ISIPV6MCAST(conf.v6pref) - || ISIPV6LINKLOCAL(conf.v6pref)) + genipmask(conf.v6mask, conf.prefixlen); + maskip(prfo->pref, conf.v6mask, conf.v6pref); + if(!validv6prefix(conf.v6pref)) continue; - + ipmove(conf.raddr, conf.v6pref); + ipmove(conf.mask, conf.v6mask); memmove(conf.laddr, conf.v6pref, 8); memmove(conf.laddr+8, conf.lladdr+8, 8); - ipmove(conf.gaddr, (prfo->lar & RFMASK) != 0? prfo->pref: ra->src); + ipmove(conf.gaddr, (prfo->lar & RFMASK) != 0? prfo->pref: conf.v6router); conf.onlink = (prfo->lar & OLMASK) != 0; conf.autoflag = (prfo->lar & AFMASK) != 0; conf.validlt = nhgetl(prfo->validlt); @@ -723,8 +750,7 @@ recvrahost(uchar buf[], int pktlen) if(conf.preflt > conf.validlt) continue; - if(conf.routerlt == 0 - || conf.preflt == 0 + if(conf.preflt == 0 || isula(conf.laddr) || ipcmp(conf.gaddr, conf.laddr) == 0 || ipcmp(conf.gaddr, conf.lladdr) == 0) @@ -754,8 +780,8 @@ recvrahost(uchar buf[], int pktlen) seen = memcmp(r->hash, hash, SHA1dlen) == 0; if(!seen && validip(r->gaddr) && ipcmp(r->gaddr, conf.gaddr) != 0){ DEBUG("changing router %I->%I", r->gaddr, conf.gaddr); - if(!noconfig) - deldefroute(r->gaddr, conf.lladdr, r->laddr, r->mask); + maskip(r->laddr, r->mask, raddr); + deldefroute(r->gaddr, conf.lladdr, r->laddr, raddr, r->mask); } } else { seen = 0; @@ -790,19 +816,13 @@ recvrahost(uchar buf[], int pktlen) DEBUG("got prefix %I %M via %I on %s", conf.v6pref, conf.mask, conf.gaddr, conf.dev); - if(noconfig) - continue; - if(validip(conf.gaddr)) - adddefroute(conf.gaddr, conf.lladdr, conf.laddr, conf.mask); + adddefroute(conf.gaddr, conf.lladdr, conf.laddr, conf.raddr, conf.mask); putndb(1); refresh(); } - /* pass gateway to dhcpv6 if it is managed network */ - ipmove(conf.gaddr, conf.mflag? ra->src: IPnoaddr); - return 0; } @@ -814,6 +834,7 @@ recvra6(void) { int fd, n, sendrscnt, gotra, pktcnt, sleepfor; uchar buf[4096]; + ulong now; fd = dialicmpv6(v6allnodesL, ICMP6_RA); if(fd < 0) @@ -834,15 +855,16 @@ recvra6(void) procsetname("recvra6 on %s %I", conf.dev, conf.lladdr); notify(catch); + gotra = 0; +restart: sendrscnt = 0; if(recvra6on(myifc) == IsHostRecv){ sendrs(fd, v6allroutersL); sendrscnt = Maxv6rss; } - - gotra = 0; pktcnt = 0; sleepfor = Minv6interradelay; + conf.state = 0; /* dhcpv6 off */ for (;;) { alarm(sleepfor); @@ -858,6 +880,7 @@ recvra6(void) pktcnt = 1; } sleepfor = Maxv6radelay; + now = time(nil); myifc = readipifc(conf.mpoint, myifc, myifc->index); if(myifc == nil) { @@ -884,34 +907,104 @@ recvra6(void) sendrs(fd, v6allroutersL); sleepfor = V6rsintvl + nrand(100); } else if(!gotra) { - gotra = 1; warning("recvra6: no router advs after %d sols on %s", Maxv6rss, conf.dev); rendezvous(recvra6, (void*)0); - } + } else if(dodhcp && conf.state) + goto renewdhcp; continue; } - if(recvrahost(buf, n) < 0) + if(recvrahost(buf, n, now) < 0) continue; - /* got at least initial ra; no whining */ - if(!gotra){ - gotra = 1; - if(dodhcp && conf.mflag){ - dhcpv6query(); - if(noconfig || !validip(conf.laddr)) + if(dodhcp && conf.mflag){ + if(conf.state){ + if(validip(conf.gaddr) && ipcmp(conf.gaddr, conf.v6router) != 0){ + warning("dhcpv6: default router changed %I -> %I on %s", + conf.gaddr, conf.v6router, conf.dev); + } else { +renewdhcp: + /* when renewing, wait for lease to time-out */ + if(now < conf.timeout) + continue; + } + } + if(dhcpv6query(conf.state) < 0){ + if(conf.state == 0) continue; + + DEBUG("dhcpv6 failed renew for %I with prefix %I %M via %I on %s", + conf.laddr, conf.v6pref, conf.v6mask, conf.gaddr, conf.dev); + + if(!noconfig){ + fprint(conf.rfd, "tag dhcp"); + if(validip(conf.gaddr)) + if(conf.preflt && validv6prefix(conf.v6pref) && !isula(conf.v6pref)) + deldefroute(conf.gaddr, conf.lladdr, IPnoaddr, conf.v6pref, conf.v6mask); + ipunconfig(); + fprint(conf.rfd, "tag ra6"); + } + /* restart sending router solitications */ + conf.state = 0; + goto restart; + } + now = time(nil); + conf.state = 1; /* dhcpv6 active */ + sendrscnt = 0; /* stop sending router solicitations */ + + DEBUG("dhcpv6 got %I with prefix %I %M via %I on %s for lease %lud", + conf.laddr, conf.v6pref, conf.v6mask, conf.v6router, conf.dev, conf.lease); + + if(!noconfig){ fprint(conf.rfd, "tag dhcp"); + + if(validip(conf.gaddr) && ipcmp(conf.gaddr, conf.v6router) != 0){ + deldefroute(conf.gaddr, conf.lladdr, conf.laddr, conf.raddr, conf.mask); + if(conf.preflt && validv6prefix(conf.v6pref) && !isula(conf.v6pref)) + deldefroute(conf.gaddr, conf.lladdr, IPnoaddr, conf.v6pref, conf.v6mask); + } + ipmove(conf.gaddr, conf.v6router); + if(ip6cfg() < 0){ fprint(conf.rfd, "tag ra6"); continue; } putndb(1); + if(conf.preflt && validv6prefix(conf.v6pref)){ + uchar save[IPaddrlen]; + + /* if we got a delegated prefix, add the default route */ + if(validip(conf.gaddr) && !isula(conf.v6pref)) + adddefroute(conf.gaddr, conf.lladdr, IPnoaddr, conf.v6pref, conf.v6mask); + + /* store prefix info in /net/ndb */ + ipmove(save, conf.laddr); + ipmove(conf.laddr, IPnoaddr); /* we don't have an address there */ + ipmove(conf.raddr, conf.v6pref); + ipmove(conf.mask, conf.v6mask); + putndb(1); + ipmove(conf.laddr, save); + ipmove(conf.raddr, save); /* was same as laddr as /128 */ + memset(conf.mask, 0xFF, IPaddrlen); + } refresh(); - rendezvous(recvra6, (void*)1); + fprint(conf.rfd, "tag ra6"); + } + /* infinity */ + if(conf.lease == ~0UL){ + if(!gotra) + rendezvous(recvra6, (void*)1); exits(nil); } + if(conf.lease < 60) + conf.lease = 60; + conf.timeout = now + conf.lease; + } + + /* got at least initial ra; no whining */ + if(!gotra){ + gotra = 1; rendezvous(recvra6, (void*)1); } } @@ -1004,11 +1097,7 @@ sendra(int fd, uchar *dst, int rlt, Ipifc *ifc, Ndb *db) 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)) + if(!validv6prefix(lifc->ip)) continue; prfo = (Prefixopt*)&buf[pktlen]; diff --git a/sys/src/cmd/ip/ipconfig/main.c b/sys/src/cmd/ip/ipconfig/main.c index ee144dab5..bce0d1fec 100644 --- a/sys/src/cmd/ip/ipconfig/main.c +++ b/sys/src/cmd/ip/ipconfig/main.c @@ -30,6 +30,7 @@ int dodhcp; int nodhcpwatch; int sendhostname; char *ndboptions; +char *ipnet; int ipv6auto; int dupl_disc = 1; /* flag: V6 duplicate neighbor discovery */ @@ -58,7 +59,7 @@ void usage(void) { fprint(2, "usage: %s [-6dDGnNOpPrtuXy][-b baud][-c ctl]* [-U duid] [-g gw]" - "[-h host][-m mtu][-s dns]...\n" + "[-h host][-i ipnet][-m mtu][-s dns]...\n" "\t[-f dbfile][-x mtpt][-o dhcpopt] type dev [verb] [laddr [mask " "[raddr [fs [auth]]]]]\n", argv0); exits("usage"); @@ -400,6 +401,9 @@ main(int argc, char **argv) sysfatal("bad hostname"); sendhostname = 1; break; + case 'i': + ipnet = EARGF(usage()); + break; case 'm': conf.mtu = atoi(EARGF(usage())); break; @@ -569,7 +573,7 @@ dodel(void) return; if(validip(conf.gaddr)) - deldefroute(conf.gaddr, conf.laddr, conf.laddr, conf.mask); + deldefroute(conf.gaddr, conf.laddr, conf.laddr, conf.raddr, conf.mask); /* use "remove" verb instead of "del" for older kernels */ if(conf.cfd >= 0 && fprint(conf.cfd, "remove %I %M", conf.laddr, conf.mask) < 0) @@ -595,6 +599,8 @@ openiproute(void) { char buf[127]; + if(noconfig) + return; snprint(buf, sizeof buf, "%s/iproute", conf.mpoint); conf.rfd = open(buf, OWRITE); } @@ -684,7 +690,7 @@ ip4cfg(void) if(validip(conf.gaddr) && isv4(conf.gaddr) && ipcmp(conf.gaddr, conf.laddr) != 0) - adddefroute(conf.gaddr, conf.laddr, conf.laddr, conf.mask); + adddefroute(conf.gaddr, conf.laddr, conf.laddr, conf.laddr, conf.mask); if(tflag) fprint(conf.cfd, "iprouting 1"); @@ -754,37 +760,43 @@ putndb(int doadd) Ndb *db; int fd; - if(beprimary == 0) + if(beprimary == 0 || noconfig) return; p = buf; e = buf + sizeof buf; if(doadd){ - p = seprint(p, e, "ip=%I ipmask=%M ipgw=%I\n", - conf.laddr, conf.mask, conf.gaddr); - if(np = strchr(conf.hostname, '.')){ - if(*conf.domainname == 0) - strcpy(conf.domainname, np+1); - *np = 0; + if(ipnet != nil && validip(conf.raddr)){ + p = seprint(p, e, "ipnet=%s ip=%I ipmask=%M ipgw=%I\n", + ipnet, conf.raddr, conf.mask, conf.gaddr); + } + if(validip(conf.laddr)){ + p = seprint(p, e, "ip=%I ipmask=%M ipgw=%I\n", + conf.laddr, conf.mask, conf.gaddr); + if(np = strchr(conf.hostname, '.')){ + if(*conf.domainname == 0) + strcpy(conf.domainname, np+1); + *np = 0; + } + if(*conf.hostname) + p = seprint(p, e, "\tsys=%U\n", conf.hostname); + if(*conf.domainname) + p = seprint(p, e, "\tdom=%U.%U\n", + conf.hostname, conf.domainname); + if(*conf.dnsdomain) + p = putnames(p, e, "\tdnsdomain", conf.dnsdomain); + if(validip(conf.dns)) + p = putaddrs(p, e, "\tdns", conf.dns, sizeof conf.dns); + if(validip(conf.fs)) + p = putaddrs(p, e, "\tfs", conf.fs, sizeof conf.fs); + if(validip(conf.auth)) + p = putaddrs(p, e, "\tauth", conf.auth, sizeof conf.auth); + if(validip(conf.ntp)) + p = putaddrs(p, e, "\tntp", conf.ntp, sizeof conf.ntp); + if(ndboptions) + p = seprint(p, e, "%s\n", ndboptions); } - if(*conf.hostname) - p = seprint(p, e, "\tsys=%U\n", conf.hostname); - if(*conf.domainname) - p = seprint(p, e, "\tdom=%U.%U\n", - conf.hostname, conf.domainname); - if(*conf.dnsdomain) - p = putnames(p, e, "\tdnsdomain", conf.dnsdomain); - if(validip(conf.dns)) - p = putaddrs(p, e, "\tdns", conf.dns, sizeof conf.dns); - if(validip(conf.fs)) - p = putaddrs(p, e, "\tfs", conf.fs, sizeof conf.fs); - if(validip(conf.auth)) - p = putaddrs(p, e, "\tauth", conf.auth, sizeof conf.auth); - if(validip(conf.ntp)) - p = putaddrs(p, e, "\tntp", conf.ntp, sizeof conf.ntp); - if(ndboptions) - p = seprint(p, e, "%s\n", ndboptions); } /* for myip() */ @@ -797,10 +809,11 @@ putndb(int doadd) while((t = ndbparse(db)) != nil){ uchar ip[IPaddrlen]; - if(ndbfindattr(t, t, "ipnet") != nil - || (nt = ndbfindattr(t, t, "ip")) == nil - || parseip(ip, nt->val) == -1 - || ipcmp(ip, conf.laddr) != 0 && myip(allifcs, ip)){ + nt = ndbfindattr(t, t, "ipnet"); + if(nt != nil && (ipnet == nil || strcmp(nt->val, ipnet) != 0) + || nt == nil && ((nt = ndbfindattr(t, t, "ip")) == nil + || parseip(ip, nt->val) == -1 + || ipcmp(ip, conf.laddr) != 0 && myip(allifcs, ip))){ if(p > buf) p = seprint(p, e, "\n"); for(nt = t; nt != nil; nt = nt->entry) @@ -843,7 +856,7 @@ routectl(char *cmd, uchar *dst, uchar *mask, uchar *gate, char *flags, uchar *ia } static void -defroutectl(char *cmd, uchar *gaddr, uchar *ia, uchar *src, uchar *smask) +defroutectl(char *cmd, uchar *gaddr, uchar *ia, uchar *laddr, uchar *src, uchar *smask) { uchar dst[IPaddrlen], mask[IPaddrlen]; @@ -870,21 +883,21 @@ defroutectl(char *cmd, uchar *gaddr, uchar *ia, uchar *src, uchar *smask) } /* add source specific route for us */ - if(validip(src)) - routectl(cmd, dst, mask, gaddr, "", ia, src, IPallbits); + if(validip(laddr)) + routectl(cmd, dst, mask, gaddr, "", ia, laddr, IPallbits); } void -adddefroute(uchar *gaddr, uchar *ia, uchar *src, uchar *smask) +adddefroute(uchar *gaddr, uchar *ia, uchar *laddr, uchar *src, uchar *smask) { - defroutectl("add", gaddr, ia, src, smask); + defroutectl("add", gaddr, ia, laddr, src, smask); } void -deldefroute(uchar *gaddr, uchar *ia, uchar *src, uchar *smask) +deldefroute(uchar *gaddr, uchar *ia, uchar *laddr, uchar *src, uchar *smask) { /* use "remove" verb instead of "del" for older kernels */ - defroutectl("remove", gaddr, ia, src, smask); + defroutectl("remove", gaddr, ia, laddr, src, smask); } void @@ -893,6 +906,9 @@ refresh(void) char file[64]; int fd; + if(noconfig) + return; + snprint(file, sizeof file, "%s/cs", conf.mpoint); if((fd = open(file, OWRITE)) >= 0){ write(fd, "refresh", 7);