ref: 190c40c9fff3eafd23ab89cb445d4f85d29963b0
parent: 8e53fe132efe25437f50974f107be4f1fcbad2ea
author: cinap_lenrek <[email protected]>
date: Tue May 1 19:32:28 EDT 2018
ip/ipconfig: populate /net/ndb from v6 router advertisements, configure multiple addresses in ndbconfig() we now update /net/ndb with the following information gathered from router advertisements (rfc6106 and plan9 specific options): - recursive dns servers (option 25, ndb: dns=) - dns search list (option 31, ndb: dnsdomain=) - plan9 fileserver (option 250, ndb: fs=) - plan9 authserver (option 251, ndb: auth=) note the plan9 specific options can be disabled with the -G flag. for ndbconfig (-N flag), we now collect all ip addresses in ndb belonging to the devices mac address and configue them all. v6 addresses are getting added when a link local address exists or the -6 flag has been specified to automatically configure one. move the dhcp code in its own dhcp.c file and make symbols static that are not used across modules.
--- a/sys/include/ip.h
+++ b/sys/include/ip.h
@@ -88,8 +88,8 @@
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,
--- /dev/null
+++ b/sys/src/cmd/ip/ipconfig/dhcp.c
@@ -1,0 +1,979 @@
+/*
+ * ipconfig - configure parameters of an ip stack
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ip.h>
+#include <ndb.h>
+#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;
+}
+
--- 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 @@
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,6 +80,7 @@
int ttl; /* default 0 (unspecified) */
/* prefix related */
+ uchar lladdr[IPaddrlen];
uchar v6pref[IPaddrlen];
int prefixlen;
uchar onlink; /* flag: address is `on-link' */
@@ -66,6 +87,8 @@
uchar autoflag; /* flag: autonomous */
ulong validlt; /* valid lifetime (seconds) */
ulong preflt; /* preferred lifetime (seconds) */
+
+ char dnsdomain[256];
};
struct Ctl
@@ -74,152 +97,60 @@
char *ctl;
};
-extern Ctl *firstctl, **ctll;
-
-extern Conf conf;
-
+extern Conf conf;
+extern int myifc;
+extern int beprimary;
extern int noconfig;
-extern int ipv6auto;
+
extern int debug;
-extern int dodhcp;
extern int dolog;
+
extern int plan9;
+extern int Oflag;
+
extern int dupl_disc;
-extern Conf conf;
-extern int myifc;
-extern char *vs;
+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
/*
- * IPv6
+ * DHCP
*/
+void dhcpinit(void);
+void dhcpquery(int, int);
+void dhcpwatch(int);
+int addoption(char*);
-void doipv6(int);
+/*
+ * IPv6
+ */
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);
--- a/sys/src/cmd/ip/ipconfig/ipv6.c
+++ b/sys/src/cmd/ip/ipconfig/ipv6.c
@@ -8,73 +8,99 @@
#include <libc.h>
#include <bio.h>
#include <ip.h>
+#include <ndb.h>
#include "ipconfig.h"
#include "../icmp.h"
-#include <libsec.h>
+#include <libsec.h> /* for sha1 */
-#pragma varargck argpos ralog 1
+enum {
+ IsRouter = 1,
+ IsHostRecv = 2,
+ IsHostNoRecv = 3,
-#define RALOG "v6routeradv"
+ ICMP6_RS = 133,
+ ICMP6_RA = 134,
-#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])
+ MFMASK = 1 << 7,
+ OCMASK = 1 << 6,
+ OLMASK = 1 << 7,
+ AFMASK = 1 << 6,
+ RFMASK = 1 << 5,
-enum {
- ICMP6LEN= 4,
+ 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] = {
0xff, 0x02, 0, 0,
0, 0, 0, 0,
@@ -132,15 +158,10 @@
0, 0, 0, 0
};
-enum
-{
- Vadd,
- Vremove,
- Vunbind,
- Vaddpref6,
- Vra6,
-};
+#pragma varargck argpos ralog 1
+#define RALOG "v6routeradv"
+
static void
ralog(char *fmt, ...)
{
@@ -154,45 +175,14 @@
}
void
-ea2lla(uchar *lla, uchar *ea)
-{
- assert(IPaddrlen == 16);
- memset(lla, 0, IPaddrlen);
- lla[0] = 0xFE;
- lla[1] = 0x80;
- lla[8] = ea[0] ^ 0x2;
- lla[9] = ea[1];
- lla[10] = ea[2];
- lla[11] = 0xFF;
- lla[12] = 0xFE;
- lla[13] = ea[3];
- lla[14] = ea[4];
- lla[15] = ea[5];
-}
-
-void
-ipv62smcast(uchar *smcast, uchar *a)
-{
- 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];
-}
-
-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->linkmtu = 1500;
cf->reachtime = V6reachabletime;
cf->rxmitra = V6retranstimer;
cf->ttl = MAXTTL;
@@ -205,71 +195,113 @@
cf->validlt = cf->preflt = ~0L;
}
-static char *
-optname(unsigned opt)
+void
+parse6pref(int argc, char **argv)
{
- 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];
+ 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);
}
-static char*
-opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe)
+/* parse router advertisement (keyword, value) pairs */
+void
+parse6ra(int argc, char **argv)
{
- int otype, osz, pktlen;
- uchar *a;
- char *p = sps, *e = spe;
+ int i, argsleft;
+ char *kw, *val;
- a = ps;
- for (pktlen = pe - ps; pktlen > 0; pktlen -= osz) {
- otype = a[0];
- osz = a[1] * 8;
+ if (argc % 2 != 0)
+ usage();
- 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;
+ 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();
}
- a += osz;
+ i += 2;
}
- return p;
+
+ /* consistency check */
+ if (conf.maxraint < conf.minraint)
+ sysfatal("maxraint %d < minraint %d",
+ conf.maxraint, conf.minraint);
}
-static void
-catch(void *a, char *msg)
+void
+ea2lla(uchar *lla, uchar *ea)
{
- USED(a);
- if(strstr(msg, "alarm"))
- noted(NCONT);
- else
- noted(NDFLT);
+ memset(lla, 0, IPaddrlen);
+ lla[0] = 0xFE;
+ lla[1] = 0x80;
+ lla[8] = ea[0] ^ 0x2;
+ lla[9] = ea[1];
+ lla[10] = ea[2];
+ lla[11] = 0xFF;
+ lla[12] = 0xFE;
+ lla[13] = ea[3];
+ lla[14] = ea[4];
+ lla[15] = ea[5];
}
+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 int
dialicmpv6(uchar *ip, int port)
{
@@ -277,13 +309,13 @@
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 @@
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 @@
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 @@
}
warning("found dup entry in arp cache");
- doremove();
- return 0;
+ ipunconfig();
+ return -1;
}
static int
@@ -434,21 +437,6 @@
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 @@
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 @@
USED(buf, pktlen);
}
-/* host receiving a router advertisement calls this */
-
static void
ewrite(int fd, char *str)
{
@@ -515,9 +501,9 @@
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 @@
{
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);
}
@@ -547,6 +531,35 @@
}
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)
{
static uchar tab[SHA1dlen*100], *w;
@@ -563,14 +576,78 @@
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 @@
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 @@
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);
+ 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;
- /* report prefix only once */
- if(seen(&conf))
+ case V6nd_9fs:
+ addrso = (Ipaddrsopt*)&buf[n];
+ n = (addrso->len - 1) * 8;
+ if(n == 0 || n % IPaddrlen || !plan9)
break;
+ 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(conf.prefixlen == 0
- || !validip(conf.v6pref)
- || isv4(conf.v6pref)
- || ipcmp(conf.v6pref, v6loopback) == 0
- || ISIPV6MCAST(conf.v6pref)
- || ISIPV6LINKLOCAL(conf.v6pref)){
+ /* 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);
- break;
- }
+ continue;
+ }
- ralog("got initial RA from %I on %s; pfx %I %M",
- ra->src, conf.dev, conf.v6pref, conf.mask);
+ /* add prefix and update parameters */
+ issueadd6(&conf);
- 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;
- break;
- }
- }
+ /* report this prefix configuration only once */
+ if(seen(&conf))
+ continue;
- if(needrefresh)
+ 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,7 +803,7 @@
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);
@@ -681,23 +810,30 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 @@
* 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,6 +983,7 @@
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
@@ -838,7 +990,8 @@
|| 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,8 +1002,58 @@
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);
}
@@ -857,18 +1060,23 @@
/*
* 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);
@@ -875,29 +1083,29 @@
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 @@
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();
--- a/sys/src/cmd/ip/ipconfig/main.c
+++ b/sys/src/cmd/ip/ipconfig/main.c
@@ -3,216 +3,49 @@
*/
#include <u.h>
#include <libc.h>
-#include <ip.h>
#include <bio.h>
+#include <ip.h>
#include <ndb.h>
-#include "../dhcp.h"
#include "ipconfig.h"
+#include "../dhcp.h"
#include <libsec.h> /* genrandom() */
-#define DEBUG if(debug)warning
+Conf conf;
+int myifc = -1;
+int beprimary = -1;
+int noconfig;
+Ipifc *ifc;
+Ctl *firstctl, **ctll = &firstctl;
-/* possible verbs */
-enum
-{
- /* commands */
- Vadd,
- Vremove,
- Vunbind,
- Vaddpref6,
- Vra6,
- /* media */
- Vether,
- Vgbe,
- Vppp,
- Vloopback,
- Vtorus,
- Vtree,
- Vpkt,
-};
+int debug;
+int dolog;
-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 plan9 = 1;
int Oflag;
-int beprimary = -1;
-Conf conf;
-int debug;
+int rflag;
+
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 noconfig;
int nodhcpwatch;
-char optmagic[4] = { 0x63, 0x82, 0x53, 0x63 };
-int plan9 = 1;
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 @@
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 @@
}
}
-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 @@
return dev;
}
+/* look for an action */
static int
-findifc(char *net, char *dev)
+parseverb(char *name)
{
- Ipifc *nifc;
+ 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;
- ifc = readipifc(net, ifc, -1);
- for(nifc = ifc; nifc != nil; nifc = nifc->next)
- if(strcmp(nifc->dev, dev) == 0)
- return nifc->index;
-
+ 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 @@
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 @@
beprimary = 0;
break;
case 'r':
- retry = 1;
+ rflag = 1;
break;
case 'u': /* IPv6: duplicate neighbour disc. off */
dupl_disc = 0;
@@ -607,7 +386,12 @@
switch(action){
case Vadd:
- doadd(retry);
+ if(dondbconfig){
+ dodhcp = 0;
+ ndbconfig();
+ return;
+ }
+ doadd();
break;
case Vaddpref6:
case Vra6:
@@ -623,14 +407,51 @@
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,7 +466,7 @@
}
if(!validip(conf.laddr))
- if(retry && dodhcp && !noconfig){
+ if(rflag && dodhcp && !noconfig){
warning("couldn't determine ip address, retrying");
dhcpwatch(1);
return;
@@ -652,6 +473,7 @@
} 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 @@
refresh();
}
-void
+static void
doremove(void)
{
if(!validip(conf.laddr))
@@ -680,7 +502,7 @@
warning("can't remove %I %M: %r", conf.laddr, conf.mask);
}
-void
+static void
dounbind(void)
{
if(fprint(conf.cfd, "unbind") < 0)
@@ -687,101 +509,8 @@
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 @@
}
/* bind an ip stack to a device, leave the control channel open */
-void
+static void
binddevice(void)
{
char buf[256];
@@ -867,7 +596,7 @@
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 @@
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 @@
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);
+ 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;
}
- snprint(file, sizeof file, "%s/dns", conf.mpoint);
- if((fd = open(file, OWRITE)) >= 0){
- write(fd, "refresh", 7);
- close(fd);
- }
+ return p;
}
/* make an ndb entry and put it into /net/ndb for the servers to see */
@@ -1693,12 +673,14 @@
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,25 +712,89 @@
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);
+}
+
/*
* based on libthread's threadsetname, but drags in less library code.
* actually just sets the arguments displayed.
@@ -1774,6 +820,83 @@
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 @@
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;
+ if(validip(conf.laddr)){
+ ndb2conf(db, conf.laddr);
+ doadd();
+ return;
+ }
+
+ memset(ips, 0, sizeof(ips));
+
+ 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;
}
- 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;
+ addaddrs(ips, sizeof(ips), conf.laddr, IPaddrlen);
}
- return s;
-}
+ ndbfree(t);
-void
-getoptions(uchar *p)
-{
- int i;
- char *s, *t;
+ n = countaddrs(ips, sizeof(ips));
+ if(n == 0)
+ sysfatal("no ip addresses found in ndb");
- 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);
+ /* 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;
+ }
}
- free(s);
+ 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();
+ }
}
}
--- a/sys/src/cmd/ip/ipconfig/mkfile
+++ b/sys/src/cmd/ip/ipconfig/mkfile
@@ -4,6 +4,7 @@
OFILES=\
main.$O\
+ dhcp.$O\
ipv6.$O\
ppp.$O\
--- a/sys/src/cmd/ip/ipconfig/ppp.c
+++ b/sys/src/cmd/ip/ipconfig/ppp.c
@@ -3,7 +3,6 @@
#include <ip.h>
#include <bio.h>
#include <ndb.h>
-#include "../dhcp.h"
#include "ipconfig.h"
void