mirror of
git://git.9front.org/plan9front/plan9front
synced 2025-01-12 11:10:06 +00:00
ip/ipconfig: implement dhcpv6 prefix delegation, dynamic client
Implement prefix delegation by requesting a prefix and populate ipnet=val entry (val passed from -i option). Before, DHCPv6 was just implemented for stateless one-shot operation, just exiting once we got out IA address. Moodies mediacom-enterprise-enterprise-ISP... ... they actually do enterprise-grade dyanmic dhcpv6 so here we are, implementing renewals...
This commit is contained in:
parent
3e4e1b0211
commit
5f59652ae1
5 changed files with 442 additions and 132 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue