ref: cbf5d3dc340da5b96cd1282e622a3f862c5b103e
parent: 169aa63ec5a670d0c72b7e9fb747e16d76b718c3
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun May 21 13:48:42 EDT 2023
ip/ipconfig: initial dhcpv6 support, clean default-routes and /net/ndb on remove This adds a very basic (probably wrong) DHCPv6 client, to handle the "managed"-flag in IPv6 router solicitations. We add -U option to pass the DHCPv6 client id as well as an -s flag to manually add a dns server (because ppp is going to call ipconfig to handle all the configuration and write-back to /net/ndb in the future). Have the remove command also remove default routes and /net/ndb entries. (needed by ppp).
--- a/sys/man/8/ipconfig
+++ b/sys/man/8/ipconfig
@@ -6,6 +6,8 @@
.ti -0.25i
.B ip/ipconfig
.RB [ -6DGNOPdnprtuX ]
+.RB [ -U
+.IR duid ]
.RB [ -b
.IR baud ]
.RB [ -c
@@ -18,6 +20,8 @@
.IR mtu ]
.RB [ -o
.IR dhcp-opt ]
+.RB [ -s
+.IR dnsserver ]
.RB [ -f
.IR dbfile ]
.RB [ -x
@@ -160,6 +164,11 @@
.TP
.B d
use DHCP to determine any unspecified configuration parameters.
+For the
+.B ra6
+verb with non-zero
+.BR recvra ,
+this enables DHCPv6 address configuration.
.TP
.B D
turn on debugging.
@@ -197,7 +206,7 @@
.I local
IP address or if
.I local
-is omited and the device is an ethernet then all IP parameters
+is omitted and the device is an ethernet then all IP parameters
associated with the MAC address. IPv6 addresses are added only
if a IPv6 link-local address exists on the interface or the
.B 6
@@ -223,10 +232,25 @@
.I ipconfig
instead to fork a background process that keeps trying forever.
.TP
+.B s
+add
+.I dnsserver
+to the
+.B /net/ndb
+configuration.
+.TP
.B t
enable source address translation on the interface and default route.
-(only usefull for IPv4).
+(only useful for IPv4).
.TP
+.B U
+specify the DHCPv6 client identifier.
+When omitted, the MAC address is used to generate a link-layer
+based duid (DUID-LL).
+Note that the
+.B -d
+flag must also be given to enable DHCPv6.
+.TP
.B u
disable IPv6 duplicate discovery detection,
which removes any existing ARP table entry for one of our IPv6 addresses
@@ -247,7 +271,7 @@
.TP
.B o
adds
-.I dhcpoption
+.I dhcp-opt
to the list of paramters requested of the DHCP server. The
result will appear in
.B /net/ndb
--- a/sys/src/cmd/ip/ipconfig/dhcp.c
+++ b/sys/src/cmd/ip/ipconfig/dhcp.c
@@ -287,7 +287,7 @@
* leave everything we've learned somewhere that
* other procs can find it.
*/
- putndb();
+ putndb(1);
refresh();
}
}
--- /dev/null
+++ b/sys/src/cmd/ip/ipconfig/dhcpv6.c
@@ -1,0 +1,233 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ip.h>
+#include <ndb.h>
+#include "ipconfig.h"
+
+enum {
+ SOLICIT = 1,
+ ADVERTISE,
+ REQUEST,
+ CONFIRM,
+ RENEW,
+ REBIND,
+ REPLY,
+ RELEASE,
+ DECLINE,
+ RECONFIGURE,
+ INFOREQ,
+ RELAYFORW,
+ RELAYREPL,
+};
+
+static uchar v6dhcpservers[IPaddrlen] = {
+ 0xff, 0x02, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 1, 0, 2,
+};
+
+static uchar sid[256];
+static int sidlen;
+
+static int
+openlisten(void)
+{
+ int n, fd, cfd;
+ char data[128], devdir[40];
+
+ sprint(data, "%s/udp!%I!546", conf.mpoint, conf.lladdr);
+ for (n = 0; (cfd = announce(data, devdir)) < 0; n++) {
+ if(!noconfig)
+ sysfatal("can't announce for dhcp: %r");
+
+ /* might be another client - wait and try again */
+ warning("can't announce %s: %r", data);
+ sleep(jitter());
+ if(n > 10)
+ return -1;
+ }
+
+ if(fprint(cfd, "headers") < 0)
+ sysfatal("can't set header mode: %r");
+
+ fprint(cfd, "ignoreadvice");
+
+ sprint(data, "%s/data", devdir);
+ fd = open(data, ORDWR);
+ if(fd < 0)
+ sysfatal("open %s: %r", data);
+ close(cfd);
+ return fd;
+}
+
+static int
+transaction(int fd, int type, int timeout)
+{
+ union {
+ Udphdr;
+ uchar buf[4096];
+ } ipkt, opkt;
+
+ uchar *p, *e, *x;
+ int tra, opt, len, sleepfor;
+
+ tra = lrand() & 0xFFFFFF;
+
+ ipmove(opkt.laddr, conf.lladdr);
+ ipmove(opkt.raddr, v6dhcpservers);
+ ipmove(opkt.ifcaddr, conf.lladdr);
+ hnputs(opkt.lport, 546);
+ hnputs(opkt.rport, 547);
+
+ p = opkt.buf + Udphdrsize;
+
+ *p++ = type;
+ *p++ = tra >> 16;
+ *p++ = tra >> 8;
+ *p++ = tra >> 0;
+
+ /* client identifier */
+ *p++ = 0x00; *p++ = 0x01;
+ /* len */
+ *p++ = conf.duidlen >> 8;
+ *p++ = conf.duidlen;
+ memmove(p, conf.duid, conf.duidlen);
+ p += conf.duidlen;
+
+ /* IA for non-temporary address */
+ len = 12;
+ if(validip(conf.laddr))
+ len += 4 + IPaddrlen + 2*4;
+ *p++ = 0x00; *p++ = 0x03;
+ *p++ = len >> 8;
+ *p++ = len;
+ /* IAID */
+ *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x01;
+ /* T1, T2 */
+ *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
+ *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
+ if(len > 12){
+ *p++ = 0x00; *p++ = 0x05;
+ *p++ = 0x00; *p++ = IPaddrlen + 2*4;
+ memmove(p, conf.laddr, IPaddrlen);
+ p += IPaddrlen;
+ memset(p, 0xFF, 2*4);
+ p += 2*4;
+ }
+
+ /* Option Request */
+ *p++ = 0x00; *p++ = 0x06;
+ *p++ = 0x00; *p++ = 0x02;
+ *p++ = 0x00; *p++ = 0x17; /* DNS servers */
+
+ if(sidlen > 0){
+ *p++ = 0x00; *p++ = 0x02;
+ /* len */
+ *p++ = sidlen >> 8;
+ *p++ = sidlen;;
+ memmove(p, sid, sidlen);
+ p += sidlen;
+ }
+
+ len = -1;
+ for(sleepfor = 500; timeout > 0; sleepfor <<= 1){
+ DEBUG("sending dhcpv6 request %x", opkt.buf[Udphdrsize]);
+
+ alarm(sleepfor);
+ if(len < 0)
+ write(fd, opkt.buf, p - opkt.buf);
+
+ len = read(fd, ipkt.buf, sizeof(ipkt.buf));
+ timeout += alarm(0);
+ timeout -= sleepfor;
+ if(len == 0)
+ break;
+
+ 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))
+ continue;
+
+ DEBUG("got dhcpv6 reply %x from %I on %I", ipkt.buf[Udphdrsize+0], ipkt.raddr, ipkt.ifcaddr);
+
+ type |= (int)ipkt.buf[Udphdrsize+0]<<8;
+ switch(type){
+ case ADVERTISE << 8 | SOLICIT:
+ case REPLY << 8 | REQUEST:
+ goto Response;
+ default:
+ return -1;
+ }
+ }
+ return -1;
+
+Response:
+ for(p = ipkt.buf + Udphdrsize + 4, e = ipkt.buf + len; p < e; p = x) {
+ if (p+4 > e)
+ return -1;
+
+ opt = (int)p[0] << 8 | p[1];
+ len = (int)p[2] << 8 | p[3];
+ p += 4;
+ x = p+len;
+ if (x > e)
+ return -1;
+
+ DEBUG("got dhcpv6 option %x: [%d] %.*H", opt, len, len, p);
+
+ switch(opt){
+ case 0x01: /* client identifier */
+ continue;
+ case 0x02: /* server identifier */
+ if(len < 1 || len > sizeof(sid))
+ break;
+ sidlen = len;
+ memmove(sid, p, sidlen);
+ continue;
+ case 0x03: /* IA for non-temporary address */
+ if(p+12+4+IPaddrlen+2*4 > x)
+ break;
+ /* skip IAID, T1, T2 */
+ p += 12;
+ /* IA Addresss */
+ if(p[0] != 0x00 || p[1] != 0x05
+ || p[2] != 0x00 || p[3] != IPaddrlen+2*4)
+ break;
+ p += 4;
+ memset(conf.mask, 0xFF, IPaddrlen);
+ memmove(conf.laddr, p, IPaddrlen);
+ continue;
+ case 0x17: /* dns servers */
+ if(len % IPaddrlen)
+ break;
+ addaddrs(conf.dns, sizeof(conf.dns), p, len);
+ continue;
+ default:
+ DEBUG("unknown dhcpv6 option %x", opt);
+ continue;
+ }
+ warning("dhcpv6: malformed option %x: [%d] %.*H", opt, len, len, x-len);
+ }
+
+ return 0;
+}
+
+void
+dhcpv6query(void)
+{
+ int fd;
+
+ fd = openlisten();
+ if(transaction(fd, SOLICIT, 5000) < 0)
+ goto out;
+ if(!validip(conf.laddr))
+ goto out;
+ if(transaction(fd, REQUEST, 10000) < 0)
+ goto out;
+out:
+ close(fd);
+}
--- a/sys/src/cmd/ip/ipconfig/ipconfig.h
+++ b/sys/src/cmd/ip/ipconfig/ipconfig.h
@@ -35,6 +35,8 @@
int hwalen;
uchar cid[32];
int cidlen;
+ uchar duid[2+128];
+ int duidlen;
char *baud;
/* learned info */
@@ -99,6 +101,7 @@
extern Conf conf;
extern int myifc;
extern int noconfig;
+extern int dodhcp;
extern int debug;
extern int dolog;
@@ -129,7 +132,7 @@
int gnames(char*, int, uchar*, int);
Ndb* opendatabase(void);
void ndb2conf(Ndb *db, uchar *ip);
-void putndb(void);
+void putndb(int);
void refresh(void);
ulong randint(ulong low, ulong hi);
int validip(uchar*);
@@ -155,3 +158,9 @@
void ea2lla(uchar *lla, uchar *ea);
int findllip(uchar *ip, Ipifc *ifc);
int ip6cfg(void);
+
+/*
+ * DHCPv6
+ */
+void dhcpv6init(void);
+void dhcpv6query(void);
--- a/sys/src/cmd/ip/ipconfig/ipv6.c
+++ b/sys/src/cmd/ip/ipconfig/ipv6.c
@@ -448,25 +448,16 @@
}
}
-/*
- * a router receiving a router adv from another
- * router calls this; it is basically supposed to
- * log the information in the ra and raise a flag
- * if any parameter value is different from its configured values.
- *
- * doing nothing for now since I don't know where to log this yet.
- */
static void
-recvrarouter(uchar buf[], int pktlen)
-{
- USED(buf, pktlen);
-}
-
-static void
ewrite(int fd, char *str)
{
int n;
+ if(noconfig){
+ DEBUG("ewrite: %s\n", str);
+ return;
+ }
+
if(fd < 0)
return;
@@ -561,7 +552,7 @@
/*
* host receiving a router advertisement calls this
*/
-static void
+static int
recvrahost(uchar buf[], int pktlen)
{
char dnsdomain[sizeof(conf.dnsdomain)];
@@ -578,19 +569,24 @@
m = sizeof *ra;
ra = (Routeradv*)buf;
if(pktlen < m)
- return;
+ return -1;
if(!ISIPV6LINKLOCAL(ra->src))
- return;
+ return -1;
conf.ttl = ra->cttl;
- conf.mflag = (MFMASK & ra->mor);
- conf.oflag = (OCMASK & ra->mor);
+ conf.mflag = (MFMASK & ra->mor) != 0;
+ conf.oflag = (OCMASK & ra->mor) != 0;
conf.routerlt = nhgets(ra->routerlt);
conf.reachtime = nhgetl(ra->rchbltime);
conf.rxmitra = nhgetl(ra->rxmtimer);
conf.linkmtu = DEFMTU;
+ if(conf.routerlt == 0)
+ ipmove(conf.gaddr, IPnoaddr);
+ else
+ ipmove(conf.gaddr, ra->src);
+
memset(conf.dns, 0, sizeof(conf.dns));
memset(conf.fs, 0, sizeof(conf.fs));
memset(conf.auth, 0, sizeof(conf.auth));
@@ -602,7 +598,7 @@
optype = buf[n];
m += 8 * buf[n+1];
if(m <= n || pktlen < m)
- return;
+ return -1;
switch (optype) {
case V6nd_srclladdr:
@@ -660,7 +656,7 @@
|| ipcmp(r->src, ra->src) == 0 && r->routerlt != 0 && conf.routerlt == 0){
DEBUG("purging RA from %I on %s; pfx %I %M",
r->src, conf.dev, r->laddr, r->mask);
- if(validip(r->gaddr))
+ if(!noconfig && validip(r->gaddr))
removedefroute(r->gaddr, conf.lladdr, r->laddr, r->mask);
*rr = r->next;
free(r);
@@ -678,7 +674,7 @@
optype = buf[n];
m += 8 * buf[n+1];
if(m <= n || pktlen < m)
- return;
+ return -1;
if(optype != V6nd_pfxinfo)
continue;
@@ -760,17 +756,19 @@
DEBUG("got RA from %I on %s; pfx %I %M",
ra->src, conf.dev, conf.v6pref, conf.mask);
+ if(noconfig)
+ continue;
+
if(validip(conf.gaddr)
&& ipcmp(conf.gaddr, conf.laddr) != 0
&& ipcmp(conf.gaddr, conf.lladdr) != 0)
adddefroute(conf.gaddr, conf.lladdr, conf.laddr, conf.mask);
- if(noconfig)
- continue;
-
- putndb();
+ putndb(1);
refresh();
}
+
+ return 0;
}
/*
@@ -838,7 +836,10 @@
exits(nil);
}
- if(recvra6on(ifc) == IsHostNoRecv || noconfig && sendrscnt < 0){
+ switch(recvra6on(ifc)){
+ case IsHostRecv:
+ break;
+ default:
warning("recvra6: recvra off, quitting on %s", conf.dev);
if(recvracnt == 0)
rendezvous(recvra6, (void*)-1);
@@ -859,18 +860,27 @@
continue;
}
- switch (recvra6on(ifc)) {
- case IsRouter:
- recvrarouter(buf, n);
- break;
- case IsHostRecv:
- recvrahost(buf, n);
- break;
- }
+ if(recvrahost(buf, n) < 0)
+ continue;
/* got at least initial ra; no whining */
- if(recvracnt == 0)
+ if(recvracnt == 0){
+ if(dodhcp && conf.mflag){
+ dhcpv6query();
+ if(noconfig || !validip(conf.laddr))
+ continue;
+ fprint(conf.rfd, "tag dhcp");
+ if(ip6cfg() < 0){
+ fprint(conf.rfd, "tag ra6");
+ continue;
+ }
+ putndb(1);
+ refresh();
+ rendezvous(recvra6, (void*)1);
+ exits(nil);
+ }
rendezvous(recvra6, (void*)1);
+ }
if(recvracnt < Maxv6initras)
recvracnt++;
--- a/sys/src/cmd/ip/ipconfig/main.c
+++ b/sys/src/cmd/ip/ipconfig/main.c
@@ -39,6 +39,7 @@
static char logfile[] = "ipconfig";
+static void openiproute(void);
static void binddevice(void);
static void controldevice(void);
extern void pppbinddev(void);
@@ -54,8 +55,8 @@
void
usage(void)
{
- fprint(2, "usage: %s [-6dDGnNOpPrtuX][-b baud][-c ctl]* [-g gw]"
- "[-h host][-m mtu]\n"
+ fprint(2, "usage: %s [-6dDGnNOpPrtuX][-b baud][-c ctl]* [-U duid] [-g gw]"
+ "[-h host][-m mtu][-s dns]...\n"
"\t[-f dbfile][-x mtpt][-o dhcpopt] type dev [verb] [laddr [mask "
"[raddr [fs [auth]]]]]\n", argv0);
exits("usage");
@@ -277,10 +278,10 @@
Ipifc *nifc;
ifc = readipifc(net, ifc, -1);
- for(nifc = ifc; nifc != nil; nifc = nifc->next)
+ for(nifc = ifc; nifc != nil; nifc = nifc->next){
if(strcmp(nifc->dev, dev) == 0)
return nifc->index;
-
+ }
return -1;
}
@@ -305,6 +306,15 @@
conf.cid[0] = conf.hwatype;
memmove(&conf.cid[1], conf.hwa, conf.hwalen);
conf.cidlen = conf.hwalen+1;
+ if(conf.duidlen == 0){
+ /* DUID-LL */
+ conf.duid[0] = 0x00;
+ conf.duid[1] = 0x03;
+ conf.duid[2] = conf.hwatype >> 8;
+ conf.duid[3] = conf.hwatype;
+ memmove(conf.duid+4, conf.hwa, conf.hwalen);
+ conf.duidlen = conf.hwalen+4;
+ }
} else {
conf.hwatype = -1;
snprint((char*)conf.cid, sizeof conf.cid,
@@ -318,8 +328,10 @@
void
main(int argc, char **argv)
{
+ uchar ip[IPaddrlen];
int action;
Ctl *cp;
+ char *s;
init();
ARGBEGIN {
@@ -384,6 +396,11 @@
case 'r':
rflag = 1;
break;
+ case 's':
+ if(parseip(ip, EARGF(usage())) == -1)
+ usage();
+ addaddrs(conf.dns, sizeof(conf.dns), ip, sizeof(ip));
+ break;
case 't':
tflag = 1;
break;
@@ -390,6 +407,12 @@
case 'u': /* IPv6: duplicate neighbour disc. off */
dupl_disc = 0;
break;
+ case 'U': /* device unique id used for dhcpv6 */
+ s = EARGF(usage());
+ conf.duidlen = dec16(conf.duid, sizeof(conf.duid), s, strlen(s));
+ if(conf.duidlen <= 0)
+ usage();
+ break;
case 'x':
setnetmtpt(conf.mpoint, sizeof conf.mpoint, EARGF(usage()));
break;
@@ -399,13 +422,13 @@
default:
usage();
} ARGEND;
- argv0 = "ipconfig"; /* boot invokes us as tcp? */
action = parseargs(argc, argv);
- if(beprimary == -1 && (ipv6auto || parseverb(conf.type) == Vloopback))
+ if(beprimary == -1 && (ipv6auto || ISIPV6LINKLOCAL(conf.laddr) || parseverb(conf.type) == Vloopback))
beprimary = 0;
+ openiproute();
myifc = findifc(conf.mpoint, conf.dev);
if(myifc < 0) {
switch(action){
@@ -416,9 +439,15 @@
controldevice();
binddevice();
myifc = findifc(conf.mpoint, conf.dev);
- case Vremove:
case Vunbind:
break;
+ case Vremove:
+ /*
+ * interface gone, just remove
+ * default route and ndb entries.
+ */
+ doremove();
+ exits(nil);
}
if(myifc < 0)
sysfatal("interface not found for: %s", conf.dev);
@@ -478,6 +507,7 @@
} else
sysfatal("no success with DHCP");
}
+
DEBUG("adding address %I %M on %s", conf.laddr, conf.mask, conf.dev);
if(noconfig)
return;
@@ -493,7 +523,7 @@
}
/* leave everything we've learned somewhere other procs can find it */
- putndb();
+ putndb(1);
refresh();
}
@@ -504,11 +534,18 @@
sysfatal("remove requires an address");
DEBUG("removing address %I %M on %s", conf.laddr, conf.mask, conf.dev);
- if(conf.cfd < 0)
+ if(noconfig)
return;
- if(fprint(conf.cfd, "remove %I %M", conf.laddr, conf.mask) < 0)
+ if(validip(conf.gaddr))
+ removedefroute(conf.gaddr, conf.laddr, conf.laddr, conf.mask);
+
+ if(conf.cfd >= 0 && fprint(conf.cfd, "remove %I %M", conf.laddr, conf.mask) < 0)
warning("can't remove %I %M: %r", conf.laddr, conf.mask);
+
+ /* remove ndb entries matching our ip address */
+ putndb(0);
+ refresh();
}
static void
@@ -521,6 +558,15 @@
warning("can't unbind %s: %r", conf.dev);
}
+static void
+openiproute(void)
+{
+ char buf[127];
+
+ snprint(buf, sizeof buf, "%s/iproute", conf.mpoint);
+ conf.rfd = open(buf, OWRITE);
+}
+
/* send some ctls to a device */
static void
controldevice(void)
@@ -570,8 +616,6 @@
if(fprint(conf.cfd, "bind %s %s", conf.type, conf.dev) < 0)
sysfatal("%s: bind %s %s: %r", buf, conf.type, conf.dev);
}
- snprint(buf, sizeof buf, "%s/iproute", conf.mpoint);
- conf.rfd = open(buf, OWRITE);
}
/* add a logical interface to the ip stack */
@@ -624,9 +668,6 @@
if(!validip(conf.mask))
ipmove(conf.mask, defmask(conf.laddr));
- if(validip(conf.gaddr))
- removedefroute(conf.gaddr, conf.laddr, conf.laddr, conf.mask);
-
doremove();
ipmove(conf.laddr, IPnoaddr);
@@ -671,7 +712,7 @@
/* make an ndb entry and put it into /net/ndb for the servers to see */
void
-putndb(void)
+putndb(int doadd)
{
static char buf[16*1024];
char file[64], *p, *e, *np;
@@ -684,32 +725,35 @@
p = buf;
e = buf + sizeof buf;
- 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(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(*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);
- /* append preexisting entries not matching our ip */
+ /* write preexisting entries not matching our ip */
snprint(file, sizeof file, "%s/ndb", conf.mpoint);
db = ndbopen(file);
if(db != nil ){
@@ -728,7 +772,6 @@
}
ndbclose(db);
}
-
if((fd = open(file, OWRITE|OTRUNC)) < 0)
return;
write(fd, buf, p-buf);
--- a/sys/src/cmd/ip/ipconfig/mkfile
+++ b/sys/src/cmd/ip/ipconfig/mkfile
@@ -5,6 +5,7 @@
OFILES=\
main.$O\
dhcp.$O\
+ dhcpv6.$O\
ipv6.$O\
ppp.$O\