diff --git a/sys/include/ip.h b/sys/include/ip.h index a719a1b41..56e707729 100644 --- a/sys/include/ip.h +++ b/sys/include/ip.h @@ -88,8 +88,8 @@ enum { V6nd_home = 8, V6nd_srcaddrs = 9, /* rfc3122 */ V6nd_ip = 17, - /* /lib/rfc/drafts/draft-jeong-dnsop-ipv6-dns-discovery-12.txt */ - V6nd_rdns = 25, + V6nd_rdns = 25, /* rfc6106 */ + V6nd_rdnssl = 31, /* plan 9 extensions */ V6nd_9fs = 250, V6nd_9auth = 251, diff --git a/sys/src/cmd/ip/ipconfig/dhcp.c b/sys/src/cmd/ip/ipconfig/dhcp.c new file mode 100644 index 000000000..4f6075857 --- /dev/null +++ b/sys/src/cmd/ip/ipconfig/dhcp.c @@ -0,0 +1,979 @@ +/* + * ipconfig - configure parameters of an ip stack + */ +#include +#include +#include +#include +#include +#include "ipconfig.h" +#include "../dhcp.h" + +enum +{ + Taddr, + Taddrs, + Tstr, + Tbyte, + Tulong, + Tvec, +}; + +typedef struct Option Option; +struct Option +{ + char *name; + int type; +}; + +/* + * I was too lazy to look up the types for each of these + * options. If someone feels like it, please mail me a + * corrected array -- presotto + */ +static Option option[256] = +{ +[OBmask] { "ipmask", Taddr }, +[OBtimeoff] { "timeoff", Tulong }, +[OBrouter] { "ipgw", Taddrs }, +[OBtimeserver] { "time", Taddrs }, +[OBnameserver] { "name", Taddrs }, +[OBdnserver] { "dns", Taddrs }, +[OBlogserver] { "log", Taddrs }, +[OBcookieserver] { "cookie", Taddrs }, +[OBlprserver] { "lpr", Taddrs }, +[OBimpressserver] { "impress", Taddrs }, +[OBrlserver] { "rl", Taddrs }, +[OBhostname] { "sys", Tstr }, +[OBbflen] { "bflen", Tulong }, +[OBdumpfile] { "dumpfile", Tstr }, +[OBdomainname] { "dom", Tstr }, +[OBswapserver] { "swap", Taddrs }, +[OBrootpath] { "rootpath", Tstr }, +[OBextpath] { "extpath", Tstr }, +[OBipforward] { "ipforward", Taddrs }, +[OBnonlocal] { "nonlocal", Taddrs }, +[OBpolicyfilter] { "policyfilter", Taddrs }, +[OBmaxdatagram] { "maxdatagram", Tulong }, +[OBttl] { "ttl", Tulong }, +[OBpathtimeout] { "pathtimeout", Taddrs }, +[OBpathplateau] { "pathplateau", Taddrs }, +[OBmtu] { "mtu", Tulong }, +[OBsubnetslocal] { "subnetslocal", Taddrs }, +[OBbaddr] { "baddr", Taddrs }, +[OBdiscovermask] { "discovermask", Taddrs }, +[OBsupplymask] { "supplymask", Taddrs }, +[OBdiscoverrouter] { "discoverrouter", Taddrs }, +[OBrsserver] { "rs", Taddrs }, +[OBstaticroutes] { "staticroutes", Taddrs }, +[OBtrailerencap] { "trailerencap", Taddrs }, +[OBarptimeout] { "arptimeout", Tulong }, +[OBetherencap] { "etherencap", Taddrs }, +[OBtcpttl] { "tcpttl", Tulong }, +[OBtcpka] { "tcpka", Tulong }, +[OBtcpkag] { "tcpkag", Tulong }, +[OBnisdomain] { "nisdomain", Tstr }, +[OBniserver] { "ni", Taddrs }, +[OBntpserver] { "ntp", Taddrs }, +[OBnetbiosns] { "netbiosns", Taddrs }, +[OBnetbiosdds] { "netbiosdds", Taddrs }, +[OBnetbiostype] { "netbiostype", Taddrs }, +[OBnetbiosscope] { "netbiosscope", Taddrs }, +[OBxfontserver] { "xfont", Taddrs }, +[OBxdispmanager] { "xdispmanager", Taddrs }, +[OBnisplusdomain] { "nisplusdomain", Tstr }, +[OBnisplusserver] { "nisplus", Taddrs }, +[OBhomeagent] { "homeagent", Taddrs }, +[OBsmtpserver] { "smtp", Taddrs }, +[OBpop3server] { "pop3", Taddrs }, +[OBnntpserver] { "nntp", Taddrs }, +[OBwwwserver] { "www", Taddrs }, +[OBfingerserver] { "finger", Taddrs }, +[OBircserver] { "irc", Taddrs }, +[OBstserver] { "st", Taddrs }, +[OBstdaserver] { "stdar", Taddrs }, + +[ODipaddr] { "ipaddr", Taddr }, +[ODlease] { "lease", Tulong }, +[ODoverload] { "overload", Taddr }, +[ODtype] { "type", Tbyte }, +[ODserverid] { "serverid", Taddr }, +[ODparams] { "params", Tvec }, +[ODmessage] { "message", Tstr }, +[ODmaxmsg] { "maxmsg", Tulong }, +[ODrenewaltime] { "renewaltime", Tulong }, +[ODrebindingtime] { "rebindingtime", Tulong }, +[ODvendorclass] { "vendorclass", Tvec }, +[ODclientid] { "clientid", Tvec }, +[ODtftpserver] { "tftp", Taddr }, +[ODbootfile] { "bootfile", Tstr }, +}; + +static uchar defrequested[] = { + OBmask, OBrouter, OBdnserver, OBhostname, OBdomainname, OBntpserver, +}; + +static uchar requested[256]; +static int nrequested; + +static char optmagic[4] = { 0x63, 0x82, 0x53, 0x63 }; + +static int openlisten(void); + +static void dhcprecv(void); +static void dhcpsend(int); +static void dhcptimer(void); + +static uchar* optaddaddr(uchar*, int, uchar*); +static uchar* optaddbyte(uchar*, int, int); +static uchar* optaddstr(uchar*, int, char*); +static uchar* optadd(uchar*, int, void*, int); +static uchar* optaddulong(uchar*, int, ulong); +static uchar* optaddvec(uchar*, int, uchar*, int); +static int optgetaddrs(uchar*, int, uchar*, int); +static int optgetp9addrs(uchar*, int, uchar*, int); +static int optgetaddr(uchar*, int, uchar*); +static int optgetbyte(uchar*, int); +static int optgetstr(uchar*, int, char*, int); +static uchar* optget(uchar*, int, int*); +static ulong optgetulong(uchar*, int); +static int optgetvec(uchar*, int, uchar*, int); +static char* optgetx(uchar*, uchar); + +static void getoptions(uchar*); +static int parseoptions(uchar *p, int n); +static Bootp* parsebootp(uchar*, int); + +void +dhcpinit(void) +{ + /* init set of requested dhcp parameters with the default */ + nrequested = sizeof defrequested; + memcpy(requested, defrequested, nrequested); +} + +void +dhcpquery(int needconfig, int startstate) +{ + if(needconfig) + fprint(conf.cfd, "add %I %I", IPnoaddr, IPnoaddr); + + conf.fd = openlisten(); + if(conf.fd < 0){ + conf.state = Sinit; + return; + } + notify(catch); + + conf.xid = lrand(); + conf.starttime = time(0); + conf.state = startstate; + switch(startstate){ + case Sselecting: + conf.offered = 0; + dhcpsend(Discover); + break; + case Srenewing: + dhcpsend(Request); + break; + default: + sysfatal("internal error 0"); + } + conf.resend = 0; + conf.timeout = time(0) + 4; + + while(conf.state != Sbound && conf.state != Sinit){ + dhcprecv(); + dhcptimer(); + } + close(conf.fd); + + if(needconfig) + fprint(conf.cfd, "remove %I %I", IPnoaddr, IPnoaddr); + +} + +enum { + /* + * was an hour, needs to be less for the ARM/GS1 until the timer + * code has been cleaned up (pb). + */ + Maxsleep = 450, +}; + +void +dhcpwatch(int needconfig) +{ + ulong secs, s, t; + + if(nodhcpwatch) + return; + + switch(rfork(RFPROC|RFFDG|RFNOWAIT|RFNOTEG)){ + default: + return; + case 0: + break; + } + + dolog = 1; /* log, don't print */ + procsetname("dhcpwatch on %s", conf.dev); + /* keep trying to renew the lease */ + for(;;){ + secs = conf.lease/2; + if(secs < 5) + secs = 5; + + /* avoid overflows */ + for(s = secs; s > 0; s -= t){ + if(s > Maxsleep) + t = Maxsleep; + else + t = s; + sleep(t*1000); + } + + if(conf.lease > 0){ + /* + * during boot, the starttime can be bogus so avoid + * spurious ipunconfig's + */ + t = time(0) - conf.starttime; + if(t > (3*secs)/2) + t = secs; + if(t >= conf.lease){ + conf.lease = 0; + if(!noconfig){ + ipunconfig(); + needconfig = 1; + } + } else + conf.lease -= t; + } + dhcpquery(needconfig, needconfig? Sselecting: Srenewing); + + if(needconfig && conf.state == Sbound){ + if(ip4cfg() < 0) + sysfatal("can't start ip: %r"); + needconfig = 0; + /* + * leave everything we've learned somewhere that + * other procs can find it. + */ + if(beprimary) + putndb(); + refresh(); + } + } +} + +static void +dhcptimer(void) +{ + ulong now; + + now = time(0); + if(now < conf.timeout) + return; + + switch(conf.state) { + default: + sysfatal("dhcptimer: unknown state %d", conf.state); + case Sinit: + case Sbound: + break; + case Sselecting: + case Srequesting: + case Srebinding: + dhcpsend(conf.state == Sselecting? Discover: Request); + conf.timeout = now + 4; + if(++conf.resend > 5) + conf.state = Sinit; + break; + case Srenewing: + dhcpsend(Request); + conf.timeout = now + 1; + if(++conf.resend > 3) { + conf.state = Srebinding; + conf.resend = 0; + } + break; + } +} + +static void +dhcpsend(int type) +{ + Bootp bp; + uchar *p; + int n; + uchar vendor[64]; + Udphdr *up = (Udphdr*)bp.udphdr; + + memset(&bp, 0, sizeof bp); + + hnputs(up->rport, 67); + bp.op = Bootrequest; + hnputl(bp.xid, conf.xid); + hnputs(bp.secs, time(0)-conf.starttime); + hnputs(bp.flags, 0); + memmove(bp.optmagic, optmagic, 4); + if(conf.hwatype >= 0 && conf.hwalen < sizeof bp.chaddr){ + memmove(bp.chaddr, conf.hwa, conf.hwalen); + bp.hlen = conf.hwalen; + bp.htype = conf.hwatype; + } + p = bp.optdata; + p = optaddbyte(p, ODtype, type); + p = optadd(p, ODclientid, conf.cid, conf.cidlen); + switch(type) { + default: + sysfatal("dhcpsend: unknown message type: %d", type); + case Discover: + ipmove(up->raddr, IPv4bcast); /* broadcast */ + if(*conf.hostname && sendhostname) + p = optaddstr(p, OBhostname, conf.hostname); + if(plan9){ + n = snprint((char*)vendor, sizeof vendor, + "plan9_%s", conf.cputype); + p = optaddvec(p, ODvendorclass, vendor, n); + } + p = optaddvec(p, ODparams, requested, nrequested); + if(validip(conf.laddr)) + p = optaddaddr(p, ODipaddr, conf.laddr); + break; + case Request: + switch(conf.state){ + case Srenewing: + ipmove(up->raddr, conf.server); + v6tov4(bp.ciaddr, conf.laddr); + break; + case Srebinding: + ipmove(up->raddr, IPv4bcast); /* broadcast */ + v6tov4(bp.ciaddr, conf.laddr); + break; + case Srequesting: + ipmove(up->raddr, IPv4bcast); /* broadcast */ + p = optaddaddr(p, ODipaddr, conf.laddr); + p = optaddaddr(p, ODserverid, conf.server); + break; + } + p = optaddulong(p, ODlease, conf.offered); + if(plan9){ + n = snprint((char*)vendor, sizeof vendor, + "plan9_%s", conf.cputype); + p = optaddvec(p, ODvendorclass, vendor, n); + } + p = optaddvec(p, ODparams, requested, nrequested); + if(*conf.hostname && sendhostname) + p = optaddstr(p, OBhostname, conf.hostname); + break; + case Release: + ipmove(up->raddr, conf.server); + v6tov4(bp.ciaddr, conf.laddr); + p = optaddaddr(p, ODipaddr, conf.laddr); + p = optaddaddr(p, ODserverid, conf.server); + break; + } + + *p++ = OBend; + + n = p - (uchar*)&bp; + USED(n); + + /* + * We use a maximum size DHCP packet to survive the + * All_Aboard NAT package from Internet Share. It + * always replies to DHCP requests with a packet of the + * same size, so if the request is too short the reply + * is truncated. + */ + if(write(conf.fd, &bp, sizeof bp) != sizeof bp) + warning("dhcpsend: write failed: %r"); +} + +static void +dhcprecv(void) +{ + int i, n, type; + ulong lease; + char err[ERRMAX]; + uchar buf[8000], vopts[256], taddr[IPaddrlen]; + Bootp *bp; + + memset(buf, 0, sizeof buf); + alarm(1000); + n = read(conf.fd, buf, sizeof buf); + alarm(0); + + if(n < 0){ + rerrstr(err, sizeof err); + if(strstr(err, "interrupt") == nil) + warning("dhcprecv: bad read: %s", err); + else + DEBUG("dhcprecv: read timed out"); + return; + } + + bp = parsebootp(buf, n); + if(bp == 0) { + DEBUG("parsebootp failed: dropping packet"); + return; + } + + type = optgetbyte(bp->optdata, ODtype); + switch(type) { + default: + warning("dhcprecv: unknown type: %d", type); + break; + case Offer: + DEBUG("got offer from %V ", bp->siaddr); + if(conf.state != Sselecting) + break; + lease = optgetulong(bp->optdata, ODlease); + if(lease == 0){ + /* + * The All_Aboard NAT package from Internet Share + * doesn't give a lease time, so we have to assume one. + */ + warning("Offer with %lud lease, using %d", lease, MinLease); + lease = MinLease; + } + DEBUG("lease=%lud ", lease); + if(!optgetaddr(bp->optdata, ODserverid, conf.server)) { + warning("Offer from server with invalid serverid"); + break; + } + + v4tov6(conf.laddr, bp->yiaddr); + memmove(conf.sname, bp->sname, sizeof conf.sname); + conf.sname[sizeof conf.sname-1] = 0; + DEBUG("server=%I sname=%s", conf.server, conf.sname); + conf.offered = lease; + conf.state = Srequesting; + dhcpsend(Request); + conf.resend = 0; + conf.timeout = time(0) + 4; + break; + case Ack: + DEBUG("got ack from %V ", bp->siaddr); + if (conf.state != Srequesting && conf.state != Srenewing && + conf.state != Srebinding) + break; + + /* ignore a bad lease */ + lease = optgetulong(bp->optdata, ODlease); + if(lease == 0){ + /* + * The All_Aboard NAT package from Internet Share + * doesn't give a lease time, so we have to assume one. + */ + warning("Ack with %lud lease, using %d", lease, MinLease); + lease = MinLease; + } + DEBUG("lease=%lud ", lease); + + /* address and mask */ + if(!validip(conf.laddr) || !Oflag) + v4tov6(conf.laddr, bp->yiaddr); + if(!validip(conf.mask) || !Oflag){ + if(!optgetaddr(bp->optdata, OBmask, conf.mask)) + ipmove(conf.mask, IPnoaddr); + if(ipcmp(conf.mask, IPv4bcast) == 0) + ipmove(conf.mask, IPnoaddr); + } + DEBUG("ipaddr=%I ipmask=%M ", conf.laddr, conf.mask); + + /* + * get a router address either from the router option + * or from the router that forwarded the dhcp packet + */ + if(validip(conf.gaddr) && Oflag) { + DEBUG("ipgw=%I ", conf.gaddr); + } else if(optgetaddr(bp->optdata, OBrouter, conf.gaddr)){ + DEBUG("ipgw=%I ", conf.gaddr); + } else if(memcmp(bp->giaddr, IPnoaddr+IPv4off, IPv4addrlen)!=0){ + v4tov6(conf.gaddr, bp->giaddr); + DEBUG("giaddr=%I ", conf.gaddr); + } + + /* get dns servers */ + memset(conf.dns, 0, sizeof conf.dns); + n = optgetaddrs(bp->optdata, OBdnserver, conf.dns, + sizeof conf.dns/IPaddrlen); + for(i = 0; i < n; i++) + DEBUG("dns=%I ", conf.dns + i*IPaddrlen); + + /* get ntp servers */ + memset(conf.ntp, 0, sizeof conf.ntp); + n = optgetaddrs(bp->optdata, OBntpserver, conf.ntp, + sizeof conf.ntp/IPaddrlen); + for(i = 0; i < n; i++) + DEBUG("ntp=%I ", conf.ntp + i*IPaddrlen); + + /* get names */ + optgetstr(bp->optdata, OBhostname, + conf.hostname, sizeof conf.hostname); + optgetstr(bp->optdata, OBdomainname, + conf.domainname, sizeof conf.domainname); + + /* get anything else we asked for */ + getoptions(bp->optdata); + + /* get plan9-specific options */ + n = optgetvec(bp->optdata, OBvendorinfo, vopts, sizeof vopts-1); + if(n > 0 && parseoptions(vopts, n) == 0){ + if(validip(conf.fs) && Oflag) + n = 1; + else { + n = optgetp9addrs(vopts, OP9fs, conf.fs, 2); + if (n == 0) + n = optgetaddrs(vopts, OP9fsv4, + conf.fs, 2); + } + for(i = 0; i < n; i++) + DEBUG("fs=%I ", conf.fs + i*IPaddrlen); + + if(validip(conf.auth) && Oflag) + n = 1; + else { + n = optgetp9addrs(vopts, OP9auth, conf.auth, 2); + if (n == 0) + n = optgetaddrs(vopts, OP9authv4, + conf.auth, 2); + } + for(i = 0; i < n; i++) + DEBUG("auth=%I ", conf.auth + i*IPaddrlen); + + n = optgetp9addrs(vopts, OP9ipaddr, taddr, 1); + if (n > 0) + memmove(conf.laddr, taddr, IPaddrlen); + n = optgetp9addrs(vopts, OP9ipmask, taddr, 1); + if (n > 0) + memmove(conf.mask, taddr, IPaddrlen); + n = optgetp9addrs(vopts, OP9ipgw, taddr, 1); + if (n > 0) + memmove(conf.gaddr, taddr, IPaddrlen); + DEBUG("new ipaddr=%I new ipmask=%M new ipgw=%I", + conf.laddr, conf.mask, conf.gaddr); + } + conf.lease = lease; + conf.state = Sbound; + DEBUG("server=%I sname=%s", conf.server, conf.sname); + break; + case Nak: + conf.state = Sinit; + warning("recved dhcpnak on %s", conf.mpoint); + break; + } +} + +static int +openlisten(void) +{ + int n, fd, cfd; + char data[128], devdir[40]; + + if (validip(conf.laddr) && + (conf.state == Srenewing || conf.state == Srebinding)) + sprint(data, "%s/udp!%I!68", conf.mpoint, conf.laddr); + else + sprint(data, "%s/udp!*!68", conf.mpoint); + 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"); + + sprint(data, "%s/data", devdir); + fd = open(data, ORDWR); + if(fd < 0) + sysfatal("open %s: %r", data); + close(cfd); + return fd; +} + +static uchar* +optadd(uchar *p, int op, void *d, int n) +{ + p[0] = op; + p[1] = n; + memmove(p+2, d, n); + return p+n+2; +} + +static uchar* +optaddbyte(uchar *p, int op, int b) +{ + p[0] = op; + p[1] = 1; + p[2] = b; + return p+3; +} + +static uchar* +optaddulong(uchar *p, int op, ulong x) +{ + p[0] = op; + p[1] = 4; + hnputl(p+2, x); + return p+6; +} + +static uchar * +optaddaddr(uchar *p, int op, uchar *ip) +{ + p[0] = op; + p[1] = 4; + v6tov4(p+2, ip); + return p+6; +} + +/* add dhcp option op with value v of length n to dhcp option array p */ +static uchar * +optaddvec(uchar *p, int op, uchar *v, int n) +{ + p[0] = op; + p[1] = n; + memmove(p+2, v, n); + return p+2+n; +} + +static uchar * +optaddstr(uchar *p, int op, char *v) +{ + int n; + + n = strlen(v); + p[0] = op; + p[1] = n; + memmove(p+2, v, n); + return p+2+n; +} + +/* + * parse p, looking for option `op'. if non-nil, np points to minimum length. + * return nil if option is too small, else ptr to opt, and + * store actual length via np if non-nil. + */ +static uchar* +optget(uchar *p, int op, int *np) +{ + int len, code; + + while ((code = *p++) != OBend) { + if(code == OBpad) + continue; + len = *p++; + if(code != op) { + p += len; + continue; + } + if(np != nil){ + if(*np > len) { + return 0; + } + *np = len; + } + return p; + } + return 0; +} + +static int +optgetbyte(uchar *p, int op) +{ + int len; + + len = 1; + p = optget(p, op, &len); + if(p == nil) + return 0; + return *p; +} + +static ulong +optgetulong(uchar *p, int op) +{ + int len; + + len = 4; + p = optget(p, op, &len); + if(p == nil) + return 0; + return nhgetl(p); +} + +static int +optgetaddr(uchar *p, int op, uchar *ip) +{ + int len; + + len = 4; + p = optget(p, op, &len); + if(p == nil) + return 0; + v4tov6(ip, p); + return 1; +} + +/* expect at most n addresses; ip[] only has room for that many */ +static int +optgetaddrs(uchar *p, int op, uchar *ip, int n) +{ + int len, i; + + len = 4; + p = optget(p, op, &len); + if(p == nil) + return 0; + len /= IPv4addrlen; + if(len > n) + len = n; + for(i = 0; i < len; i++) + v4tov6(&ip[i*IPaddrlen], &p[i*IPv4addrlen]); + return i; +} + +/* expect at most n addresses; ip[] only has room for that many */ +static int +optgetp9addrs(uchar *ap, int op, uchar *ip, int n) +{ + int len, i, slen, addrs; + char *p; + + len = 1; /* minimum bytes needed */ + p = (char *)optget(ap, op, &len); + if(p == nil) + return 0; + addrs = *p++; /* first byte is address count */ + for (i = 0; i < n && i < addrs && len > 0; i++) { + slen = strlen(p) + 1; + if (parseip(&ip[i*IPaddrlen], p) == -1) + fprint(2, "%s: bad address %s\n", argv0, p); + DEBUG("got plan 9 option %d addr %I (%s)", + op, &ip[i*IPaddrlen], p); + p += slen; + len -= slen; + } + return addrs; +} + +static int +optgetvec(uchar *p, int op, uchar *v, int n) +{ + int len; + + len = 1; + p = optget(p, op, &len); + if(p == nil) + return 0; + if(len > n) + len = n; + memmove(v, p, len); + return len; +} + +static int +optgetstr(uchar *p, int op, char *s, int n) +{ + int len; + + len = 1; + p = optget(p, op, &len); + if(p == nil) + return 0; + if(len >= n) + len = n-1; + memmove(s, p, len); + s[len] = 0; + return len; +} + +int +addoption(char *opt) +{ + int i; + Option *o; + + if(opt == nil) + return -1; + for(o = option; o < &option[nelem(option)]; o++) + if(o->name && strcmp(opt, o->name) == 0){ + i = o - option; + if(memchr(requested, i, nrequested) == 0 && + nrequested < nelem(requested)) + requested[nrequested++] = i; + return 0; + } + return -1; +} + +static char* +optgetx(uchar *p, uchar opt) +{ + int i, n; + ulong x; + char *s, *ns; + char str[256]; + uchar ip[IPaddrlen], ips[16*IPaddrlen], vec[256]; + Option *o; + + o = &option[opt]; + if(o->name == nil) + return nil; + + s = nil; + switch(o->type){ + case Taddr: + if(optgetaddr(p, opt, ip)) + s = smprint("%s=%I", o->name, ip); + break; + case Taddrs: + n = optgetaddrs(p, opt, ips, 16); + if(n > 0) + s = smprint("%s=%I", o->name, ips); + for(i = 1; i < n; i++){ + ns = smprint("%s %s=%I", s, o->name, &ips[i*IPaddrlen]); + free(s); + s = ns; + } + break; + case Tulong: + x = optgetulong(p, opt); + if(x != 0) + s = smprint("%s=%lud", o->name, x); + break; + case Tbyte: + x = optgetbyte(p, opt); + if(x != 0) + s = smprint("%s=%lud", o->name, x); + break; + case Tstr: + if(optgetstr(p, opt, str, sizeof str)) + s = smprint("%s=%s", o->name, str); + break; + case Tvec: + n = optgetvec(p, opt, vec, sizeof vec); + if(n > 0) + /* what's %H? it's not installed */ + s = smprint("%s=%.*H", o->name, n, vec); + break; + } + return s; +} + +static void +getoptions(uchar *p) +{ + int i; + char *s, *t; + + for(i = nelem(defrequested); i < nrequested; i++){ + s = optgetx(p, requested[i]); + if(s != nil) + DEBUG("%s ", s); + if(ndboptions == nil) + ndboptions = smprint("\t%s", s); + else{ + t = ndboptions; + ndboptions = smprint("\t%s%s", s, ndboptions); + free(t); + } + free(s); + } +} + +/* + * sanity check options area + * - options don't overflow packet + * - options end with an OBend + */ +static int +parseoptions(uchar *p, int n) +{ + int code, len, nin = n; + + while (n > 0) { + code = *p++; + n--; + if(code == OBend) + return 0; + if(code == OBpad) + continue; + if(n == 0) { + warning("parseoptions: bad option: 0x%ux: truncated: " + "opt length = %d", code, nin); + return -1; + } + + len = *p++; + n--; + DEBUG("parseoptions: %s(%d) len %d, bytes left %d", + option[code].name, code, len, n); + if(len > n) { + warning("parseoptions: bad option: 0x%ux: %d > %d: " + "opt length = %d", code, len, n, nin); + return -1; + } + p += len; + n -= len; + } + + /* make sure packet ends with an OBend after all the optget code */ + *p = OBend; + return 0; +} + +/* + * sanity check received packet: + * - magic is dhcp magic + * - options don't overflow packet + */ +static Bootp* +parsebootp(uchar *p, int n) +{ + Bootp *bp; + + bp = (Bootp*)p; + if(n < bp->optmagic - p) { + warning("parsebootp: short bootp packet"); + return nil; + } + + if(conf.xid != nhgetl(bp->xid)) /* not meant for us */ + return nil; + + if(bp->op != Bootreply) { + warning("parsebootp: bad op %d", bp->op); + return nil; + } + + n -= bp->optmagic - p; + p = bp->optmagic; + + if(n < 4) { + warning("parsebootp: no option data"); + return nil; + } + if(memcmp(optmagic, p, 4) != 0) { + warning("parsebootp: bad opt magic %ux %ux %ux %ux", + p[0], p[1], p[2], p[3]); + return nil; + } + p += 4; + n -= 4; + DEBUG("parsebootp: new packet"); + if(parseoptions(p, n) < 0) + return nil; + return bp; +} + diff --git a/sys/src/cmd/ip/ipconfig/ipconfig.h b/sys/src/cmd/ip/ipconfig/ipconfig.h index 888b87f87..7f58a5148 100644 --- a/sys/src/cmd/ip/ipconfig/ipconfig.h +++ b/sys/src/cmd/ip/ipconfig/ipconfig.h @@ -1,3 +1,23 @@ +/* possible verbs */ +enum +{ + /* commands */ + Vadd, + Vremove, + Vunbind, + Vaddpref6, + Vra6, + + /* media */ + Vether, + Vgbe, + Vppp, + Vloopback, + Vtorus, + Vtree, + Vpkt, +}; + typedef struct Conf Conf; typedef struct Ctl Ctl; @@ -22,7 +42,7 @@ struct Conf uchar laddr[IPaddrlen]; uchar mask[IPaddrlen]; uchar raddr[IPaddrlen]; - uchar dns[2*IPaddrlen]; + uchar dns[8*IPaddrlen]; uchar fs[2*IPaddrlen]; uchar auth[2*IPaddrlen]; uchar ntp[2*IPaddrlen]; @@ -60,12 +80,15 @@ struct Conf int ttl; /* default 0 (unspecified) */ /* prefix related */ + uchar lladdr[IPaddrlen]; uchar v6pref[IPaddrlen]; int prefixlen; uchar onlink; /* flag: address is `on-link' */ uchar autoflag; /* flag: autonomous */ ulong validlt; /* valid lifetime (seconds) */ ulong preflt; /* preferred lifetime (seconds) */ + + char dnsdomain[256]; }; struct Ctl @@ -74,152 +97,60 @@ struct Ctl char *ctl; }; -extern Ctl *firstctl, **ctll; - -extern Conf conf; - -extern int noconfig; -extern int ipv6auto; -extern int debug; -extern int dodhcp; -extern int dolog; -extern int plan9; -extern int dupl_disc; - extern Conf conf; extern int myifc; -extern char *vs; +extern int beprimary; +extern int noconfig; + +extern int debug; +extern int dolog; + +extern int plan9; +extern int Oflag; + +extern int dupl_disc; + +extern int nodhcpwatch; +extern int sendhostname; +extern char *ndboptions; + +void usage(void); +int ip4cfg(void); +void ipunconfig(void); 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 mklladdr(void); void procsetname(char *fmt, ...); +void catch(void*, char*); +int countaddrs(uchar *a, int len); +void addaddrs(uchar *to, int nto, uchar *from, int nfrom); +void addnames(char *d, char *s, int len); +Ndb* opendatabase(void); +void ndb2conf(Ndb *db, uchar *ip); +void putndb(void); void refresh(void); ulong randint(ulong low, ulong hi); int validip(uchar*); void warning(char *fmt, ...); +#define DEBUG if(debug)warning + +/* + * DHCP + */ +void dhcpinit(void); +void dhcpquery(int, int); +void dhcpwatch(int); +int addoption(char*); /* * IPv6 */ - -void doipv6(int); void v6paraminit(Conf*); - -typedef struct Headers Headers; -typedef struct Ip4hdr Ip4hdr; -typedef struct Lladdropt Lladdropt; -typedef struct Mtuopt Mtuopt; -typedef struct Prefixopt Prefixopt; -typedef struct Routeradv Routeradv; -typedef struct Routersol Routersol; - -enum { - IsRouter = 1, - IsHostRecv = 2, - IsHostNoRecv = 3, - - MAClen = 6, - - IPv4 = 4, - IPv6 = 6, - Defmtu = 1400, - - IP_HOPBYHOP = 0, - ICMPv4 = 1, - IP_IGMPPROTO = 2, - IP_TCPPROTO = 6, - IP_UDPPROTO = 17, - IP_ILPROTO = 40, - IP_v6ROUTE = 43, - IP_v6FRAG = 44, - IP_IPsecESP = 50, - IP_IPsecAH = 51, - IP_v6NOMORE = 59, - ICMP6_RS = 133, - ICMP6_RA = 134, - - IP_IN_IP = 41, -}; - -enum { - MFMASK = 1 << 7, - OCMASK = 1 << 6, - OLMASK = 1 << 7, - AFMASK = 1 << 6, - RFMASK = 1 << 5, -}; - -enum { - MAXTTL = 255, - D64HLEN = IPV6HDR_LEN - IPV4HDR_LEN, - IP_MAX = 32*1024, -}; - -struct Headers { - uchar dst[IPaddrlen]; - uchar src[IPaddrlen]; -}; - -struct Routersol { - uchar vcf[4]; /* version:4, traffic class:8, flow label:20 */ - uchar ploadlen[2]; /* payload length: packet length - 40 */ - uchar proto; /* next header type */ - uchar ttl; /* hop limit */ - uchar src[IPaddrlen]; - uchar dst[IPaddrlen]; - uchar type; - uchar code; - uchar cksum[2]; - uchar res[4]; -}; - -struct Routeradv { - uchar vcf[4]; /* version:4, traffic class:8, flow label:20 */ - uchar ploadlen[2]; /* payload length: packet length - 40 */ - uchar proto; /* next header type */ - uchar ttl; /* hop limit */ - uchar src[IPaddrlen]; - uchar dst[IPaddrlen]; - uchar type; - uchar code; - uchar cksum[2]; - uchar cttl; - uchar mor; - uchar routerlt[2]; - uchar rchbltime[4]; - uchar rxmtimer[4]; -}; - -struct Lladdropt { - uchar type; - uchar len; - uchar lladdr[MAClen]; -}; - -struct Prefixopt { - uchar type; - uchar len; - uchar plen; - uchar lar; - uchar validlt[4]; - uchar preflt[4]; - uchar reserv[4]; - uchar pref[IPaddrlen]; -}; - -struct Mtuopt { - uchar type; - uchar len; - uchar reserv[2]; - uchar mtu[4]; -}; - +void parse6pref(int argc, char **argv); +void parse6ra(int argc, char **argv); +void doipv6(int); void ea2lla(uchar *lla, uchar *ea); -void ipv62smcast(uchar *smcast, uchar *a); +int findllip(uchar *ip, Ipifc *ifc); +int ip6cfg(void); diff --git a/sys/src/cmd/ip/ipconfig/ipv6.c b/sys/src/cmd/ip/ipconfig/ipv6.c index 941bd2c6d..c1e8cde8f 100644 --- a/sys/src/cmd/ip/ipconfig/ipv6.c +++ b/sys/src/cmd/ip/ipconfig/ipv6.c @@ -8,71 +8,97 @@ #include #include #include +#include #include "ipconfig.h" #include "../icmp.h" -#include - -#pragma varargck argpos ralog 1 - -#define RALOG "v6routeradv" - -#define NetS(x) (((uchar*)x)[0]<< 8 | ((uchar*)x)[1]) -#define NetL(x) (((uchar*)x)[0]<<24 | ((uchar*)x)[1]<<16 | \ - ((uchar*)x)[2]<< 8 | ((uchar*)x)[3]) +#include /* for sha1 */ enum { - ICMP6LEN= 4, + IsRouter = 1, + IsHostRecv = 2, + IsHostNoRecv = 3, + + ICMP6_RS = 133, + ICMP6_RA = 134, + + MFMASK = 1 << 7, + OCMASK = 1 << 6, + OLMASK = 1 << 7, + AFMASK = 1 << 6, + RFMASK = 1 << 5, + + MAXTTL = 255, + DEFMTU = 1500, }; -typedef struct Hdr Hdr; -struct Hdr /* ICMP v4 & v6 header */ -{ +typedef struct Routeradv Routeradv; +typedef struct Routersol Routersol; +typedef struct Lladdropt Lladdropt; +typedef struct Prefixopt Prefixopt; +typedef struct Mtuopt Mtuopt; +typedef struct Ipaddrsopt Ipaddrsopt; + +struct Routersol { + uchar vcf[4]; /* version:4, traffic class:8, flow label:20 */ + uchar ploadlen[2]; /* payload length: packet length - 40 */ + uchar proto; /* next header type */ + uchar ttl; /* hop limit */ + uchar src[16]; + uchar dst[16]; uchar type; uchar code; - uchar cksum[2]; /* Checksum */ - uchar data[]; + uchar cksum[2]; + uchar res[4]; }; -char *icmpmsg6[Maxtype6+1] = -{ -[EchoReply] "EchoReply", -[UnreachableV6] "UnreachableV6", -[PacketTooBigV6] "PacketTooBigV6", -[TimeExceedV6] "TimeExceedV6", -[Redirect] "Redirect", -[EchoRequest] "EchoRequest", -[TimeExceed] "TimeExceed", -[InParmProblem] "InParmProblem", -[Timestamp] "Timestamp", -[TimestampReply] "TimestampReply", -[InfoRequest] "InfoRequest", -[InfoReply] "InfoReply", -[AddrMaskRequest] "AddrMaskRequest", -[AddrMaskReply] "AddrMaskReply", -[EchoRequestV6] "EchoRequestV6", -[EchoReplyV6] "EchoReplyV6", -[RouterSolicit] "RouterSolicit", -[RouterAdvert] "RouterAdvert", -[NbrSolicit] "NbrSolicit", -[NbrAdvert] "NbrAdvert", -[RedirectV6] "RedirectV6", +struct Routeradv { + uchar vcf[4]; /* version:4, traffic class:8, flow label:20 */ + uchar ploadlen[2]; /* payload length: packet length - 40 */ + uchar proto; /* next header type */ + uchar ttl; /* hop limit */ + uchar src[16]; + uchar dst[16]; + uchar type; + uchar code; + uchar cksum[2]; + uchar cttl; + uchar mor; + uchar routerlt[2]; + uchar rchbltime[4]; + uchar rxmtimer[4]; }; -static char *icmp6opts[] = -{ -[0] "unknown option", -[V6nd_srclladdr] "srcll_addr", -[V6nd_targlladdr] "targll_addr", -[V6nd_pfxinfo] "prefix", -[V6nd_redirhdr] "redirect", -[V6nd_mtu] "mtu", -[V6nd_home] "home", -[V6nd_srcaddrs] "src_addrs", -[V6nd_ip] "ip", -[V6nd_rdns] "rdns", -[V6nd_9fs] "9fs", -[V6nd_9auth] "9auth", +struct Lladdropt { + uchar type; + uchar len; + uchar lladdr[6]; +}; + +struct Prefixopt { + uchar type; + uchar len; + uchar plen; + uchar lar; + uchar validlt[4]; + uchar preflt[4]; + uchar reserv[4]; + uchar pref[16]; +}; + +struct Mtuopt { + uchar type; + uchar len; + uchar reserv[2]; + uchar mtu[4]; +}; + +struct Ipaddrsopt { + uchar type; + uchar len; + uchar reserv[2]; + uchar lifetime[4]; + uchar addrs[]; }; uchar v6allroutersL[IPaddrlen] = { @@ -132,14 +158,9 @@ uchar v6defmask[IPaddrlen] = { 0, 0, 0, 0 }; -enum -{ - Vadd, - Vremove, - Vunbind, - Vaddpref6, - Vra6, -}; +#pragma varargck argpos ralog 1 + +#define RALOG "v6routeradv" static void ralog(char *fmt, ...) @@ -153,10 +174,106 @@ ralog(char *fmt, ...) syslog(debug, RALOG, msg); } +void +v6paraminit(Conf *cf) +{ + cf->sendra = cf->recvra = 0; + cf->mflag = 0; + cf->oflag = 0; + cf->linkmtu = DEFMTU; + cf->maxraint = Maxv6initraintvl; + cf->minraint = Maxv6initraintvl / 4; + cf->reachtime = V6reachabletime; + cf->rxmitra = V6retranstimer; + cf->ttl = MAXTTL; + + cf->routerlt = 0; + + cf->prefixlen = 64; + cf->onlink = 0; + cf->autoflag = 0; + cf->validlt = cf->preflt = ~0L; +} + +void +parse6pref(int argc, char **argv) +{ + switch(argc){ + case 6: + conf.preflt = strtoul(argv[5], 0, 10); + /* fall through */ + case 5: + conf.validlt = strtoul(argv[4], 0, 10); + /* fall through */ + case 4: + conf.autoflag = (atoi(argv[3]) != 0); + /* fall through */ + case 3: + conf.onlink = (atoi(argv[2]) != 0); + /* fall through */ + case 2: + conf.prefixlen = atoi(argv[1]); + /* fall through */ + case 1: + if (parseip(conf.v6pref, argv[0]) == -1) + sysfatal("bad address %s", argv[0]); + break; + } + DEBUG("parse6pref: pref %I len %d", conf.v6pref, conf.prefixlen); +} + +/* parse router advertisement (keyword, value) pairs */ +void +parse6ra(int argc, char **argv) +{ + int i, argsleft; + char *kw, *val; + + if (argc % 2 != 0) + usage(); + + i = 0; + for (argsleft = argc; argsleft > 1; argsleft -= 2) { + kw = argv[i]; + val = argv[i+1]; + if (strcmp(kw, "recvra") == 0) + conf.recvra = (atoi(val) != 0); + else if (strcmp(kw, "sendra") == 0) + conf.sendra = (atoi(val) != 0); + else if (strcmp(kw, "mflag") == 0) + conf.mflag = (atoi(val) != 0); + else if (strcmp(kw, "oflag") == 0) + conf.oflag = (atoi(val) != 0); + else if (strcmp(kw, "maxraint") == 0) + conf.maxraint = atoi(val); + else if (strcmp(kw, "minraint") == 0) + conf.minraint = atoi(val); + else if (strcmp(kw, "linkmtu") == 0) + conf.linkmtu = atoi(val); + else if (strcmp(kw, "reachtime") == 0) + conf.reachtime = atoi(val); + else if (strcmp(kw, "rxmitra") == 0) + conf.rxmitra = atoi(val); + else if (strcmp(kw, "ttl") == 0) + conf.ttl = atoi(val); + else if (strcmp(kw, "routerlt") == 0) + conf.routerlt = atoi(val); + else { + warning("bad ra6 keyword %s", kw); + usage(); + } + i += 2; + } + + /* consistency check */ + if (conf.maxraint < conf.minraint) + sysfatal("maxraint %d < minraint %d", + conf.maxraint, conf.minraint); +} + void ea2lla(uchar *lla, uchar *ea) { - assert(IPaddrlen == 16); memset(lla, 0, IPaddrlen); lla[0] = 0xFE; lla[1] = 0x80; @@ -170,104 +287,19 @@ ea2lla(uchar *lla, uchar *ea) lla[15] = ea[5]; } -void -ipv62smcast(uchar *smcast, uchar *a) +int +findllip(uchar *ip, Ipifc *ifc) { - assert(IPaddrlen == 16); - memset(smcast, 0, IPaddrlen); - smcast[0] = 0xFF; - smcast[1] = 0x02; - smcast[11] = 0x1; - smcast[12] = 0xFF; - smcast[13] = a[13]; - smcast[14] = a[14]; - smcast[15] = a[15]; -} + Iplifc *lifc; -void -v6paraminit(Conf *cf) -{ - cf->sendra = cf->recvra = 0; - cf->mflag = 0; - cf->oflag = 0; - cf->maxraint = Maxv6initraintvl; - cf->minraint = Maxv6initraintvl / 4; - cf->linkmtu = 1500; - cf->reachtime = V6reachabletime; - cf->rxmitra = V6retranstimer; - cf->ttl = MAXTTL; - - cf->routerlt = 0; - - cf->prefixlen = 64; - cf->onlink = 0; - cf->autoflag = 0; - cf->validlt = cf->preflt = ~0L; -} - -static char * -optname(unsigned opt) -{ - static char buf[32]; - - if(opt >= nelem(icmp6opts) || icmp6opts[opt] == nil) { - snprint(buf, sizeof buf, "unknown option %d", opt); - return buf; - } else - return icmp6opts[opt]; -} - -static char* -opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe) -{ - int otype, osz, pktlen; - uchar *a; - char *p = sps, *e = spe; - - a = ps; - for (pktlen = pe - ps; pktlen > 0; pktlen -= osz) { - otype = a[0]; - osz = a[1] * 8; - - switch (otype) { - default: - return seprint(p, e, " option=%s ", optname(otype)); - case V6nd_srclladdr: - case V6nd_targlladdr: - 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), - a+2); - break; - case V6nd_pfxinfo: - if(pktlen < osz || osz != 32) - return seprint(p, e, " option=%s: bad size=%d", - optname(otype), osz); - - p = seprint(p, e, " option=%s pref=%I preflen=%3.3d" - " lflag=%1.1d aflag=%1.1d unused1=%1.1d" - " validlt=%ud preflt=%ud unused2=%1.1d", - optname(otype), a+16, (int)(*(a+2)), - (*(a+3) & (1 << 7)) != 0, - (*(a+3) & (1 << 6)) != 0, - (*(a+3) & 63) != 0, - NetL(a+4), NetL(a+8), NetL(a+12)!=0); - break; + for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){ + if(ISIPV6LINKLOCAL(lifc->ip)){ + ipmove(ip, lifc->ip); + return 1; } - a += osz; } - return p; -} - -static void -catch(void *a, char *msg) -{ - USED(a); - if(strstr(msg, "alarm")) - noted(NCONT); - else - noted(NDFLT); + ipmove(ip, v6Unspecified); + return 0; } static int @@ -277,13 +309,13 @@ dialicmpv6(uchar *ip, int port) int fd, cfd; snprint(addr, sizeof(addr), "%s/icmpv6!%I!%d!r", conf.mpoint, ip, port); - snprint(local, sizeof(local), "%I!%d", conf.laddr, port); + snprint(local, sizeof(local), "%I!%d", conf.lladdr, 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); + fprint(cfd, "addmulti %I", conf.lladdr); close(cfd); return fd; } @@ -301,7 +333,7 @@ arpenter(uchar *ip, uchar *mac) 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); + n = snprint(buf, sizeof buf, "add %s %I %E %I\n", conf.type, ip, mac, conf.lladdr); if(write(fd, buf, n) != n) { warning("arpenter: %s: %r", buf); close(fd); @@ -341,35 +373,6 @@ arpcheck(uchar *ip) 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) @@ -417,8 +420,8 @@ Again: } warning("found dup entry in arp cache"); - doremove(); - return 0; + ipunconfig(); + return -1; } static int @@ -434,21 +437,6 @@ recvra6on(Ipifc *ifc) return IsHostNoRecv; } -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, uchar *dst) { @@ -459,14 +447,14 @@ sendrs(int fd, uchar *dst) memset(buf, 0, sizeof buf); - rs = (Routersol *)buf; + rs = (Routersol*)buf; rs->type = ICMP6_RS; ipmove(rs->dst, dst); - ipmove(rs->src, conf.laddr); + ipmove(rs->src, conf.lladdr); pktlen = sizeof *rs; if(conf.hwalen > 0){ - llao = (Lladdropt *)&buf[pktlen]; + llao = (Lladdropt*)&buf[pktlen]; llao->type = V6nd_srclladdr; llao->len = (2+7+conf.hwalen)/8; memmove(llao->lladdr, conf.hwa, conf.hwalen); @@ -494,8 +482,6 @@ recvrarouter(uchar buf[], int pktlen) USED(buf, pktlen); } -/* host receiving a router advertisement calls this */ - static void ewrite(int fd, char *str) { @@ -515,9 +501,9 @@ issuebasera6(Conf *cf) char *cfg; cfg = smprint("ra6 mflag %d oflag %d reachtime %d rxmitra %d " - "ttl %d routerlt %d", + "ttl %d routerlt %d linkmtu %d", cf->mflag, cf->oflag, cf->reachtime, cf->rxmitra, - cf->ttl, cf->routerlt); + cf->ttl, cf->routerlt, cf->linkmtu); ewrite(cf->cfd, cfg); free(cfg); } @@ -527,10 +513,8 @@ issuerara6(Conf *cf) { char *cfg; - cfg = smprint("ra6 sendra %d recvra %d maxraint %d minraint %d " - "linkmtu %d", - cf->sendra, cf->recvra, cf->maxraint, cf->minraint, - cf->linkmtu); + cfg = smprint("ra6 sendra %d recvra %d maxraint %d minraint %d", + cf->sendra, cf->recvra, cf->maxraint, cf->minraint); ewrite(cf->cfd, cfg); free(cfg); } @@ -546,6 +530,35 @@ issueadd6(Conf *cf) free(cfg); } +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); +} + static int seen(Conf *cf) { @@ -563,14 +576,78 @@ seen(Conf *cf) return 0; } +static int +pnames(uchar *d, int nd, char *s) +{ + uchar *de = d + nd; + int l; + + if(nd < 1) + return -1; + for(; *s != 0; s++){ + for(l = 0; *s != 0 && *s != '.' && *s != ' '; l++) + s++; + + d += l+1; + if(d >= de || l > 077) + return -1; + + d[-l-1] = l; + memmove(d-l, s-l, l); + + if(*s != '.') + *d++ = 0; + } + return d - (de - nd); +} + +static int +gnames(char *d, int nd, uchar *s, int ns) +{ + uchar *se = s + ns; + char *de = d + nd; + int l; + + if(nd < 1 || ns < 1) + return -1; + l = *s++ & 077; + while(l > 0){ + if(d + l >= de || s + l >= se) + return -1; + + memmove(d, s, l); + d += l; + s += l; + + l = *s++ & 077; + if(l > 0) + *d++ = '.'; + else { + if(s >= se) + break; + + l = *s++ & 077; + if(l == 0) + break; + *d++ = ' '; + } + } + *d = 0; + return d - (de - nd); +} + +/* + * host receiving a router advertisement calls this + */ static void recvrahost(uchar buf[], int pktlen) { - int m, n, optype, needrefresh; - uchar src[IPaddrlen]; + char dnsdomain[sizeof(conf.dnsdomain)]; + int m, n, optype; Lladdropt *llao; Mtuopt *mtuo; Prefixopt *prfo; + Ipaddrsopt *addrso; Routeradv *ra; m = sizeof *ra; @@ -584,22 +661,27 @@ recvrahost(uchar buf[], int pktlen) conf.ttl = ra->cttl; conf.mflag = (MFMASK & ra->mor); conf.oflag = (OCMASK & ra->mor); - conf.routerlt = nhgets(ra->routerlt); + conf.routerlt = nhgets(ra->routerlt); conf.reachtime = nhgetl(ra->rchbltime); - conf.rxmitra = nhgetl(ra->rxmtimer); - issuebasera6(&conf); + conf.rxmitra = nhgetl(ra->rxmtimer); + conf.linkmtu = DEFMTU; - needrefresh = 0; + memset(conf.dns, 0, sizeof(conf.dns)); + memset(conf.fs, 0, sizeof(conf.fs)); + memset(conf.auth, 0, sizeof(conf.auth)); + memset(conf.dnsdomain, 0, sizeof(conf.dnsdomain)); + + /* process options */ while(pktlen - m >= 8) { n = m; optype = buf[n]; m += 8 * buf[n+1]; - if(pktlen < m) + if(m <= n || pktlen < m) return; switch (optype) { case V6nd_srclladdr: - llao = (Lladdropt *)&buf[n]; + llao = (Lladdropt*)&buf[n]; if(llao->len == 1 && conf.hwalen == 6) arpenter(ra->src, llao->lladdr); break; @@ -607,63 +689,110 @@ recvrahost(uchar buf[], int pktlen) mtuo = (Mtuopt*)&buf[n]; conf.linkmtu = nhgetl(mtuo->mtu); break; - case V6nd_pfxinfo: - prfo = (Prefixopt*)&buf[n]; - if(prfo->len != 4) + + case V6nd_rdnssl: + addrso = (Ipaddrsopt*)&buf[n]; + if(gnames(dnsdomain, sizeof(dnsdomain), + addrso->addrs, (addrso->len - 1)*8) <= 0) break; + addnames(conf.dnsdomain, dnsdomain, sizeof(conf.dnsdomain)); + break; - 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(conf.routerlt == 0) - ipmove(conf.gaddr, IPnoaddr); - else if((prfo->lar & RFMASK) != 0) - ipmove(conf.gaddr, prfo->pref); - else - ipmove(conf.gaddr, ra->src); - - /* report prefix only once */ - if(seen(&conf)) + case V6nd_rdns: + addrso = (Ipaddrsopt*)&buf[n]; + n = (addrso->len - 1) * 8; + if(n == 0 || n % IPaddrlen) break; + addaddrs(conf.dns, sizeof(conf.dns), addrso->addrs, n); + break; - if(conf.prefixlen == 0 - || !validip(conf.v6pref) - || isv4(conf.v6pref) - || ipcmp(conf.v6pref, v6loopback) == 0 - || ISIPV6MCAST(conf.v6pref) - || ISIPV6LINKLOCAL(conf.v6pref)){ - ralog("igoring bogus prefix from %I on %s; pfx %I %M", - ra->src, conf.dev, conf.v6pref, conf.mask); + case V6nd_9fs: + addrso = (Ipaddrsopt*)&buf[n]; + n = (addrso->len - 1) * 8; + if(n == 0 || n % IPaddrlen || !plan9) break; - } - - ralog("got initial RA from %I on %s; pfx %I %M", - ra->src, conf.dev, conf.v6pref, conf.mask); - - if(validip(conf.gaddr)){ - memmove(src, conf.v6pref, 8); - memmove(src+8, conf.laddr+8, 8); - adddefroute(conf.gaddr, conf.laddr, src, conf.mask); - } - needrefresh = 1; + addaddrs(conf.fs, sizeof(conf.fs), addrso->addrs, n); + break; + case V6nd_9auth: + addrso = (Ipaddrsopt*)&buf[n]; + n = (addrso->len - 1) * 8; + if(n == 0 || n % IPaddrlen || !plan9) + break; + addaddrs(conf.auth, sizeof(conf.auth), addrso->addrs, n); break; } } + issuebasera6(&conf); - if(needrefresh) + /* process prefixes */ + m = sizeof *ra; + while(pktlen - m >= 8) { + n = m; + optype = buf[n]; + m += 8 * buf[n+1]; + if(m <= n || pktlen < m) + return; + + if(optype != V6nd_pfxinfo) + continue; + + prfo = (Prefixopt*)&buf[n]; + if(prfo->len != 4) + continue; + + conf.prefixlen = prfo->plen & 127; + genipmkask(conf.mask, conf.prefixlen); + maskip(prfo->pref, conf.mask, conf.v6pref); + memmove(conf.laddr, conf.v6pref, 8); + memmove(conf.laddr+8, conf.lladdr+8, 8); + conf.onlink = ((prfo->lar & OLMASK) != 0); + conf.autoflag = ((prfo->lar & AFMASK) != 0); + conf.validlt = nhgetl(prfo->validlt); + conf.preflt = nhgetl(prfo->preflt); + + if(conf.routerlt == 0) + ipmove(conf.gaddr, IPnoaddr); + else if((prfo->lar & RFMASK) != 0) + ipmove(conf.gaddr, prfo->pref); + else + ipmove(conf.gaddr, ra->src); + + if(conf.prefixlen < 1 + || conf.prefixlen > 64 + || !validip(conf.v6pref) + || isv4(conf.v6pref) + || ipcmp(conf.v6pref, v6loopback) == 0 + || ISIPV6MCAST(conf.v6pref) + || ISIPV6LINKLOCAL(conf.v6pref)){ + if(!seen(&conf)) + ralog("igoring bogus prefix from %I on %s; pfx %I %M", + ra->src, conf.dev, conf.v6pref, conf.mask); + continue; + } + + /* add prefix and update parameters */ + issueadd6(&conf); + + /* report this prefix configuration only once */ + if(seen(&conf)) + continue; + + ralog("got RA from %I on %s; pfx %I %M", + ra->src, conf.dev, conf.v6pref, conf.mask); + + if(validip(conf.gaddr)) + adddefroute(conf.gaddr, conf.lladdr, conf.laddr, conf.mask); + + if(beprimary) + putndb(); refresh(); + } } /* * daemon to receive router advertisements from routers */ -void +static int recvra6(void) { int fd, n, sendrscnt, recvracnt, sleepfor; @@ -674,30 +803,37 @@ recvra6(void) if(ifc == nil) sysfatal("can't read ipifc: %r"); - if(!findllip(conf.laddr, ifc)) + if(!findllip(conf.lladdr, 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; + ralog("recvra6 on %s", conf.dev); + + /* wait for initial RA */ + return (int)(uintptr)rendezvous(recvra6, (void*)0); case 0: break; } + procsetname("recvra6 on %s %I", conf.dev, conf.lladdr); + notify(catch); - procsetname("recvra6 on %s %I", conf.dev, conf.laddr); - ralog("recvra6 on %s", conf.dev); + sendrscnt = 0; + if(recvra6on(ifc) == IsHostRecv){ + sendrs(fd, v6allroutersL); + sendrscnt = Maxv6rss; + } + + recvracnt = Maxv6initras; sleepfor = Minv6interradelay; + for (;;) { alarm(sleepfor); n = read(fd, buf, sizeof buf); @@ -711,34 +847,27 @@ recvra6(void) if(ifc == nil) { ralog("recvra6: can't read router params on %s, quitting on %s", conf.mpoint, conf.dev); + if(sendrscnt >= 0) + rendezvous(recvra6, (void*)-1); exits(nil); } - + if(n <= 0) { if(sendrscnt > 0) { sendrscnt--; - if(recvra6on(ifc) == IsHostRecv) - sendrs(fd, v6allroutersL); + sendrs(fd, v6allroutersL); sleepfor = V6rsintvl + nrand(100); } if(sendrscnt == 0) { sendrscnt--; - sleepfor = 0; ralog("recvra6: no router advs after %d sols on %s", Maxv6rss, conf.dev); + rendezvous(recvra6, (void*)0); + sleepfor = 0; } continue; } - /* got at least initial ra; no whining */ - sendrscnt = -1; - sleepfor = 0; - - if(++recvracnt >= Maxv6initras){ - recvracnt = 0; - sleepfor = Maxv6radelay; - } - switch (recvra6on(ifc)) { case IsRouter: recvrarouter(buf, n); @@ -748,8 +877,23 @@ recvra6(void) break; case IsHostNoRecv: ralog("recvra6: recvra off, quitting on %s", conf.dev); + if(sendrscnt >= 0) + rendezvous(recvra6, (void*)-1); exits(nil); } + + /* got at least initial ra; no whining */ + if(sendrscnt >= 0) + rendezvous(recvra6, (void*)1); + sendrscnt = -1; + sleepfor = 0; + + if(recvracnt > 0) + recvracnt--; + else { + recvracnt = Maxv6initras; + sleepfor = Maxv6radelay; + } } } @@ -758,7 +902,7 @@ recvra6(void) * 0 -- no arp table updates * 1 -- successful arp table update */ -int +static int recvrs(uchar *buf, int pktlen, uchar *sol) { int n; @@ -766,11 +910,11 @@ recvrs(uchar *buf, int pktlen, uchar *sol) Lladdropt *llao; n = sizeof *rs + sizeof *llao; - rs = (Routersol *)buf; + rs = (Routersol*)buf; if(pktlen < n) return 0; - llao = (Lladdropt *)&buf[sizeof *rs]; + llao = (Lladdropt*)&buf[sizeof *rs]; if(llao->type != V6nd_srclladdr || llao->len != 1 || conf.hwalen != 6) return 0; @@ -787,21 +931,28 @@ recvrs(uchar *buf, int pktlen, uchar *sol) return 1; } -void -sendra(int fd, uchar *dst, int rlt, Ipifc *ifc) +static void +sendra(int fd, uchar *dst, int rlt, Ipifc *ifc, Ndb *db) { - uchar buf[1024]; - Iplifc *lifc; - Lladdropt *llao; + uchar dns[sizeof(conf.dns)], fs[sizeof(conf.fs)], auth[sizeof(conf.auth)]; + char dnsdomain[sizeof(conf.dnsdomain)]; + Ipaddrsopt *addrso; Prefixopt *prfo; + Iplifc *lifc; Routeradv *ra; - int pktlen; + uchar buf[1024]; + int pktlen, n; + + memset(dns, 0, sizeof(dns)); + memset(fs, 0, sizeof(fs)); + memset(auth, 0, sizeof(auth)); + memset(dnsdomain, 0, sizeof(dnsdomain)); memset(buf, 0, sizeof buf); - ra = (Routeradv *)buf; + ra = (Routeradv*)buf; ipmove(ra->dst, dst); - ipmove(ra->src, conf.laddr); + ipmove(ra->src, conf.lladdr); ra->type = ICMP6_RA; ra->cttl = conf.ttl; if(conf.mflag > 0) @@ -821,7 +972,7 @@ sendra(int fd, uchar *dst, int rlt, Ipifc *ifc) * link layer address option */ if(conf.hwalen > 0){ - llao = (Lladdropt *)&buf[pktlen]; + Lladdropt *llao = (Lladdropt *)&buf[pktlen]; llao->type = V6nd_srclladdr; llao->len = (2+7+conf.hwalen)/8; memmove(llao->lladdr, conf.hwa, conf.hwalen); @@ -832,13 +983,15 @@ sendra(int fd, uchar *dst, int rlt, Ipifc *ifc) 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 = (Prefixopt*)&buf[pktlen]; prfo->type = V6nd_pfxinfo; prfo->len = 4; prfo->plen = masklen(lifc->mask) & 127; @@ -849,55 +1002,110 @@ sendra(int fd, uchar *dst, int rlt, Ipifc *ifc) hnputl(prfo->validlt, lifc->validlt); hnputl(prfo->preflt, lifc->preflt); pktlen += 8 * prfo->len; + + /* get ndb configuration for this prefix */ + ipmove(conf.laddr, lifc->ip); + ndb2conf(db, lifc->net); + + addaddrs(dns, sizeof(dns), conf.dns, sizeof(conf.dns)); + addaddrs(fs, sizeof(fs), conf.fs, sizeof(conf.fs)); + addaddrs(auth, sizeof(auth), conf.auth, sizeof(conf.auth)); + + addnames(dnsdomain, conf.dnsdomain, sizeof(dnsdomain)); } + addrso = (Ipaddrsopt*)&buf[pktlen]; + n = pnames(addrso->addrs, sizeof buf - 8 - pktlen, dnsdomain); + if(n > 0){ + addrso->type = V6nd_rdnssl; + addrso->len = 1 + ((n + 7) / 8); + hnputl(addrso->lifetime, ~0L); + pktlen += 8 * addrso->len; + } + + if((n = countaddrs(dns, sizeof(dns))) > 0 && pktlen+8+n*IPaddrlen <= sizeof buf) { + addrso = (Ipaddrsopt*)&buf[pktlen]; + addrso->type = V6nd_rdns; + addrso->len = 1 + n*2; + memmove(addrso->addrs, dns, n*IPaddrlen); + hnputl(addrso->lifetime, ~0L); + pktlen += 8 * addrso->len; + } + + if(!plan9) + goto send; + + /* send plan9 specific options */ + if((n = countaddrs(fs, sizeof(fs))) > 0 && pktlen+8+n*IPaddrlen <= sizeof buf) { + addrso = (Ipaddrsopt*)&buf[pktlen]; + addrso->type = V6nd_9fs; + addrso->len = 1 + n*2; + memmove(addrso->addrs, fs, n*IPaddrlen); + hnputl(addrso->lifetime, ~0L); + pktlen += 8 * addrso->len; + } + if((n = countaddrs(auth, sizeof(auth))) > 0 && pktlen+8+n*IPaddrlen <= sizeof buf) { + addrso = (Ipaddrsopt*)&buf[pktlen]; + addrso->type = V6nd_9auth; + addrso->len = 1 + n*2; + memmove(addrso->addrs, auth, n*IPaddrlen); + hnputl(addrso->lifetime, ~0L); + pktlen += 8 * addrso->len; + } + +send: write(fd, buf, pktlen); } /* * daemon to send router advertisements to hosts */ -void +static void sendra6(void) { int fd, n, sleepfor, nquitmsgs; uchar buf[4096], dst[IPaddrlen]; Ipifc *ifc; + Ndb *db; + + db = opendatabase(); + if(db == nil) + warning("couldn't open ndb: %r"); ifc = readipifc(conf.mpoint, nil, myifc); if(ifc == nil) sysfatal("can't read ipifc: %r"); - if(!findllip(conf.laddr, ifc)) + if(!findllip(conf.lladdr, ifc)) sysfatal("no link local address"); fd = dialicmpv6(v6allroutersL, ICMP6_RS); if(fd < 0) sysfatal("can't open icmp_rs connection: %r"); - notify(catch); - nquitmsgs = Maxv6finalras; - switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){ case -1: sysfatal("can't fork: %r"); default: close(fd); + ralog("sendra6 on %s", conf.dev); return; case 0: break; } + procsetname("sendra6 on %s %I", conf.dev, conf.lladdr); + notify(catch); - procsetname("sendra6 on %s %I", conf.dev, conf.laddr); - ralog("sendra6 on %s", conf.dev); + nquitmsgs = Maxv6finalras; sleepfor = 100 + jitter(); + for (;;) { alarm(sleepfor); n = read(fd, buf, sizeof buf); sleepfor = alarm(0); - if(n > 0 && recvrs(buf, n, dst) > 0) - sendra(fd, dst, 1, ifc); + if(ifc->sendra6 > 0 && n > 0 && recvrs(buf, n, dst) > 0) + sendra(fd, dst, 1, ifc, db); /* wait for alarm to expire */ if(sleepfor > 100) @@ -913,31 +1121,30 @@ sendra6(void) if(ifc->sendra6 <= 0){ if(nquitmsgs > 0) { nquitmsgs--; - sendra(fd, v6allnodesL, 0, ifc); + sendra(fd, v6allnodesL, 0, ifc, nil); continue; - } else { - ralog("sendra6: sendra off, quitting on %s", conf.dev); - exits(nil); } + ralog("sendra6: sendra off on %s, quitting on %s", + conf.mpoint, conf.dev); + exits(nil); } - sendra(fd, v6allnodesL, 1, ifc); + db = opendatabase(); + sendra(fd, v6allnodesL, 1, ifc, db); sleepfor = randint(ifc->rp.minraint, ifc->rp.maxraint); } } -void +static void startra6(void) { static char routeon[] = "iprouting 1"; - mklladdr(); - if(conf.recvra > 0) recvra6(); if(conf.sendra > 0) { if(write(conf.cfd, routeon, sizeof routeon - 1) < 0) { - warning("write (iprouting 1) failed: %r"); + warning("write (%s) failed: %r", routeon); return; } sendra6(); diff --git a/sys/src/cmd/ip/ipconfig/main.c b/sys/src/cmd/ip/ipconfig/main.c index a699994cd..e051821d9 100644 --- a/sys/src/cmd/ip/ipconfig/main.c +++ b/sys/src/cmd/ip/ipconfig/main.c @@ -3,216 +3,49 @@ */ #include #include -#include #include +#include #include -#include "../dhcp.h" #include "ipconfig.h" +#include "../dhcp.h" #include /* genrandom() */ -#define DEBUG if(debug)warning - -/* possible verbs */ -enum -{ - /* commands */ - Vadd, - Vremove, - Vunbind, - Vaddpref6, - Vra6, - /* media */ - Vether, - Vgbe, - Vppp, - Vloopback, - Vtorus, - Vtree, - Vpkt, -}; - -enum -{ - Taddr, - Taddrs, - Tstr, - Tbyte, - Tulong, - Tvec, -}; - -typedef struct Option Option; -struct Option -{ - char *name; - int type; -}; - -/* - * I was too lazy to look up the types for each of these - * options. If someone feels like it, please mail me a - * corrected array -- presotto - */ -Option option[256] = -{ -[OBmask] { "ipmask", Taddr }, -[OBtimeoff] { "timeoff", Tulong }, -[OBrouter] { "ipgw", Taddrs }, -[OBtimeserver] { "time", Taddrs }, -[OBnameserver] { "name", Taddrs }, -[OBdnserver] { "dns", Taddrs }, -[OBlogserver] { "log", Taddrs }, -[OBcookieserver] { "cookie", Taddrs }, -[OBlprserver] { "lpr", Taddrs }, -[OBimpressserver] { "impress", Taddrs }, -[OBrlserver] { "rl", Taddrs }, -[OBhostname] { "sys", Tstr }, -[OBbflen] { "bflen", Tulong }, -[OBdumpfile] { "dumpfile", Tstr }, -[OBdomainname] { "dom", Tstr }, -[OBswapserver] { "swap", Taddrs }, -[OBrootpath] { "rootpath", Tstr }, -[OBextpath] { "extpath", Tstr }, -[OBipforward] { "ipforward", Taddrs }, -[OBnonlocal] { "nonlocal", Taddrs }, -[OBpolicyfilter] { "policyfilter", Taddrs }, -[OBmaxdatagram] { "maxdatagram", Tulong }, -[OBttl] { "ttl", Tulong }, -[OBpathtimeout] { "pathtimeout", Taddrs }, -[OBpathplateau] { "pathplateau", Taddrs }, -[OBmtu] { "mtu", Tulong }, -[OBsubnetslocal] { "subnetslocal", Taddrs }, -[OBbaddr] { "baddr", Taddrs }, -[OBdiscovermask] { "discovermask", Taddrs }, -[OBsupplymask] { "supplymask", Taddrs }, -[OBdiscoverrouter] { "discoverrouter", Taddrs }, -[OBrsserver] { "rs", Taddrs }, -[OBstaticroutes] { "staticroutes", Taddrs }, -[OBtrailerencap] { "trailerencap", Taddrs }, -[OBarptimeout] { "arptimeout", Tulong }, -[OBetherencap] { "etherencap", Taddrs }, -[OBtcpttl] { "tcpttl", Tulong }, -[OBtcpka] { "tcpka", Tulong }, -[OBtcpkag] { "tcpkag", Tulong }, -[OBnisdomain] { "nisdomain", Tstr }, -[OBniserver] { "ni", Taddrs }, -[OBntpserver] { "ntp", Taddrs }, -[OBnetbiosns] { "netbiosns", Taddrs }, -[OBnetbiosdds] { "netbiosdds", Taddrs }, -[OBnetbiostype] { "netbiostype", Taddrs }, -[OBnetbiosscope] { "netbiosscope", Taddrs }, -[OBxfontserver] { "xfont", Taddrs }, -[OBxdispmanager] { "xdispmanager", Taddrs }, -[OBnisplusdomain] { "nisplusdomain", Tstr }, -[OBnisplusserver] { "nisplus", Taddrs }, -[OBhomeagent] { "homeagent", Taddrs }, -[OBsmtpserver] { "smtp", Taddrs }, -[OBpop3server] { "pop3", Taddrs }, -[OBnntpserver] { "nntp", Taddrs }, -[OBwwwserver] { "www", Taddrs }, -[OBfingerserver] { "finger", Taddrs }, -[OBircserver] { "irc", Taddrs }, -[OBstserver] { "st", Taddrs }, -[OBstdaserver] { "stdar", Taddrs }, - -[ODipaddr] { "ipaddr", Taddr }, -[ODlease] { "lease", Tulong }, -[ODoverload] { "overload", Taddr }, -[ODtype] { "type", Tbyte }, -[ODserverid] { "serverid", Taddr }, -[ODparams] { "params", Tvec }, -[ODmessage] { "message", Tstr }, -[ODmaxmsg] { "maxmsg", Tulong }, -[ODrenewaltime] { "renewaltime", Tulong }, -[ODrebindingtime] { "rebindingtime", Tulong }, -[ODvendorclass] { "vendorclass", Tvec }, -[ODclientid] { "clientid", Tvec }, -[ODtftpserver] { "tftp", Taddr }, -[ODbootfile] { "bootfile", Tstr }, -}; - -uchar defrequested[] = { - OBmask, OBrouter, OBdnserver, OBhostname, OBdomainname, OBntpserver, -}; - -uchar requested[256]; -int nrequested; - -int Oflag; -int beprimary = -1; Conf conf; -int debug; -int dodhcp; -int dolog; -int dondbconfig = 0; -int dupl_disc = 1; /* flag: V6 duplicate neighbor discovery */ -Ctl *firstctl, **ctll; -Ipifc *ifc; -int ipv6auto = 0; int myifc = -1; -char *dbfile; -char *ndboptions; +int beprimary = -1; int noconfig; -int nodhcpwatch; -char optmagic[4] = { 0x63, 0x82, 0x53, 0x63 }; +Ipifc *ifc; +Ctl *firstctl, **ctll = &firstctl; + +int debug; +int dolog; + int plan9 = 1; +int Oflag; +int rflag; + +int dodhcp; +int nodhcpwatch; int sendhostname; +char *ndboptions; + +int ipv6auto; +int dupl_disc = 1; /* flag: V6 duplicate neighbor discovery */ + +int dondbconfig; +char *dbfile; static char logfile[] = "ipconfig"; -char *verbs[] = { -[Vadd] "add", -[Vremove] "remove", -[Vunbind] "unbind", -[Vether] "ether", -[Vgbe] "gbe", -[Vppp] "ppp", -[Vloopback] "loopback", -[Vaddpref6] "add6", -[Vra6] "ra6", -[Vtorus] "torus", -[Vtree] "tree", -[Vpkt] "pkt", -}; +static void binddevice(void); +static void controldevice(void); +extern void pppbinddev(void); -int addoption(char*); -void binddevice(void); -void controldevice(void); -void dhcpquery(int, int); -void dhcprecv(void); -void dhcpsend(int); -void dhcptimer(void); -void dhcpwatch(int); -void doadd(int); -void doremove(void); -void dounbind(void); -void getoptions(uchar*); -int ip4cfg(void); -int ip6cfg(void); -void mkclientid(void); -void ndbconfig(void); -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 optgetp9addrs(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); -char* optgetx(uchar*, uchar); -Bootp* parsebootp(uchar*, int); -int parseoptions(uchar *p, int n); -int parseverb(char*); -void pppbinddev(void); -void putndb(void); +static void doadd(void); +static void doremove(void); +static void dounbind(void); +static void ndbconfig(void); void usage(void) @@ -224,6 +57,29 @@ usage(void) exits("usage"); } +static void +init(void) +{ + srand(truerand()); + fmtinstall('E', eipfmt); + fmtinstall('I', eipfmt); + fmtinstall('M', eipfmt); + 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) + conf.cputype = "386"; + + v6paraminit(&conf); + + dhcpinit(); +} + void warning(char *fmt, ...) { @@ -274,82 +130,6 @@ parsenorm(int argc, char **argv) } } -static void -parse6pref(int argc, char **argv) -{ - switch(argc){ - case 6: - conf.preflt = strtoul(argv[5], 0, 10); - /* fall through */ - case 5: - conf.validlt = strtoul(argv[4], 0, 10); - /* fall through */ - case 4: - conf.autoflag = (atoi(argv[3]) != 0); - /* fall through */ - case 3: - conf.onlink = (atoi(argv[2]) != 0); - /* fall through */ - case 2: - conf.prefixlen = atoi(argv[1]); - /* fall through */ - case 1: - if (parseip(conf.v6pref, argv[0]) == -1) - sysfatal("bad address %s", argv[0]); - break; - } - DEBUG("parse6pref: pref %I len %d", conf.v6pref, conf.prefixlen); -} - -/* parse router advertisement (keyword, value) pairs */ -static void -parse6ra(int argc, char **argv) -{ - int i, argsleft; - char *kw, *val; - - if (argc % 2 != 0) - usage(); - - i = 0; - for (argsleft = argc; argsleft > 1; argsleft -= 2) { - kw = argv[i]; - val = argv[i+1]; - if (strcmp(kw, "recvra") == 0) - conf.recvra = (atoi(val) != 0); - else if (strcmp(kw, "sendra") == 0) - conf.sendra = (atoi(val) != 0); - else if (strcmp(kw, "mflag") == 0) - conf.mflag = (atoi(val) != 0); - else if (strcmp(kw, "oflag") == 0) - conf.oflag = (atoi(val) != 0); - else if (strcmp(kw, "maxraint") == 0) - conf.maxraint = atoi(val); - else if (strcmp(kw, "minraint") == 0) - conf.minraint = atoi(val); - else if (strcmp(kw, "linkmtu") == 0) - conf.linkmtu = atoi(val); - else if (strcmp(kw, "reachtime") == 0) - conf.reachtime = atoi(val); - else if (strcmp(kw, "rxmitra") == 0) - conf.rxmitra = atoi(val); - else if (strcmp(kw, "ttl") == 0) - conf.ttl = atoi(val); - else if (strcmp(kw, "routerlt") == 0) - conf.routerlt = atoi(val); - else { - warning("bad ra6 keyword %s", kw); - usage(); - } - i += 2; - } - - /* consistency check */ - if (conf.maxraint < conf.minraint) - sysfatal("maxraint %d < minraint %d", - conf.maxraint, conf.minraint); -} - static char* finddev(char *dir, char *name, char *dev) { @@ -374,45 +154,32 @@ finddev(char *dir, char *name, char *dev) return dev; } +/* look for an action */ static int -findifc(char *net, char *dev) +parseverb(char *name) { - Ipifc *nifc; - - ifc = readipifc(net, ifc, -1); - for(nifc = ifc; nifc != nil; nifc = nifc->next) - if(strcmp(nifc->dev, dev) == 0) - return nifc->index; + static char *verbs[] = { + [Vadd] "add", + [Vremove] "remove", + [Vunbind] "unbind", + [Vether] "ether", + [Vgbe] "gbe", + [Vppp] "ppp", + [Vloopback] "loopback", + [Vaddpref6] "add6", + [Vra6] "ra6", + [Vtorus] "torus", + [Vtree] "tree", + [Vpkt] "pkt", + }; + int i; + for(i = 0; i < nelem(verbs); i++) + if(verbs[i] != nil && strcmp(name, verbs[i]) == 0) + return i; return -1; } -static void -init(void) -{ - srand(truerand()); - fmtinstall('E', eipfmt); - fmtinstall('I', eipfmt); - fmtinstall('M', eipfmt); - 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) - conf.cputype = "386"; - - ctll = &firstctl; - v6paraminit(&conf); - - /* init set of requested dhcp parameters with the default */ - nrequested = sizeof defrequested; - memcpy(requested, defrequested, nrequested); -} - static int parseargs(int argc, char **argv) { @@ -498,14 +265,26 @@ parseargs(int argc, char **argv) return action; } +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; +} + void main(int argc, char **argv) { - int retry, action; + int action; Ctl *cp; init(); - retry = 0; ARGBEGIN { case '6': /* IPv6 auto config */ ipv6auto = 1; @@ -566,7 +345,7 @@ main(int argc, char **argv) beprimary = 0; break; case 'r': - retry = 1; + rflag = 1; break; case 'u': /* IPv6: duplicate neighbour disc. off */ dupl_disc = 0; @@ -607,7 +386,12 @@ main(int argc, char **argv) switch(action){ case Vadd: - doadd(retry); + if(dondbconfig){ + dodhcp = 0; + ndbconfig(); + return; + } + doadd(); break; case Vaddpref6: case Vra6: @@ -623,14 +407,51 @@ main(int argc, char **argv) exits(nil); } -void -doadd(int retry) +static int +isether(void) +{ + return strcmp(conf.type, "ether") == 0 || strcmp(conf.type, "gbe") == 0; +} + +/* create link local address */ +static void +mklladdr(void) +{ + 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.lladdr, conf.hwa); +} + +/* create a client id */ +static void +mkclientid(void) +{ + if(isether() && myetheraddr(conf.hwa, conf.dev) == 0){ + conf.hwalen = 6; + conf.hwatype = 1; + conf.cid[0] = conf.hwatype; + memmove(&conf.cid[1], conf.hwa, conf.hwalen); + conf.cidlen = conf.hwalen+1; + } else { + conf.hwatype = -1; + snprint((char*)conf.cid, sizeof conf.cid, + "plan9_%ld.%d", lrand(), getpid()); + conf.cidlen = strlen((char*)conf.cid); + } +} + +static void +doadd(void) { if(!validip(conf.laddr)){ - if(dondbconfig) - ndbconfig(); - else if(ipv6auto){ + if(ipv6auto){ mklladdr(); + ipmove(conf.laddr, conf.lladdr); dodhcp = 0; } else dodhcp = 1; @@ -645,13 +466,14 @@ doadd(int retry) } if(!validip(conf.laddr)) - if(retry && dodhcp && !noconfig){ + if(rflag && dodhcp && !noconfig){ warning("couldn't determine ip address, retrying"); dhcpwatch(1); return; } else sysfatal("no success with DHCP"); + DEBUG("adding address %I %M on %s", conf.laddr, conf.mask, conf.dev); if(noconfig) return; @@ -671,7 +493,7 @@ doadd(int retry) refresh(); } -void +static void doremove(void) { if(!validip(conf.laddr)) @@ -680,108 +502,15 @@ doremove(void) warning("can't remove %I %M: %r", conf.laddr, conf.mask); } -void +static void dounbind(void) { if(fprint(conf.cfd, "unbind") < 0) warning("can't unbind %s: %r", conf.dev); } -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; - - 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 -removeroute(uchar *dst, uchar *mask, uchar *src, uchar *smask) -{ - char *cmd; - - if(issrcspec(src, smask)) - cmd = "remove %I %M %I %M"; - else - 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); - - /* also add a source specific route */ - if(ipcmp(src, IPnoaddr) != 0 && ipcmp(src, v4prefix) != 0) - addroute(dst, mask, gaddr, laddr, src, IPallbits); -} - - -int -isether(void) -{ - return strcmp(conf.type, "ether") == 0 || strcmp(conf.type, "gbe") == 0; -} - -/* create link local address */ -void -mklladdr(void) -{ - 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); -} - -/* create a client id */ -void -mkclientid(void) -{ - if(isether() && myetheraddr(conf.hwa, conf.dev) == 0){ - conf.hwalen = 6; - conf.hwatype = 1; - conf.cid[0] = conf.hwatype; - memmove(&conf.cid[1], conf.hwa, conf.hwalen); - conf.cidlen = conf.hwalen+1; - } else { - conf.hwatype = -1; - snprint((char*)conf.cid, sizeof conf.cid, - "plan9_%ld.%d", lrand(), getpid()); - conf.cidlen = strlen((char*)conf.cid); - } -} - /* send some ctls to a device */ -void +static void controldevice(void) { char ctlfile[256]; @@ -805,7 +534,7 @@ controldevice(void) } /* bind an ip stack to a device, leave the control channel open */ -void +static void binddevice(void) { char buf[256]; @@ -867,7 +596,7 @@ ip4cfg(void) return 0; } -/* remove a logical interface to the ip stack */ +/* remove a logical interface from the ip stack */ void ipunconfig(void) { @@ -886,762 +615,15 @@ ipunconfig(void) ipmove(conf.mask, IPnoaddr); } -void -ding(void*, char *msg) -{ - if(strstr(msg, "alarm")) - noted(NCONT); - noted(NDFLT); -} - -void -dhcpquery(int needconfig, int startstate) -{ - if(needconfig) - fprint(conf.cfd, "add %I %I", IPnoaddr, IPnoaddr); - - conf.fd = openlisten(); - if(conf.fd < 0){ - conf.state = Sinit; - return; - } - notify(ding); - - conf.xid = lrand(); - conf.starttime = time(0); - conf.state = startstate; - switch(startstate){ - case Sselecting: - conf.offered = 0; - dhcpsend(Discover); - break; - case Srenewing: - dhcpsend(Request); - break; - default: - sysfatal("internal error 0"); - } - conf.resend = 0; - conf.timeout = time(0) + 4; - - while(conf.state != Sbound && conf.state != Sinit){ - dhcprecv(); - dhcptimer(); - } - close(conf.fd); - - if(needconfig) - fprint(conf.cfd, "remove %I %I", IPnoaddr, IPnoaddr); - -} - -enum { - /* - * was an hour, needs to be less for the ARM/GS1 until the timer - * code has been cleaned up (pb). - */ - Maxsleep = 450, -}; - -void -dhcpwatch(int needconfig) -{ - ulong secs, s, t; - - if(nodhcpwatch) - return; - - switch(rfork(RFPROC|RFFDG|RFNOWAIT|RFNOTEG)){ - default: - return; - case 0: - break; - } - - dolog = 1; /* log, don't print */ - procsetname("dhcpwatch on %s", conf.dev); - /* keep trying to renew the lease */ - for(;;){ - secs = conf.lease/2; - if(secs < 5) - secs = 5; - - /* avoid overflows */ - for(s = secs; s > 0; s -= t){ - if(s > Maxsleep) - t = Maxsleep; - else - t = s; - sleep(t*1000); - } - - if(conf.lease > 0){ - /* - * during boot, the starttime can be bogus so avoid - * spurious ipunconfig's - */ - t = time(0) - conf.starttime; - if(t > (3*secs)/2) - t = secs; - if(t >= conf.lease){ - conf.lease = 0; - if(!noconfig){ - ipunconfig(); - needconfig = 1; - } - } else - conf.lease -= t; - } - dhcpquery(needconfig, needconfig? Sselecting: Srenewing); - - if(needconfig && conf.state == Sbound){ - if(ip4cfg() < 0) - sysfatal("can't start ip: %r"); - needconfig = 0; - /* - * leave everything we've learned somewhere that - * other procs can find it. - */ - if(beprimary) - putndb(); - refresh(); - } - } -} - -void -dhcptimer(void) -{ - ulong now; - - now = time(0); - if(now < conf.timeout) - return; - - switch(conf.state) { - default: - sysfatal("dhcptimer: unknown state %d", conf.state); - case Sinit: - case Sbound: - break; - case Sselecting: - case Srequesting: - case Srebinding: - dhcpsend(conf.state == Sselecting? Discover: Request); - conf.timeout = now + 4; - if(++conf.resend > 5) - conf.state = Sinit; - break; - case Srenewing: - dhcpsend(Request); - conf.timeout = now + 1; - if(++conf.resend > 3) { - conf.state = Srebinding; - conf.resend = 0; - } - break; - } -} - -void -dhcpsend(int type) -{ - Bootp bp; - uchar *p; - int n; - uchar vendor[64]; - Udphdr *up = (Udphdr*)bp.udphdr; - - memset(&bp, 0, sizeof bp); - - hnputs(up->rport, 67); - bp.op = Bootrequest; - hnputl(bp.xid, conf.xid); - hnputs(bp.secs, time(0)-conf.starttime); - hnputs(bp.flags, 0); - memmove(bp.optmagic, optmagic, 4); - if(conf.hwatype >= 0 && conf.hwalen < sizeof bp.chaddr){ - memmove(bp.chaddr, conf.hwa, conf.hwalen); - bp.hlen = conf.hwalen; - bp.htype = conf.hwatype; - } - p = bp.optdata; - p = optaddbyte(p, ODtype, type); - p = optadd(p, ODclientid, conf.cid, conf.cidlen); - switch(type) { - default: - sysfatal("dhcpsend: unknown message type: %d", type); - case Discover: - ipmove(up->raddr, IPv4bcast); /* broadcast */ - if(*conf.hostname && sendhostname) - p = optaddstr(p, OBhostname, conf.hostname); - if(plan9){ - n = snprint((char*)vendor, sizeof vendor, - "plan9_%s", conf.cputype); - p = optaddvec(p, ODvendorclass, vendor, n); - } - p = optaddvec(p, ODparams, requested, nrequested); - if(validip(conf.laddr)) - p = optaddaddr(p, ODipaddr, conf.laddr); - break; - case Request: - switch(conf.state){ - case Srenewing: - ipmove(up->raddr, conf.server); - v6tov4(bp.ciaddr, conf.laddr); - break; - case Srebinding: - ipmove(up->raddr, IPv4bcast); /* broadcast */ - v6tov4(bp.ciaddr, conf.laddr); - break; - case Srequesting: - ipmove(up->raddr, IPv4bcast); /* broadcast */ - p = optaddaddr(p, ODipaddr, conf.laddr); - p = optaddaddr(p, ODserverid, conf.server); - break; - } - p = optaddulong(p, ODlease, conf.offered); - if(plan9){ - n = snprint((char*)vendor, sizeof vendor, - "plan9_%s", conf.cputype); - p = optaddvec(p, ODvendorclass, vendor, n); - } - p = optaddvec(p, ODparams, requested, nrequested); - if(*conf.hostname && sendhostname) - p = optaddstr(p, OBhostname, conf.hostname); - break; - case Release: - ipmove(up->raddr, conf.server); - v6tov4(bp.ciaddr, conf.laddr); - p = optaddaddr(p, ODipaddr, conf.laddr); - p = optaddaddr(p, ODserverid, conf.server); - break; - } - - *p++ = OBend; - - n = p - (uchar*)&bp; - USED(n); - - /* - * We use a maximum size DHCP packet to survive the - * All_Aboard NAT package from Internet Share. It - * always replies to DHCP requests with a packet of the - * same size, so if the request is too short the reply - * is truncated. - */ - if(write(conf.fd, &bp, sizeof bp) != sizeof bp) - warning("dhcpsend: write failed: %r"); -} - -void -dhcprecv(void) -{ - int i, n, type; - ulong lease; - char err[ERRMAX]; - uchar buf[8000], vopts[256], taddr[IPaddrlen]; - Bootp *bp; - - memset(buf, 0, sizeof buf); - alarm(1000); - n = read(conf.fd, buf, sizeof buf); - alarm(0); - - if(n < 0){ - rerrstr(err, sizeof err); - if(strstr(err, "interrupt") == nil) - warning("dhcprecv: bad read: %s", err); - else - DEBUG("dhcprecv: read timed out"); - return; - } - - bp = parsebootp(buf, n); - if(bp == 0) { - DEBUG("parsebootp failed: dropping packet"); - return; - } - - type = optgetbyte(bp->optdata, ODtype); - switch(type) { - default: - warning("dhcprecv: unknown type: %d", type); - break; - case Offer: - DEBUG("got offer from %V ", bp->siaddr); - if(conf.state != Sselecting) - break; - lease = optgetulong(bp->optdata, ODlease); - if(lease == 0){ - /* - * The All_Aboard NAT package from Internet Share - * doesn't give a lease time, so we have to assume one. - */ - warning("Offer with %lud lease, using %d", lease, MinLease); - lease = MinLease; - } - DEBUG("lease=%lud ", lease); - if(!optgetaddr(bp->optdata, ODserverid, conf.server)) { - warning("Offer from server with invalid serverid"); - break; - } - - v4tov6(conf.laddr, bp->yiaddr); - memmove(conf.sname, bp->sname, sizeof conf.sname); - conf.sname[sizeof conf.sname-1] = 0; - DEBUG("server=%I sname=%s", conf.server, conf.sname); - conf.offered = lease; - conf.state = Srequesting; - dhcpsend(Request); - conf.resend = 0; - conf.timeout = time(0) + 4; - break; - case Ack: - DEBUG("got ack from %V ", bp->siaddr); - if (conf.state != Srequesting && conf.state != Srenewing && - conf.state != Srebinding) - break; - - /* ignore a bad lease */ - lease = optgetulong(bp->optdata, ODlease); - if(lease == 0){ - /* - * The All_Aboard NAT package from Internet Share - * doesn't give a lease time, so we have to assume one. - */ - warning("Ack with %lud lease, using %d", lease, MinLease); - lease = MinLease; - } - DEBUG("lease=%lud ", lease); - - /* address and mask */ - if(!validip(conf.laddr) || !Oflag) - v4tov6(conf.laddr, bp->yiaddr); - if(!validip(conf.mask) || !Oflag){ - if(!optgetaddr(bp->optdata, OBmask, conf.mask)) - ipmove(conf.mask, IPnoaddr); - if(ipcmp(conf.mask, IPv4bcast) == 0) - ipmove(conf.mask, IPnoaddr); - } - DEBUG("ipaddr=%I ipmask=%M ", conf.laddr, conf.mask); - - /* - * get a router address either from the router option - * or from the router that forwarded the dhcp packet - */ - if(validip(conf.gaddr) && Oflag) { - DEBUG("ipgw=%I ", conf.gaddr); - } else if(optgetaddr(bp->optdata, OBrouter, conf.gaddr)){ - DEBUG("ipgw=%I ", conf.gaddr); - } else if(memcmp(bp->giaddr, IPnoaddr+IPv4off, IPv4addrlen)!=0){ - v4tov6(conf.gaddr, bp->giaddr); - DEBUG("giaddr=%I ", conf.gaddr); - } - - /* get dns servers */ - memset(conf.dns, 0, sizeof conf.dns); - n = optgetaddrs(bp->optdata, OBdnserver, conf.dns, - sizeof conf.dns/IPaddrlen); - for(i = 0; i < n; i++) - DEBUG("dns=%I ", conf.dns + i*IPaddrlen); - - /* get ntp servers */ - memset(conf.ntp, 0, sizeof conf.ntp); - n = optgetaddrs(bp->optdata, OBntpserver, conf.ntp, - sizeof conf.ntp/IPaddrlen); - for(i = 0; i < n; i++) - DEBUG("ntp=%I ", conf.ntp + i*IPaddrlen); - - /* get names */ - optgetstr(bp->optdata, OBhostname, - conf.hostname, sizeof conf.hostname); - optgetstr(bp->optdata, OBdomainname, - conf.domainname, sizeof conf.domainname); - - /* get anything else we asked for */ - getoptions(bp->optdata); - - /* get plan9-specific options */ - n = optgetvec(bp->optdata, OBvendorinfo, vopts, sizeof vopts-1); - if(n > 0 && parseoptions(vopts, n) == 0){ - if(validip(conf.fs) && Oflag) - n = 1; - else { - n = optgetp9addrs(vopts, OP9fs, conf.fs, 2); - if (n == 0) - n = optgetaddrs(vopts, OP9fsv4, - conf.fs, 2); - } - for(i = 0; i < n; i++) - DEBUG("fs=%I ", conf.fs + i*IPaddrlen); - - if(validip(conf.auth) && Oflag) - n = 1; - else { - n = optgetp9addrs(vopts, OP9auth, conf.auth, 2); - if (n == 0) - n = optgetaddrs(vopts, OP9authv4, - conf.auth, 2); - } - for(i = 0; i < n; i++) - DEBUG("auth=%I ", conf.auth + i*IPaddrlen); - - n = optgetp9addrs(vopts, OP9ipaddr, taddr, 1); - if (n > 0) - memmove(conf.laddr, taddr, IPaddrlen); - n = optgetp9addrs(vopts, OP9ipmask, taddr, 1); - if (n > 0) - memmove(conf.mask, taddr, IPaddrlen); - n = optgetp9addrs(vopts, OP9ipgw, taddr, 1); - if (n > 0) - memmove(conf.gaddr, taddr, IPaddrlen); - DEBUG("new ipaddr=%I new ipmask=%M new ipgw=%I", - conf.laddr, conf.mask, conf.gaddr); - } - conf.lease = lease; - conf.state = Sbound; - DEBUG("server=%I sname=%s", conf.server, conf.sname); - break; - case Nak: - conf.state = Sinit; - warning("recved dhcpnak on %s", conf.mpoint); - break; - } -} - -/* return pseudo-random integer in range low...(hi-1) */ -ulong -randint(ulong low, ulong hi) -{ - if (hi < low) - return low; - return low + nrand(hi - low); -} - -long -jitter(void) /* compute small pseudo-random delay in ms */ -{ - return randint(0, 10*1000); -} - +/* return true if this is not a null address */ int -openlisten(void) +validip(uchar *addr) { - int n, fd, cfd; - char data[128], devdir[40]; - - if (validip(conf.laddr) && - (conf.state == Srenewing || conf.state == Srebinding)) - sprint(data, "%s/udp!%I!68", conf.mpoint, conf.laddr); - else - sprint(data, "%s/udp!*!68", conf.mpoint); - 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"); - - sprint(data, "%s/data", devdir); - fd = open(data, ORDWR); - if(fd < 0) - sysfatal("open %s: %r", data); - close(cfd); - return fd; + return ipcmp(addr, IPnoaddr) != 0 && ipcmp(addr, v4prefix) != 0; } -uchar* -optadd(uchar *p, int op, void *d, int n) -{ - p[0] = op; - p[1] = n; - memmove(p+2, d, n); - return p+n+2; -} - -uchar* -optaddbyte(uchar *p, int op, int b) -{ - p[0] = op; - p[1] = 1; - p[2] = b; - return p+3; -} - -uchar* -optaddulong(uchar *p, int op, ulong x) -{ - p[0] = op; - p[1] = 4; - hnputl(p+2, x); - return p+6; -} - -uchar * -optaddaddr(uchar *p, int op, uchar *ip) -{ - p[0] = op; - p[1] = 4; - v6tov4(p+2, ip); - return p+6; -} - -/* add dhcp option op with value v of length n to dhcp option array p */ -uchar * -optaddvec(uchar *p, int op, uchar *v, int n) -{ - p[0] = op; - p[1] = n; - memmove(p+2, v, n); - return p+2+n; -} - -uchar * -optaddstr(uchar *p, int op, char *v) -{ - int n; - - n = strlen(v); - p[0] = op; - p[1] = n; - memmove(p+2, v, n); - return p+2+n; -} - -/* - * parse p, looking for option `op'. if non-nil, np points to minimum length. - * return nil if option is too small, else ptr to opt, and - * store actual length via np if non-nil. - */ -uchar* -optget(uchar *p, int op, int *np) -{ - int len, code; - - while ((code = *p++) != OBend) { - if(code == OBpad) - continue; - len = *p++; - if(code != op) { - p += len; - continue; - } - if(np != nil){ - if(*np > len) { - return 0; - } - *np = len; - } - return p; - } - return 0; -} - -int -optgetbyte(uchar *p, int op) -{ - int len; - - len = 1; - p = optget(p, op, &len); - if(p == nil) - return 0; - return *p; -} - -ulong -optgetulong(uchar *p, int op) -{ - int len; - - len = 4; - p = optget(p, op, &len); - if(p == nil) - return 0; - return nhgetl(p); -} - -int -optgetaddr(uchar *p, int op, uchar *ip) -{ - int len; - - len = 4; - p = optget(p, op, &len); - if(p == nil) - return 0; - v4tov6(ip, p); - return 1; -} - -/* expect at most n addresses; ip[] only has room for that many */ -int -optgetaddrs(uchar *p, int op, uchar *ip, int n) -{ - int len, i; - - len = 4; - p = optget(p, op, &len); - if(p == nil) - return 0; - len /= IPv4addrlen; - if(len > n) - len = n; - for(i = 0; i < len; i++) - v4tov6(&ip[i*IPaddrlen], &p[i*IPv4addrlen]); - return i; -} - -/* expect at most n addresses; ip[] only has room for that many */ -int -optgetp9addrs(uchar *ap, int op, uchar *ip, int n) -{ - int len, i, slen, addrs; - char *p; - - len = 1; /* minimum bytes needed */ - p = (char *)optget(ap, op, &len); - if(p == nil) - return 0; - addrs = *p++; /* first byte is address count */ - for (i = 0; i < n && i < addrs && len > 0; i++) { - slen = strlen(p) + 1; - if (parseip(&ip[i*IPaddrlen], p) == -1) - fprint(2, "%s: bad address %s\n", argv0, p); - DEBUG("got plan 9 option %d addr %I (%s)", - op, &ip[i*IPaddrlen], p); - p += slen; - len -= slen; - } - return addrs; -} - -int -optgetvec(uchar *p, int op, uchar *v, int n) -{ - int len; - - len = 1; - p = optget(p, op, &len); - if(p == nil) - return 0; - if(len > n) - len = n; - memmove(v, p, len); - return len; -} - -int -optgetstr(uchar *p, int op, char *s, int n) -{ - int len; - - len = 1; - p = optget(p, op, &len); - if(p == nil) - return 0; - if(len >= n) - len = n-1; - memmove(s, p, len); - s[len] = 0; - return len; -} - -/* - * sanity check options area - * - options don't overflow packet - * - options end with an OBend - */ -int -parseoptions(uchar *p, int n) -{ - int code, len, nin = n; - - while (n > 0) { - code = *p++; - n--; - if(code == OBend) - return 0; - if(code == OBpad) - continue; - if(n == 0) { - warning("parseoptions: bad option: 0x%ux: truncated: " - "opt length = %d", code, nin); - return -1; - } - - len = *p++; - n--; - DEBUG("parseoptions: %s(%d) len %d, bytes left %d", - option[code].name, code, len, n); - if(len > n) { - warning("parseoptions: bad option: 0x%ux: %d > %d: " - "opt length = %d", code, len, n, nin); - return -1; - } - p += len; - n -= len; - } - - /* make sure packet ends with an OBend after all the optget code */ - *p = OBend; - return 0; -} - -/* - * sanity check received packet: - * - magic is dhcp magic - * - options don't overflow packet - */ -Bootp * -parsebootp(uchar *p, int n) -{ - Bootp *bp; - - bp = (Bootp*)p; - if(n < bp->optmagic - p) { - warning("parsebootp: short bootp packet"); - return nil; - } - - if(conf.xid != nhgetl(bp->xid)) /* not meant for us */ - return nil; - - if(bp->op != Bootreply) { - warning("parsebootp: bad op %d", bp->op); - return nil; - } - - n -= bp->optmagic - p; - p = bp->optmagic; - - if(n < 4) { - warning("parsebootp: no option data"); - return nil; - } - if(memcmp(optmagic, p, 4) != 0) { - warning("parsebootp: bad opt magic %ux %ux %ux %ux", - p[0], p[1], p[2], p[3]); - return nil; - } - p += 4; - n -= 4; - DEBUG("parsebootp: new packet"); - if(parseoptions(p, n) < 0) - return nil; - return bp; -} - -/* put server addresses into the ndb entry */ -char* +/* put server ip addresses into the ndb entry */ +static char* putaddrs(char *p, char *e, char *attr, uchar *a, int len) { int i; @@ -1651,22 +633,20 @@ putaddrs(char *p, char *e, char *attr, uchar *a, int len) return p; } -void -refresh(void) +/* put space separated names into ndb entry */ +static char* +putnames(char *p, char *e, char *attr, char *s) { - char file[64]; - int fd; + char *x; - snprint(file, sizeof file, "%s/cs", conf.mpoint); - if((fd = open(file, OWRITE)) >= 0){ - write(fd, "refresh", 7); - close(fd); - } - snprint(file, sizeof file, "%s/dns", conf.mpoint); - if((fd = open(file, OWRITE)) >= 0){ - write(fd, "refresh", 7); - close(fd); + for(; *s != 0; s = x+1){ + if((x = strchr(s, ' ')) == nil) + x = strchr(s, 0); + p = seprint(p, e, "%s=%.*s\n", attr, (int)(x - s), s); + if(*x == 0) + break; } + return p; } /* make an ndb entry and put it into /net/ndb for the servers to see */ @@ -1693,12 +673,14 @@ putndb(void) if(*conf.domainname) p = seprint(p, e, "\tdom=%s.%s\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.dns)) - p = putaddrs(p, e, "\tdns", conf.dns, sizeof conf.dns); if(validip(conf.ntp)) p = putaddrs(p, e, "\tntp", conf.ntp, sizeof conf.ntp); if(ndboptions) @@ -1730,23 +712,87 @@ putndb(void) close(fd); } -/* return true if this is a valid v4 address */ -int -validip(uchar *addr) +static int +issrcspec(uchar *src, uchar *smask) { - return ipcmp(addr, IPnoaddr) != 0 && ipcmp(addr, v4prefix) != 0; + return isv4(src)? memcmp(smask+IPv4off, IPnoaddr+IPv4off, 4): ipcmp(smask, IPnoaddr); } -/* look for an action */ -int -parseverb(char *name) +void +addroute(uchar *dst, uchar *mask, uchar *gate, uchar *ia, uchar *src, uchar *smask) { - int i; + char *cmd; - for(i = 0; i < nelem(verbs); i++) - if(verbs[i] != nil && strcmp(name, verbs[i]) == 0) - return i; - return -1; + 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, ia, src, smask); +} + +void +removeroute(uchar *dst, uchar *mask, uchar *src, uchar *smask) +{ + char *cmd; + + if(issrcspec(src, smask)) + cmd = "remove %I %M %I %M"; + else + cmd = "remove %I %M"; + fprint(conf.rfd, cmd, dst, mask, src, smask); +} + +void +adddefroute(uchar *gaddr, uchar *ia, 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, ia, src, smask); + + /* also add a source specific route */ + if(ipcmp(src, IPnoaddr) != 0 && ipcmp(src, v4prefix) != 0) + addroute(dst, mask, gaddr, ia, src, IPallbits); +} + +void +refresh(void) +{ + char file[64]; + int fd; + + snprint(file, sizeof file, "%s/cs", conf.mpoint); + if((fd = open(file, OWRITE)) >= 0){ + write(fd, "refresh", 7); + close(fd); + } + snprint(file, sizeof file, "%s/dns", conf.mpoint); + if((fd = open(file, OWRITE)) >= 0){ + write(fd, "refresh", 7); + close(fd); + } +} + +void +catch(void*, char *msg) +{ + if(strstr(msg, "alarm")) + noted(NCONT); + noted(NDFLT); } /* @@ -1774,6 +820,83 @@ procsetname(char *fmt, ...) free(cmdname); } +/* return pseudo-random integer in range low...(hi-1) */ +ulong +randint(ulong low, ulong hi) +{ + if (hi < low) + return low; + return low + nrand(hi - low); +} + +long +jitter(void) /* compute small pseudo-random delay in ms */ +{ + return randint(0, 10*1000); +} + +int +countaddrs(uchar *a, int len) +{ + int i; + + for(i = 0; i < len && validip(a); i += IPaddrlen, a += IPaddrlen) + ; + return i / IPaddrlen; +} + +void +addaddrs(uchar *to, int nto, uchar *from, int nfrom) +{ + int i, j; + + for(i = 0; i < nfrom; i += IPaddrlen, from += IPaddrlen){ + if(!validip(from)) + continue; + for(j = 0; j < nto && validip(to+j); j += IPaddrlen){ + if(ipcmp(to+j, from) == 0) + return; + } + if(j == nto) + return; + ipmove(to+j, from); + } +} + +void +addnames(char *d, char *s, int len) +{ + char *p, *e, *f; + int n; + + for(;;s++){ + if((e = strchr(s, ' ')) == nil) + e = strchr(s, 0); + n = e - s; + if(n == 0) + goto next; + for(p = d;;p++){ + if((f = strchr(p, ' ')) == nil) + f = strchr(p, 0); + if(f - p == n && memcmp(s, p, n) == 0) + goto next; + p = f; + if(*p == 0) + break; + } + if(1 + n + p - d >= len) + break; + if(p > d) + *p++ = ' '; + p[n] = 0; + memmove(p, s, n); +next: + s = e; + if(*s == 0) + break; + } +} + static Ndbtuple* uniquent(Ndbtuple *t) { @@ -1792,148 +915,149 @@ uniquent(Ndbtuple *t) return t; } -/* get everything out of ndb */ +/* read configuration (except laddr) for myip from ndb */ void -ndbconfig(void) +ndb2conf(Ndb *db, uchar *myip) { - int nattr, nauth = 0, ndns = 0, nfs = 0, nntp = 0, ok; - char etheraddr[32]; - char *attrs[10]; - Ndb *db; + int nattr; + char *attrs[10], val[64]; + uchar ip[IPaddrlen]; Ndbtuple *t, *nt; - db = ndbopen(dbfile); + ipmove(conf.mask, defmask(conf.laddr)); + + memset(conf.gaddr, 0, sizeof(conf.gaddr)); + memset(conf.dns, 0, sizeof(conf.dns)); + memset(conf.ntp, 0, sizeof(conf.ntp)); + memset(conf.fs, 0, sizeof(conf.fs)); + memset(conf.auth, 0, sizeof(conf.auth)); + memset(conf.dnsdomain, 0, sizeof(conf.dnsdomain)); + if(db == nil) - sysfatal("can't open ndb: %r"); - if (!isether() || myetheraddr(conf.hwa, conf.dev) != 0) - sysfatal("can't read hardware address"); - sprint(etheraddr, "%E", conf.hwa); + return; + nattr = 0; - attrs[nattr++] = "ip"; attrs[nattr++] = "ipmask"; attrs[nattr++] = "ipgw"; - /* the @ triggers resolution to an IP address; see ndb(2) */ + attrs[nattr++] = "@dns"; attrs[nattr++] = "@ntp"; attrs[nattr++] = "@fs"; attrs[nattr++] = "@auth"; - attrs[nattr] = nil; - t = ndbipinfo(db, "ether", etheraddr, attrs, nattr); + + attrs[nattr++] = "dnsdomain"; + + snprint(val, sizeof(val), "%I", myip); + t = ndbipinfo(db, "ip", val, attrs, nattr); for(nt = t; nt != nil; nt = nt->entry) { - ok = 1; - if(strcmp(nt->attr, "ip") == 0) - ok = parseip(conf.laddr, uniquent(nt)->val); - else if(strcmp(nt->attr, "ipmask") == 0) - parseipmask(conf.mask, uniquent(nt)->val); /* could be -1 */ - else if(strcmp(nt->attr, "ipgw") == 0) - ok = parseip(conf.gaddr, uniquent(nt)->val); - else if(ndns < sizeof(conf.dns)/IPaddrlen && strcmp(nt->attr, "dns") == 0) - ok = parseip(conf.dns+IPaddrlen*ndns++, nt->val); - else if(nntp < sizeof(conf.ntp)/IPaddrlen && strcmp(nt->attr, "ntp") == 0) - ok = parseip(conf.ntp+IPaddrlen*nntp++, nt->val); - else if(nfs < sizeof(conf.fs)/IPaddrlen && strcmp(nt->attr, "fs") == 0) - ok = parseip(conf.fs+IPaddrlen*nfs++, nt->val); - else if(nauth < sizeof(conf.auth)/IPaddrlen && strcmp(nt->attr, "auth") == 0) - ok = parseip(conf.auth+IPaddrlen*nauth++, nt->val); - if(ok == -1) + if(strcmp(nt->attr, "dnsdomain") == 0) { + addnames(conf.dnsdomain, nt->val, sizeof(conf.dnsdomain)); + continue; + } + if(strcmp(nt->attr, "ipmask") == 0) { + nt = uniquent(nt); + parseipmask(conf.mask, nt->val); /* could be -1 */ + continue; + } + if(parseip(ip, nt->val) == -1) { fprint(2, "%s: bad %s address in ndb: %s\n", argv0, nt->attr, nt->val); + continue; + } + if(strcmp(nt->attr, "ipgw") == 0) { + nt = uniquent(nt); + ipmove(conf.gaddr, ip); + } else if(strcmp(nt->attr, "dns") == 0) { + addaddrs(conf.dns, sizeof(conf.dns), ip, IPaddrlen); + } else if(strcmp(nt->attr, "ntp") == 0) { + addaddrs(conf.ntp, sizeof(conf.ntp), ip, IPaddrlen); + } else if(strcmp(nt->attr, "fs") == 0) { + addaddrs(conf.fs, sizeof(conf.fs), ip, IPaddrlen); + } else if(strcmp(nt->attr, "auth") == 0) { + addaddrs(conf.auth, sizeof(conf.auth), ip, IPaddrlen); + } } ndbfree(t); - if(!validip(conf.laddr)) - sysfatal("address not found in ndb"); } -int -addoption(char *opt) +Ndb* +opendatabase(void) { - int i; - Option *o; + static Ndb *db; - if(opt == nil) - return -1; - for(o = option; o < &option[nelem(option)]; o++) - if(o->name && strcmp(opt, o->name) == 0){ - i = o - option; - if(memchr(requested, i, nrequested) == 0 && - nrequested < nelem(requested)) - requested[nrequested++] = i; - return 0; - } - return -1; + if(db != nil) + ndbclose(db); + db = ndbopen(dbfile); + return db; } -char* -optgetx(uchar *p, uchar opt) +/* add addresses for my ethernet address from ndb */ +static void +ndbconfig(void) { - int i, n; - ulong x; - char *s, *ns; - char str[256]; - uchar ip[IPaddrlen], ips[16*IPaddrlen], vec[256]; - Option *o; + uchar ips[128*IPaddrlen]; + char etheraddr[32], *attr; + Ndbtuple *t, *nt; + Ndb *db; + int n, i; - o = &option[opt]; - if(o->name == nil) - return nil; + db = opendatabase(); + if(db == nil) + sysfatal("can't open ndb: %r"); - s = nil; - switch(o->type){ - case Taddr: - if(optgetaddr(p, opt, ip)) - s = smprint("%s=%I", o->name, ip); - break; - case Taddrs: - n = optgetaddrs(p, opt, ips, 16); - if(n > 0) - s = smprint("%s=%I", o->name, ips); - for(i = 1; i < n; i++){ - ns = smprint("%s %s=%I", s, o->name, &ips[i*IPaddrlen]); - free(s); - s = ns; - } - break; - case Tulong: - x = optgetulong(p, opt); - if(x != 0) - s = smprint("%s=%lud", o->name, x); - break; - case Tbyte: - x = optgetbyte(p, opt); - if(x != 0) - s = smprint("%s=%lud", o->name, x); - break; - case Tstr: - if(optgetstr(p, opt, str, sizeof str)) - s = smprint("%s=%s", o->name, str); - break; - case Tvec: - n = optgetvec(p, opt, vec, sizeof vec); - if(n > 0) - /* what's %H? it's not installed */ - s = smprint("%s=%.*H", o->name, n, vec); - break; + if(validip(conf.laddr)){ + ndb2conf(db, conf.laddr); + doadd(); + return; } - return s; -} -void -getoptions(uchar *p) -{ - int i; - char *s, *t; + memset(ips, 0, sizeof(ips)); - for(i = nelem(defrequested); i < nrequested; i++){ - s = optgetx(p, requested[i]); - if(s != nil) - DEBUG("%s ", s); - if(ndboptions == nil) - ndboptions = smprint("\t%s", s); - else{ - t = ndboptions; - ndboptions = smprint("\t%s%s", s, ndboptions); - free(t); + if(!isether() || myetheraddr(conf.hwa, conf.dev) != 0) + sysfatal("can't read hardware address"); + snprint(etheraddr, sizeof(etheraddr), "%E", conf.hwa); + + attr = "ip"; + t = ndbipinfo(db, "ether", etheraddr, &attr, 1); + for(nt = t; nt != nil; nt = nt->entry) { + if(parseip(conf.laddr, nt->val) == -1){ + fprint(2, "%s: bad %s address in ndb: %s\n", argv0, + nt->attr, nt->val); + continue; + } + addaddrs(ips, sizeof(ips), conf.laddr, IPaddrlen); + } + ndbfree(t); + + n = countaddrs(ips, sizeof(ips)); + if(n == 0) + sysfatal("no ip addresses found in ndb"); + + /* add link local address first, if not already done */ + if(!validip(conf.lladdr) && !findllip(conf.lladdr, ifc)){ + for(i = 0; i < n; i++){ + ipmove(conf.laddr, ips+i*IPaddrlen); + if(ISIPV6LINKLOCAL(conf.laddr)){ + ipv6auto = 0; + ipmove(conf.lladdr, conf.laddr); + ndb2conf(db, conf.laddr); + doadd(); + break; + } + } + if(ipv6auto){ + ipmove(conf.laddr, IPnoaddr); + doadd(); + } + } + + /* add v4 addresses and v6 if link local address is available */ + for(i = 0; i < n; i++){ + ipmove(conf.laddr, ips+i*IPaddrlen); + if(isv4(conf.laddr) + || validip(conf.lladdr) && ipcmp(conf.laddr, conf.lladdr) != 0){ + ndb2conf(db, conf.laddr); + doadd(); } - free(s); } } diff --git a/sys/src/cmd/ip/ipconfig/mkfile b/sys/src/cmd/ip/ipconfig/mkfile index d888e9a9b..cdeedb188 100644 --- a/sys/src/cmd/ip/ipconfig/mkfile +++ b/sys/src/cmd/ip/ipconfig/mkfile @@ -4,6 +4,7 @@ TARG=ipconfig\ OFILES=\ main.$O\ + dhcp.$O\ ipv6.$O\ ppp.$O\ diff --git a/sys/src/cmd/ip/ipconfig/ppp.c b/sys/src/cmd/ip/ipconfig/ppp.c index 82d5a5578..1a2ee0138 100644 --- a/sys/src/cmd/ip/ipconfig/ppp.c +++ b/sys/src/cmd/ip/ipconfig/ppp.c @@ -3,7 +3,6 @@ #include #include #include -#include "../dhcp.h" #include "ipconfig.h" void