diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-05-01 23:32:28 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-05-01 23:32:28 +0200 |
commit | 190c40c9fff3eafd23ab89cb445d4f85d29963b0 (patch) | |
tree | a6d3ee36203c112ddeb129ea52fae96c74392683 /sys | |
parent | 8e53fe132efe25437f50974f107be4f1fcbad2ea (diff) |
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.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/include/ip.h | 4 | ||||
-rw-r--r-- | sys/src/cmd/ip/ipconfig/dhcp.c | 979 | ||||
-rw-r--r-- | sys/src/cmd/ip/ipconfig/ipconfig.h | 187 | ||||
-rw-r--r-- | sys/src/cmd/ip/ipconfig/ipv6.c | 819 | ||||
-rw-r--r-- | sys/src/cmd/ip/ipconfig/main.c | 1736 | ||||
-rw-r--r-- | sys/src/cmd/ip/ipconfig/mkfile | 1 | ||||
-rw-r--r-- | sys/src/cmd/ip/ipconfig/ppp.c | 1 |
7 files changed, 1984 insertions, 1743 deletions
diff --git a/sys/include/ip.h b/sys/include/ip.h index a719a1b41..56e707729 100644 --- a/sys/include/ip.h +++ b/sys/include/ip.h @@ -88,8 +88,8 @@ enum { V6nd_home = 8, V6nd_srcaddrs = 9, /* rfc3122 */ V6nd_ip = 17, - /* /lib/rfc/drafts/draft-jeong-dnsop-ipv6-dns-discovery-12.txt */ - V6nd_rdns = 25, + V6nd_rdns = 25, /* rfc6106 */ + V6nd_rdnssl = 31, /* plan 9 extensions */ V6nd_9fs = 250, V6nd_9auth = 251, diff --git a/sys/src/cmd/ip/ipconfig/dhcp.c b/sys/src/cmd/ip/ipconfig/dhcp.c new file mode 100644 index 000000000..4f6075857 --- /dev/null +++ b/sys/src/cmd/ip/ipconfig/dhcp.c @@ -0,0 +1,979 @@ +/* + * ipconfig - configure parameters of an ip stack + */ +#include <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; +} + diff --git a/sys/src/cmd/ip/ipconfig/ipconfig.h b/sys/src/cmd/ip/ipconfig/ipconfig.h index 888b87f87..7f58a5148 100644 --- a/sys/src/cmd/ip/ipconfig/ipconfig.h +++ b/sys/src/cmd/ip/ipconfig/ipconfig.h @@ -1,3 +1,23 @@ +/* possible verbs */ +enum +{ + /* commands */ + Vadd, + Vremove, + Vunbind, + Vaddpref6, + Vra6, + + /* media */ + Vether, + Vgbe, + Vppp, + Vloopback, + Vtorus, + Vtree, + Vpkt, +}; + typedef struct Conf Conf; typedef struct Ctl Ctl; @@ -22,7 +42,7 @@ struct Conf uchar laddr[IPaddrlen]; uchar mask[IPaddrlen]; uchar raddr[IPaddrlen]; - uchar dns[2*IPaddrlen]; + uchar dns[8*IPaddrlen]; uchar fs[2*IPaddrlen]; uchar auth[2*IPaddrlen]; uchar ntp[2*IPaddrlen]; @@ -60,12 +80,15 @@ struct Conf int ttl; /* default 0 (unspecified) */ /* prefix related */ + uchar lladdr[IPaddrlen]; uchar v6pref[IPaddrlen]; int prefixlen; uchar onlink; /* flag: address is `on-link' */ uchar autoflag; /* flag: autonomous */ ulong validlt; /* valid lifetime (seconds) */ ulong preflt; /* preferred lifetime (seconds) */ + + char dnsdomain[256]; }; struct Ctl @@ -74,152 +97,60 @@ struct Ctl char *ctl; }; -extern Ctl *firstctl, **ctll; - -extern Conf conf; - +extern 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); diff --git a/sys/src/cmd/ip/ipconfig/ipv6.c b/sys/src/cmd/ip/ipconfig/ipv6.c index 941bd2c6d..c1e8cde8f 100644 --- a/sys/src/cmd/ip/ipconfig/ipv6.c +++ b/sys/src/cmd/ip/ipconfig/ipv6.c @@ -8,71 +8,97 @@ #include <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] = { @@ -132,14 +158,9 @@ uchar v6defmask[IPaddrlen] = { 0, 0, 0, 0 }; -enum -{ - Vadd, - Vremove, - Vunbind, - Vaddpref6, - Vra6, -}; +#pragma varargck argpos ralog 1 + +#define RALOG "v6routeradv" static void ralog(char *fmt, ...) @@ -154,45 +175,14 @@ ralog(char *fmt, ...) } 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,69 +195,111 @@ v6paraminit(Conf *cf) 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; - - a = ps; - for (pktlen = pe - ps; pktlen > 0; pktlen -= osz) { - otype = a[0]; - osz = a[1] * 8; - - switch (otype) { - default: - return seprint(p, e, " option=%s ", optname(otype)); - case V6nd_srclladdr: - case V6nd_targlladdr: - if(pktlen < osz || osz != 8) - return seprint(p, e, " option=%s bad size=%d", - optname(otype), osz); - p = seprint(p, e, " option=%s maddr=%E", optname(otype), - a+2); - break; - case V6nd_pfxinfo: - if(pktlen < osz || osz != 32) - return seprint(p, e, " option=%s: bad size=%d", - optname(otype), osz); - - p = seprint(p, e, " option=%s pref=%I preflen=%3.3d" - " lflag=%1.1d aflag=%1.1d unused1=%1.1d" - " validlt=%ud preflt=%ud unused2=%1.1d", - optname(otype), a+16, (int)(*(a+2)), - (*(a+3) & (1 << 7)) != 0, - (*(a+3) & (1 << 6)) != 0, - (*(a+3) & 63) != 0, - NetL(a+4), NetL(a+8), NetL(a+12)!=0); - break; + 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(); } - 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 @@ -277,13 +309,13 @@ dialicmpv6(uchar *ip, int port) int fd, cfd; snprint(addr, sizeof(addr), "%s/icmpv6!%I!%d!r", conf.mpoint, ip, port); - snprint(local, sizeof(local), "%I!%d", conf.laddr, port); + snprint(local, sizeof(local), "%I!%d", conf.lladdr, port); if((fd = dial(addr, local, nil, &cfd)) < 0) sysfatal("dialicmp6: %r"); fprint(cfd, "headers"); fprint(cfd, "ignoreadvice"); if(ISIPV6MCAST(ip)) - fprint(cfd, "addmulti %I", conf.laddr); + fprint(cfd, "addmulti %I", conf.lladdr); close(cfd); return fd; } @@ -301,7 +333,7 @@ arpenter(uchar *ip, uchar *mac) warning("couldn't open %s: %r", buf); return -1; } - n = snprint(buf, sizeof buf, "add %s %I %E %I\n", conf.type, ip, mac, conf.laddr); + n = snprint(buf, sizeof buf, "add %s %I %E %I\n", conf.type, ip, mac, conf.lladdr); if(write(fd, buf, n) != n) { warning("arpenter: %s: %r", buf); close(fd); @@ -341,35 +373,6 @@ arpcheck(uchar *ip) return rv; } -static int -masklen(uchar *mask) -{ - int len; - - for(len=0; len < 128; len += 8){ - if(*mask != 255) - break; - mask++; - } - while(len < 128 && (*mask & (0x80 >> (len & 7))) != 0) - len++; - return len; -} - -static void -genipmkask(uchar *mask, int len) -{ - memset(mask, 0, IPaddrlen); - if(len < 0) - len = 0; - else if(len > 128) - len = 128; - for(; len >= 8; len -= 8) - *mask++ = 255; - if(len > 0) - *mask = ~((1<<(8-len))-1); -} - /* add ipv6 addr to an interface */ int ip6cfg(void) @@ -417,8 +420,8 @@ Again: } warning("found dup entry in arp cache"); - doremove(); - return 0; + ipunconfig(); + return -1; } static int @@ -434,21 +437,6 @@ recvra6on(Ipifc *ifc) return IsHostNoRecv; } -static int -findllip(uchar *ip, Ipifc *ifc) -{ - Iplifc *lifc; - - for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){ - if(ISIPV6LINKLOCAL(lifc->ip)){ - ipmove(ip, lifc->ip); - return 1; - } - } - ipmove(ip, v6Unspecified); - return 0; -} - static void sendrs(int fd, uchar *dst) { @@ -459,14 +447,14 @@ sendrs(int fd, uchar *dst) memset(buf, 0, sizeof buf); - rs = (Routersol *)buf; + rs = (Routersol*)buf; rs->type = ICMP6_RS; ipmove(rs->dst, dst); - ipmove(rs->src, conf.laddr); + ipmove(rs->src, conf.lladdr); pktlen = sizeof *rs; if(conf.hwalen > 0){ - llao = (Lladdropt *)&buf[pktlen]; + llao = (Lladdropt*)&buf[pktlen]; llao->type = V6nd_srclladdr; llao->len = (2+7+conf.hwalen)/8; memmove(llao->lladdr, conf.hwa, conf.hwalen); @@ -494,8 +482,6 @@ recvrarouter(uchar buf[], int pktlen) USED(buf, pktlen); } -/* host receiving a router advertisement calls this */ - static void ewrite(int fd, char *str) { @@ -515,9 +501,9 @@ issuebasera6(Conf *cf) char *cfg; cfg = smprint("ra6 mflag %d oflag %d reachtime %d rxmitra %d " - "ttl %d routerlt %d", + "ttl %d routerlt %d linkmtu %d", cf->mflag, cf->oflag, cf->reachtime, cf->rxmitra, - cf->ttl, cf->routerlt); + cf->ttl, cf->routerlt, cf->linkmtu); ewrite(cf->cfd, cfg); free(cfg); } @@ -527,10 +513,8 @@ issuerara6(Conf *cf) { char *cfg; - cfg = smprint("ra6 sendra %d recvra %d maxraint %d minraint %d " - "linkmtu %d", - cf->sendra, cf->recvra, cf->maxraint, cf->minraint, - cf->linkmtu); + cfg = smprint("ra6 sendra %d recvra %d maxraint %d minraint %d", + cf->sendra, cf->recvra, cf->maxraint, cf->minraint); ewrite(cf->cfd, cfg); free(cfg); } @@ -547,6 +531,35 @@ issueadd6(Conf *cf) } 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 @@ seen(Conf *cf) return 0; } +static int +pnames(uchar *d, int nd, char *s) +{ + uchar *de = d + nd; + int l; + + if(nd < 1) + return -1; + for(; *s != 0; s++){ + for(l = 0; *s != 0 && *s != '.' && *s != ' '; l++) + s++; + + d += l+1; + if(d >= de || l > 077) + return -1; + + d[-l-1] = l; + memmove(d-l, s-l, l); + + if(*s != '.') + *d++ = 0; + } + return d - (de - nd); +} + +static int +gnames(char *d, int nd, uchar *s, int ns) +{ + uchar *se = s + ns; + char *de = d + nd; + int l; + + if(nd < 1 || ns < 1) + return -1; + l = *s++ & 077; + while(l > 0){ + if(d + l >= de || s + l >= se) + return -1; + + memmove(d, s, l); + d += l; + s += l; + + l = *s++ & 077; + if(l > 0) + *d++ = '.'; + else { + if(s >= se) + break; + + l = *s++ & 077; + if(l == 0) + break; + *d++ = ' '; + } + } + *d = 0; + return d - (de - nd); +} + +/* + * host receiving a router advertisement calls this + */ static void recvrahost(uchar buf[], int pktlen) { - int m, n, optype, needrefresh; - uchar src[IPaddrlen]; + char dnsdomain[sizeof(conf.dnsdomain)]; + int m, n, optype; Lladdropt *llao; Mtuopt *mtuo; Prefixopt *prfo; + Ipaddrsopt *addrso; Routeradv *ra; m = sizeof *ra; @@ -584,22 +661,27 @@ recvrahost(uchar buf[], int pktlen) conf.ttl = ra->cttl; conf.mflag = (MFMASK & ra->mor); conf.oflag = (OCMASK & ra->mor); - conf.routerlt = nhgets(ra->routerlt); + conf.routerlt = nhgets(ra->routerlt); conf.reachtime = nhgetl(ra->rchbltime); - conf.rxmitra = nhgetl(ra->rxmtimer); - issuebasera6(&conf); + conf.rxmitra = nhgetl(ra->rxmtimer); + conf.linkmtu = DEFMTU; + + 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)); - needrefresh = 0; + /* process options */ while(pktlen - m >= 8) { n = m; optype = buf[n]; m += 8 * buf[n+1]; - if(pktlen < m) + if(m <= n || pktlen < m) return; switch (optype) { case V6nd_srclladdr: - llao = (Lladdropt *)&buf[n]; + llao = (Lladdropt*)&buf[n]; if(llao->len == 1 && conf.hwalen == 6) arpenter(ra->src, llao->lladdr); break; @@ -607,63 +689,110 @@ recvrahost(uchar buf[], int pktlen) mtuo = (Mtuopt*)&buf[n]; conf.linkmtu = nhgetl(mtuo->mtu); break; - case V6nd_pfxinfo: - prfo = (Prefixopt*)&buf[n]; - if(prfo->len != 4) - break; - conf.prefixlen = prfo->plen & 127; - genipmkask(conf.mask, conf.prefixlen); - maskip(prfo->pref, conf.mask, conf.v6pref); - conf.onlink = ((prfo->lar & OLMASK) != 0); - conf.autoflag = ((prfo->lar & AFMASK) != 0); - conf.validlt = nhgetl(prfo->validlt); - conf.preflt = nhgetl(prfo->preflt); - issueadd6(&conf); - - if(conf.routerlt == 0) - ipmove(conf.gaddr, IPnoaddr); - else if((prfo->lar & RFMASK) != 0) - ipmove(conf.gaddr, prfo->pref); - else - ipmove(conf.gaddr, ra->src); - - /* report prefix only once */ - if(seen(&conf)) + case V6nd_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; - if(conf.prefixlen == 0 - || !validip(conf.v6pref) - || isv4(conf.v6pref) - || ipcmp(conf.v6pref, v6loopback) == 0 - || ISIPV6MCAST(conf.v6pref) - || ISIPV6LINKLOCAL(conf.v6pref)){ - ralog("igoring bogus prefix from %I on %s; pfx %I %M", - ra->src, conf.dev, conf.v6pref, conf.mask); + case V6nd_rdns: + addrso = (Ipaddrsopt*)&buf[n]; + n = (addrso->len - 1) * 8; + if(n == 0 || n % IPaddrlen) break; - } - - ralog("got initial RA from %I on %s; pfx %I %M", - ra->src, conf.dev, conf.v6pref, conf.mask); + addaddrs(conf.dns, sizeof(conf.dns), addrso->addrs, n); + break; - 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; + 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); + + /* process prefixes */ + m = sizeof *ra; + while(pktlen - m >= 8) { + n = m; + optype = buf[n]; + m += 8 * buf[n+1]; + if(m <= n || pktlen < m) + return; + + if(optype != V6nd_pfxinfo) + continue; + + prfo = (Prefixopt*)&buf[n]; + if(prfo->len != 4) + continue; + + conf.prefixlen = prfo->plen & 127; + genipmkask(conf.mask, conf.prefixlen); + maskip(prfo->pref, conf.mask, conf.v6pref); + memmove(conf.laddr, conf.v6pref, 8); + memmove(conf.laddr+8, conf.lladdr+8, 8); + conf.onlink = ((prfo->lar & OLMASK) != 0); + conf.autoflag = ((prfo->lar & AFMASK) != 0); + conf.validlt = nhgetl(prfo->validlt); + conf.preflt = nhgetl(prfo->preflt); + + if(conf.routerlt == 0) + ipmove(conf.gaddr, IPnoaddr); + else if((prfo->lar & RFMASK) != 0) + ipmove(conf.gaddr, prfo->pref); + else + ipmove(conf.gaddr, ra->src); + + if(conf.prefixlen < 1 + || conf.prefixlen > 64 + || !validip(conf.v6pref) + || isv4(conf.v6pref) + || ipcmp(conf.v6pref, v6loopback) == 0 + || ISIPV6MCAST(conf.v6pref) + || ISIPV6LINKLOCAL(conf.v6pref)){ + if(!seen(&conf)) + ralog("igoring bogus prefix from %I on %s; pfx %I %M", + ra->src, conf.dev, conf.v6pref, conf.mask); + continue; + } + + /* add prefix and update parameters */ + issueadd6(&conf); - if(needrefresh) + /* report this prefix configuration only once */ + if(seen(&conf)) + continue; + + ralog("got RA from %I on %s; pfx %I %M", + ra->src, conf.dev, conf.v6pref, conf.mask); + + if(validip(conf.gaddr)) + adddefroute(conf.gaddr, conf.lladdr, conf.laddr, conf.mask); + + if(beprimary) + putndb(); refresh(); + } } /* * daemon to receive router advertisements from routers */ -void +static int recvra6(void) { int fd, n, sendrscnt, recvracnt, sleepfor; @@ -674,30 +803,37 @@ recvra6(void) if(ifc == nil) sysfatal("can't read ipifc: %r"); - if(!findllip(conf.laddr, ifc)) + if(!findllip(conf.lladdr, ifc)) sysfatal("no link local address"); fd = dialicmpv6(v6allnodesL, ICMP6_RA); if(fd < 0) sysfatal("can't open icmp_ra connection: %r"); - notify(catch); - sendrscnt = Maxv6rss; - recvracnt = 0; - switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){ case -1: sysfatal("can't fork: %r"); default: close(fd); - return; + ralog("recvra6 on %s", conf.dev); + + /* wait for initial RA */ + return (int)(uintptr)rendezvous(recvra6, (void*)0); case 0: break; } + procsetname("recvra6 on %s %I", conf.dev, conf.lladdr); + notify(catch); + + sendrscnt = 0; + if(recvra6on(ifc) == IsHostRecv){ + sendrs(fd, v6allroutersL); + sendrscnt = Maxv6rss; + } - procsetname("recvra6 on %s %I", conf.dev, conf.laddr); - ralog("recvra6 on %s", conf.dev); + recvracnt = Maxv6initras; sleepfor = Minv6interradelay; + for (;;) { alarm(sleepfor); n = read(fd, buf, sizeof buf); @@ -711,34 +847,27 @@ recvra6(void) if(ifc == nil) { ralog("recvra6: can't read router params on %s, quitting on %s", conf.mpoint, conf.dev); + if(sendrscnt >= 0) + rendezvous(recvra6, (void*)-1); exits(nil); } - + if(n <= 0) { if(sendrscnt > 0) { sendrscnt--; - if(recvra6on(ifc) == IsHostRecv) - sendrs(fd, v6allroutersL); + sendrs(fd, v6allroutersL); sleepfor = V6rsintvl + nrand(100); } if(sendrscnt == 0) { sendrscnt--; - sleepfor = 0; ralog("recvra6: no router advs after %d sols on %s", Maxv6rss, conf.dev); + rendezvous(recvra6, (void*)0); + sleepfor = 0; } continue; } - /* got at least initial ra; no whining */ - sendrscnt = -1; - sleepfor = 0; - - if(++recvracnt >= Maxv6initras){ - recvracnt = 0; - sleepfor = Maxv6radelay; - } - switch (recvra6on(ifc)) { case IsRouter: recvrarouter(buf, n); @@ -748,8 +877,23 @@ recvra6(void) break; case IsHostNoRecv: ralog("recvra6: recvra off, quitting on %s", conf.dev); + if(sendrscnt >= 0) + rendezvous(recvra6, (void*)-1); exits(nil); } + + /* got at least initial ra; no whining */ + if(sendrscnt >= 0) + rendezvous(recvra6, (void*)1); + sendrscnt = -1; + sleepfor = 0; + + if(recvracnt > 0) + recvracnt--; + else { + recvracnt = Maxv6initras; + sleepfor = Maxv6radelay; + } } } @@ -758,7 +902,7 @@ recvra6(void) * 0 -- no arp table updates * 1 -- successful arp table update */ -int +static int recvrs(uchar *buf, int pktlen, uchar *sol) { int n; @@ -766,11 +910,11 @@ recvrs(uchar *buf, int pktlen, uchar *sol) Lladdropt *llao; n = sizeof *rs + sizeof *llao; - rs = (Routersol *)buf; + rs = (Routersol*)buf; if(pktlen < n) return 0; - llao = (Lladdropt *)&buf[sizeof *rs]; + llao = (Lladdropt*)&buf[sizeof *rs]; if(llao->type != V6nd_srclladdr || llao->len != 1 || conf.hwalen != 6) return 0; @@ -787,21 +931,28 @@ recvrs(uchar *buf, int pktlen, uchar *sol) return 1; } -void -sendra(int fd, uchar *dst, int rlt, Ipifc *ifc) +static void +sendra(int fd, uchar *dst, int rlt, Ipifc *ifc, Ndb *db) { - uchar buf[1024]; - Iplifc *lifc; - Lladdropt *llao; + uchar dns[sizeof(conf.dns)], fs[sizeof(conf.fs)], auth[sizeof(conf.auth)]; + char dnsdomain[sizeof(conf.dnsdomain)]; + Ipaddrsopt *addrso; Prefixopt *prfo; + Iplifc *lifc; Routeradv *ra; - int pktlen; + uchar buf[1024]; + int pktlen, n; + + memset(dns, 0, sizeof(dns)); + memset(fs, 0, sizeof(fs)); + memset(auth, 0, sizeof(auth)); + memset(dnsdomain, 0, sizeof(dnsdomain)); memset(buf, 0, sizeof buf); - ra = (Routeradv *)buf; + ra = (Routeradv*)buf; ipmove(ra->dst, dst); - ipmove(ra->src, conf.laddr); + ipmove(ra->src, conf.lladdr); ra->type = ICMP6_RA; ra->cttl = conf.ttl; if(conf.mflag > 0) @@ -821,7 +972,7 @@ sendra(int fd, uchar *dst, int rlt, Ipifc *ifc) * link layer address option */ if(conf.hwalen > 0){ - llao = (Lladdropt *)&buf[pktlen]; + Lladdropt *llao = (Lladdropt *)&buf[pktlen]; llao->type = V6nd_srclladdr; llao->len = (2+7+conf.hwalen)/8; memmove(llao->lladdr, conf.hwa, conf.hwalen); @@ -832,13 +983,15 @@ sendra(int fd, uchar *dst, int rlt, Ipifc *ifc) for (lifc = (ifc != nil? ifc->lifc: nil); lifc != nil; lifc = lifc->next) { if(pktlen > sizeof buf - 4*8) break; + if(!validip(lifc->ip) || isv4(lifc->ip) || ipcmp(lifc->ip, v6loopback) == 0 || ISIPV6MCAST(lifc->ip) || ISIPV6LINKLOCAL(lifc->ip)) continue; - prfo = (Prefixopt *)&buf[pktlen]; + + prfo = (Prefixopt*)&buf[pktlen]; prfo->type = V6nd_pfxinfo; prfo->len = 4; prfo->plen = masklen(lifc->mask) & 127; @@ -849,55 +1002,110 @@ sendra(int fd, uchar *dst, int rlt, Ipifc *ifc) hnputl(prfo->validlt, lifc->validlt); hnputl(prfo->preflt, lifc->preflt); pktlen += 8 * prfo->len; + + /* get ndb configuration for this prefix */ + ipmove(conf.laddr, lifc->ip); + ndb2conf(db, lifc->net); + + addaddrs(dns, sizeof(dns), conf.dns, sizeof(conf.dns)); + addaddrs(fs, sizeof(fs), conf.fs, sizeof(conf.fs)); + addaddrs(auth, sizeof(auth), conf.auth, sizeof(conf.auth)); + + addnames(dnsdomain, conf.dnsdomain, sizeof(dnsdomain)); + } + + addrso = (Ipaddrsopt*)&buf[pktlen]; + n = pnames(addrso->addrs, sizeof buf - 8 - pktlen, dnsdomain); + if(n > 0){ + addrso->type = V6nd_rdnssl; + addrso->len = 1 + ((n + 7) / 8); + hnputl(addrso->lifetime, ~0L); + pktlen += 8 * addrso->len; + } + + if((n = countaddrs(dns, sizeof(dns))) > 0 && pktlen+8+n*IPaddrlen <= sizeof buf) { + addrso = (Ipaddrsopt*)&buf[pktlen]; + addrso->type = V6nd_rdns; + addrso->len = 1 + n*2; + memmove(addrso->addrs, dns, n*IPaddrlen); + hnputl(addrso->lifetime, ~0L); + pktlen += 8 * addrso->len; } + if(!plan9) + goto send; + + /* send plan9 specific options */ + if((n = countaddrs(fs, sizeof(fs))) > 0 && pktlen+8+n*IPaddrlen <= sizeof buf) { + addrso = (Ipaddrsopt*)&buf[pktlen]; + addrso->type = V6nd_9fs; + addrso->len = 1 + n*2; + memmove(addrso->addrs, fs, n*IPaddrlen); + hnputl(addrso->lifetime, ~0L); + pktlen += 8 * addrso->len; + } + if((n = countaddrs(auth, sizeof(auth))) > 0 && pktlen+8+n*IPaddrlen <= sizeof buf) { + addrso = (Ipaddrsopt*)&buf[pktlen]; + addrso->type = V6nd_9auth; + addrso->len = 1 + n*2; + memmove(addrso->addrs, auth, n*IPaddrlen); + hnputl(addrso->lifetime, ~0L); + pktlen += 8 * addrso->len; + } + +send: write(fd, buf, pktlen); } /* * daemon to send router advertisements to hosts */ -void +static void sendra6(void) { int fd, n, sleepfor, nquitmsgs; uchar buf[4096], dst[IPaddrlen]; Ipifc *ifc; + Ndb *db; + + db = opendatabase(); + if(db == nil) + warning("couldn't open ndb: %r"); ifc = readipifc(conf.mpoint, nil, myifc); if(ifc == nil) sysfatal("can't read ipifc: %r"); - if(!findllip(conf.laddr, ifc)) + if(!findllip(conf.lladdr, ifc)) sysfatal("no link local address"); fd = dialicmpv6(v6allroutersL, ICMP6_RS); if(fd < 0) sysfatal("can't open icmp_rs connection: %r"); - notify(catch); - nquitmsgs = Maxv6finalras; - switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){ case -1: sysfatal("can't fork: %r"); default: close(fd); + ralog("sendra6 on %s", conf.dev); return; case 0: break; } + procsetname("sendra6 on %s %I", conf.dev, conf.lladdr); + notify(catch); - procsetname("sendra6 on %s %I", conf.dev, conf.laddr); - ralog("sendra6 on %s", conf.dev); + nquitmsgs = Maxv6finalras; sleepfor = 100 + jitter(); + for (;;) { alarm(sleepfor); n = read(fd, buf, sizeof buf); sleepfor = alarm(0); - if(n > 0 && recvrs(buf, n, dst) > 0) - sendra(fd, dst, 1, ifc); + if(ifc->sendra6 > 0 && n > 0 && recvrs(buf, n, dst) > 0) + sendra(fd, dst, 1, ifc, db); /* wait for alarm to expire */ if(sleepfor > 100) @@ -913,31 +1121,30 @@ sendra6(void) if(ifc->sendra6 <= 0){ if(nquitmsgs > 0) { nquitmsgs--; - sendra(fd, v6allnodesL, 0, ifc); + sendra(fd, v6allnodesL, 0, ifc, nil); continue; - } else { - ralog("sendra6: sendra off, quitting on %s", conf.dev); - exits(nil); } + ralog("sendra6: sendra off on %s, quitting on %s", + conf.mpoint, conf.dev); + exits(nil); } - sendra(fd, v6allnodesL, 1, ifc); + db = opendatabase(); + sendra(fd, v6allnodesL, 1, ifc, db); sleepfor = randint(ifc->rp.minraint, ifc->rp.maxraint); } } -void +static void startra6(void) { static char routeon[] = "iprouting 1"; - mklladdr(); - if(conf.recvra > 0) recvra6(); if(conf.sendra > 0) { if(write(conf.cfd, routeon, sizeof routeon - 1) < 0) { - warning("write (iprouting 1) failed: %r"); + warning("write (%s) failed: %r", routeon); return; } sendra6(); diff --git a/sys/src/cmd/ip/ipconfig/main.c b/sys/src/cmd/ip/ipconfig/main.c index a699994cd..e051821d9 100644 --- a/sys/src/cmd/ip/ipconfig/main.c +++ b/sys/src/cmd/ip/ipconfig/main.c @@ -3,216 +3,49 @@ */ #include <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 - -/* possible verbs */ -enum -{ - /* commands */ - Vadd, - Vremove, - Vunbind, - Vaddpref6, - Vra6, - /* media */ - Vether, - Vgbe, - Vppp, - Vloopback, - Vtorus, - Vtree, - Vpkt, -}; - -enum -{ - Taddr, - Taddrs, - Tstr, - Tbyte, - Tulong, - Tvec, -}; - -typedef struct Option Option; -struct Option -{ - char *name; - int type; -}; +Conf conf; +int myifc = -1; +int beprimary = -1; +int noconfig; +Ipifc *ifc; +Ctl *firstctl, **ctll = &firstctl; -/* - * 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 debug; +int dolog; +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", -}; - -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 binddevice(void); +static void controldevice(void); +extern void pppbinddev(void); + +static void doadd(void); +static void doremove(void); +static void dounbind(void); +static void ndbconfig(void); void usage(void) @@ -224,6 +57,29 @@ usage(void) exits("usage"); } +static void +init(void) +{ + srand(truerand()); + fmtinstall('E', eipfmt); + fmtinstall('I', eipfmt); + fmtinstall('M', eipfmt); + fmtinstall('V', eipfmt); + nsec(); /* make sure time file is open before forking */ + + conf.cfd = -1; + conf.rfd = -1; + + setnetmtpt(conf.mpoint, sizeof conf.mpoint, nil); + conf.cputype = getenv("cputype"); + if(conf.cputype == nil) + conf.cputype = "386"; + + v6paraminit(&conf); + + dhcpinit(); +} + void warning(char *fmt, ...) { @@ -274,82 +130,6 @@ parsenorm(int argc, char **argv) } } -static void -parse6pref(int argc, char **argv) -{ - switch(argc){ - case 6: - conf.preflt = strtoul(argv[5], 0, 10); - /* fall through */ - case 5: - conf.validlt = strtoul(argv[4], 0, 10); - /* fall through */ - case 4: - conf.autoflag = (atoi(argv[3]) != 0); - /* fall through */ - case 3: - conf.onlink = (atoi(argv[2]) != 0); - /* fall through */ - case 2: - conf.prefixlen = atoi(argv[1]); - /* fall through */ - case 1: - if (parseip(conf.v6pref, argv[0]) == -1) - sysfatal("bad address %s", argv[0]); - break; - } - DEBUG("parse6pref: pref %I len %d", conf.v6pref, conf.prefixlen); -} - -/* parse router advertisement (keyword, value) pairs */ -static void -parse6ra(int argc, char **argv) -{ - int i, argsleft; - char *kw, *val; - - if (argc % 2 != 0) - usage(); - - i = 0; - for (argsleft = argc; argsleft > 1; argsleft -= 2) { - kw = argv[i]; - val = argv[i+1]; - if (strcmp(kw, "recvra") == 0) - conf.recvra = (atoi(val) != 0); - else if (strcmp(kw, "sendra") == 0) - conf.sendra = (atoi(val) != 0); - else if (strcmp(kw, "mflag") == 0) - conf.mflag = (atoi(val) != 0); - else if (strcmp(kw, "oflag") == 0) - conf.oflag = (atoi(val) != 0); - else if (strcmp(kw, "maxraint") == 0) - conf.maxraint = atoi(val); - else if (strcmp(kw, "minraint") == 0) - conf.minraint = atoi(val); - else if (strcmp(kw, "linkmtu") == 0) - conf.linkmtu = atoi(val); - else if (strcmp(kw, "reachtime") == 0) - conf.reachtime = atoi(val); - else if (strcmp(kw, "rxmitra") == 0) - conf.rxmitra = atoi(val); - else if (strcmp(kw, "ttl") == 0) - conf.ttl = atoi(val); - else if (strcmp(kw, "routerlt") == 0) - conf.routerlt = atoi(val); - else { - warning("bad ra6 keyword %s", kw); - usage(); - } - i += 2; - } - - /* consistency check */ - if (conf.maxraint < conf.minraint) - sysfatal("maxraint %d < minraint %d", - conf.maxraint, conf.minraint); -} - static char* finddev(char *dir, char *name, char *dev) { @@ -374,45 +154,32 @@ finddev(char *dir, char *name, char *dev) return dev; } +/* look for an action */ static int -findifc(char *net, char *dev) +parseverb(char *name) { - Ipifc *nifc; - - ifc = readipifc(net, ifc, -1); - for(nifc = ifc; nifc != nil; nifc = nifc->next) - if(strcmp(nifc->dev, dev) == 0) - return nifc->index; + static char *verbs[] = { + [Vadd] "add", + [Vremove] "remove", + [Vunbind] "unbind", + [Vether] "ether", + [Vgbe] "gbe", + [Vppp] "ppp", + [Vloopback] "loopback", + [Vaddpref6] "add6", + [Vra6] "ra6", + [Vtorus] "torus", + [Vtree] "tree", + [Vpkt] "pkt", + }; + int i; + for(i = 0; i < nelem(verbs); i++) + if(verbs[i] != nil && strcmp(name, verbs[i]) == 0) + return i; return -1; } -static void -init(void) -{ - srand(truerand()); - fmtinstall('E', eipfmt); - fmtinstall('I', eipfmt); - fmtinstall('M', eipfmt); - fmtinstall('V', eipfmt); - nsec(); /* make sure time file is open before forking */ - - conf.cfd = -1; - conf.rfd = -1; - - setnetmtpt(conf.mpoint, sizeof conf.mpoint, nil); - conf.cputype = getenv("cputype"); - if(conf.cputype == nil) - conf.cputype = "386"; - - ctll = &firstctl; - v6paraminit(&conf); - - /* init set of requested dhcp parameters with the default */ - nrequested = sizeof defrequested; - memcpy(requested, defrequested, nrequested); -} - static int parseargs(int argc, char **argv) { @@ -498,14 +265,26 @@ parseargs(int argc, char **argv) return action; } +static int +findifc(char *net, char *dev) +{ + Ipifc *nifc; + + ifc = readipifc(net, ifc, -1); + for(nifc = ifc; nifc != nil; nifc = nifc->next) + if(strcmp(nifc->dev, dev) == 0) + return nifc->index; + + return -1; +} + void main(int argc, char **argv) { - int retry, action; + int action; Ctl *cp; init(); - retry = 0; ARGBEGIN { case '6': /* IPv6 auto config */ ipv6auto = 1; @@ -566,7 +345,7 @@ main(int argc, char **argv) beprimary = 0; break; case 'r': - retry = 1; + rflag = 1; break; case 'u': /* IPv6: duplicate neighbour disc. off */ dupl_disc = 0; @@ -607,7 +386,12 @@ main(int argc, char **argv) switch(action){ case Vadd: - doadd(retry); + if(dondbconfig){ + dodhcp = 0; + ndbconfig(); + return; + } + doadd(); break; case Vaddpref6: case Vra6: @@ -623,14 +407,51 @@ main(int argc, char **argv) exits(nil); } -void -doadd(int retry) +static int +isether(void) +{ + return strcmp(conf.type, "ether") == 0 || strcmp(conf.type, "gbe") == 0; +} + +/* create link local address */ +static void +mklladdr(void) +{ + if(isether() && myetheraddr(conf.hwa, conf.dev) == 0){ + conf.hwalen = 6; + conf.hwatype = 1; + } else { + genrandom(conf.hwa, sizeof(conf.hwa)); + conf.hwatype = -1; + } + ea2lla(conf.lladdr, conf.hwa); +} + +/* create a client id */ +static void +mkclientid(void) +{ + if(isether() && myetheraddr(conf.hwa, conf.dev) == 0){ + conf.hwalen = 6; + conf.hwatype = 1; + conf.cid[0] = conf.hwatype; + memmove(&conf.cid[1], conf.hwa, conf.hwalen); + conf.cidlen = conf.hwalen+1; + } else { + conf.hwatype = -1; + snprint((char*)conf.cid, sizeof conf.cid, + "plan9_%ld.%d", lrand(), getpid()); + conf.cidlen = strlen((char*)conf.cid); + } +} + +static void +doadd(void) { if(!validip(conf.laddr)){ - if(dondbconfig) - ndbconfig(); - else if(ipv6auto){ + if(ipv6auto){ mklladdr(); + ipmove(conf.laddr, conf.lladdr); dodhcp = 0; } else dodhcp = 1; @@ -645,13 +466,14 @@ doadd(int retry) } if(!validip(conf.laddr)) - if(retry && dodhcp && !noconfig){ + if(rflag && dodhcp && !noconfig){ warning("couldn't determine ip address, retrying"); dhcpwatch(1); return; } else sysfatal("no success with DHCP"); + DEBUG("adding address %I %M on %s", conf.laddr, conf.mask, conf.dev); if(noconfig) return; @@ -671,7 +493,7 @@ doadd(int retry) refresh(); } -void +static void doremove(void) { if(!validip(conf.laddr)) @@ -680,108 +502,15 @@ doremove(void) warning("can't remove %I %M: %r", conf.laddr, conf.mask); } -void +static void dounbind(void) { if(fprint(conf.cfd, "unbind") < 0) warning("can't unbind %s: %r", conf.dev); } -int -issrcspec(uchar *src, uchar *smask) -{ - return isv4(src)? memcmp(smask+IPv4off, IPnoaddr+IPv4off, 4): ipcmp(smask, IPnoaddr); -} -void -addroute(uchar *dst, uchar *mask, uchar *gate, uchar *laddr, uchar *src, uchar *smask) -{ - char *cmd; - - if(issrcspec(src, smask)) - cmd = "add %I %M %I %I %I %M"; - else - cmd = "add %I %M %I %I"; - fprint(conf.rfd, cmd, dst, mask, gate, laddr, src, smask); -} -void -removeroute(uchar *dst, uchar *mask, uchar *src, uchar *smask) -{ - char *cmd; - - if(issrcspec(src, smask)) - cmd = "remove %I %M %I %M"; - else - cmd = "remove %I %M"; - fprint(conf.rfd, cmd, dst, mask, src, smask); -} -void -adddefroute(uchar *gaddr, uchar *laddr, uchar *src, uchar *smask) -{ - uchar dst[IPaddrlen], mask[IPaddrlen]; - - if(isv4(gaddr)){ - parseip(dst, "0.0.0.0"); - parseipmask(mask, "0.0.0.0"); - if(src == nil) - src = dst; - if(smask == nil) - smask = mask; - } else { - parseip(dst, "2000::"); - parseipmask(mask, "/3"); - if(src == nil) - src = IPnoaddr; - if(smask == nil) - smask = IPnoaddr; - } - addroute(dst, mask, gaddr, laddr, src, smask); - - /* also add a source specific route */ - if(ipcmp(src, IPnoaddr) != 0 && ipcmp(src, v4prefix) != 0) - addroute(dst, mask, gaddr, laddr, src, IPallbits); -} - - -int -isether(void) -{ - return strcmp(conf.type, "ether") == 0 || strcmp(conf.type, "gbe") == 0; -} - -/* create link local address */ -void -mklladdr(void) -{ - if(isether() && myetheraddr(conf.hwa, conf.dev) == 0){ - conf.hwalen = 6; - conf.hwatype = 1; - } else { - genrandom(conf.hwa, sizeof(conf.hwa)); - conf.hwatype = -1; - } - ea2lla(conf.laddr, conf.hwa); -} - -/* create a client id */ -void -mkclientid(void) -{ - if(isether() && myetheraddr(conf.hwa, conf.dev) == 0){ - conf.hwalen = 6; - conf.hwatype = 1; - conf.cid[0] = conf.hwatype; - memmove(&conf.cid[1], conf.hwa, conf.hwalen); - conf.cidlen = conf.hwalen+1; - } else { - conf.hwatype = -1; - snprint((char*)conf.cid, sizeof conf.cid, - "plan9_%ld.%d", lrand(), getpid()); - conf.cidlen = strlen((char*)conf.cid); - } -} - /* send some ctls to a device */ -void +static void controldevice(void) { char ctlfile[256]; @@ -805,7 +534,7 @@ controldevice(void) } /* bind an ip stack to a device, leave the control channel open */ -void +static void binddevice(void) { char buf[256]; @@ -867,7 +596,7 @@ ip4cfg(void) return 0; } -/* remove a logical interface to the ip stack */ +/* remove a logical interface from the ip stack */ void ipunconfig(void) { @@ -886,762 +615,15 @@ ipunconfig(void) ipmove(conf.mask, IPnoaddr); } -void -ding(void*, char *msg) -{ - if(strstr(msg, "alarm")) - noted(NCONT); - noted(NDFLT); -} - -void -dhcpquery(int needconfig, int startstate) -{ - if(needconfig) - fprint(conf.cfd, "add %I %I", IPnoaddr, IPnoaddr); - - conf.fd = openlisten(); - if(conf.fd < 0){ - conf.state = Sinit; - return; - } - notify(ding); - - conf.xid = lrand(); - conf.starttime = time(0); - conf.state = startstate; - switch(startstate){ - case Sselecting: - conf.offered = 0; - dhcpsend(Discover); - break; - case Srenewing: - dhcpsend(Request); - break; - default: - sysfatal("internal error 0"); - } - conf.resend = 0; - conf.timeout = time(0) + 4; - - while(conf.state != Sbound && conf.state != Sinit){ - dhcprecv(); - dhcptimer(); - } - close(conf.fd); - - if(needconfig) - fprint(conf.cfd, "remove %I %I", IPnoaddr, IPnoaddr); - -} - -enum { - /* - * was an hour, needs to be less for the ARM/GS1 until the timer - * code has been cleaned up (pb). - */ - Maxsleep = 450, -}; - -void -dhcpwatch(int needconfig) -{ - ulong secs, s, t; - - if(nodhcpwatch) - return; - - switch(rfork(RFPROC|RFFDG|RFNOWAIT|RFNOTEG)){ - default: - return; - case 0: - break; - } - - dolog = 1; /* log, don't print */ - procsetname("dhcpwatch on %s", conf.dev); - /* keep trying to renew the lease */ - for(;;){ - secs = conf.lease/2; - if(secs < 5) - secs = 5; - - /* avoid overflows */ - for(s = secs; s > 0; s -= t){ - if(s > Maxsleep) - t = Maxsleep; - else - t = s; - sleep(t*1000); - } - - if(conf.lease > 0){ - /* - * during boot, the starttime can be bogus so avoid - * spurious ipunconfig's - */ - t = time(0) - conf.starttime; - if(t > (3*secs)/2) - t = secs; - if(t >= conf.lease){ - conf.lease = 0; - if(!noconfig){ - ipunconfig(); - needconfig = 1; - } - } else - conf.lease -= t; - } - dhcpquery(needconfig, needconfig? Sselecting: Srenewing); - - if(needconfig && conf.state == Sbound){ - if(ip4cfg() < 0) - sysfatal("can't start ip: %r"); - needconfig = 0; - /* - * leave everything we've learned somewhere that - * other procs can find it. - */ - if(beprimary) - putndb(); - refresh(); - } - } -} - -void -dhcptimer(void) -{ - ulong now; - - now = time(0); - if(now < conf.timeout) - return; - - switch(conf.state) { - default: - sysfatal("dhcptimer: unknown state %d", conf.state); - case Sinit: - case Sbound: - break; - case Sselecting: - case Srequesting: - case Srebinding: - dhcpsend(conf.state == Sselecting? Discover: Request); - conf.timeout = now + 4; - if(++conf.resend > 5) - conf.state = Sinit; - break; - case Srenewing: - dhcpsend(Request); - conf.timeout = now + 1; - if(++conf.resend > 3) { - conf.state = Srebinding; - conf.resend = 0; - } - break; - } -} - -void -dhcpsend(int type) -{ - Bootp bp; - uchar *p; - int n; - uchar vendor[64]; - Udphdr *up = (Udphdr*)bp.udphdr; - - memset(&bp, 0, sizeof bp); - - hnputs(up->rport, 67); - bp.op = Bootrequest; - hnputl(bp.xid, conf.xid); - hnputs(bp.secs, time(0)-conf.starttime); - hnputs(bp.flags, 0); - memmove(bp.optmagic, optmagic, 4); - if(conf.hwatype >= 0 && conf.hwalen < sizeof bp.chaddr){ - memmove(bp.chaddr, conf.hwa, conf.hwalen); - bp.hlen = conf.hwalen; - bp.htype = conf.hwatype; - } - p = bp.optdata; - p = optaddbyte(p, ODtype, type); - p = optadd(p, ODclientid, conf.cid, conf.cidlen); - switch(type) { - default: - sysfatal("dhcpsend: unknown message type: %d", type); - case Discover: - ipmove(up->raddr, IPv4bcast); /* broadcast */ - if(*conf.hostname && sendhostname) - p = optaddstr(p, OBhostname, conf.hostname); - if(plan9){ - n = snprint((char*)vendor, sizeof vendor, - "plan9_%s", conf.cputype); - p = optaddvec(p, ODvendorclass, vendor, n); - } - p = optaddvec(p, ODparams, requested, nrequested); - if(validip(conf.laddr)) - p = optaddaddr(p, ODipaddr, conf.laddr); - break; - case Request: - switch(conf.state){ - case Srenewing: - ipmove(up->raddr, conf.server); - v6tov4(bp.ciaddr, conf.laddr); - break; - case Srebinding: - ipmove(up->raddr, IPv4bcast); /* broadcast */ - v6tov4(bp.ciaddr, conf.laddr); - break; - case Srequesting: - ipmove(up->raddr, IPv4bcast); /* broadcast */ - p = optaddaddr(p, ODipaddr, conf.laddr); - p = optaddaddr(p, ODserverid, conf.server); - break; - } - p = optaddulong(p, ODlease, conf.offered); - if(plan9){ - n = snprint((char*)vendor, sizeof vendor, - "plan9_%s", conf.cputype); - p = optaddvec(p, ODvendorclass, vendor, n); - } - p = optaddvec(p, ODparams, requested, nrequested); - if(*conf.hostname && sendhostname) - p = optaddstr(p, OBhostname, conf.hostname); - break; - case Release: - ipmove(up->raddr, conf.server); - v6tov4(bp.ciaddr, conf.laddr); - p = optaddaddr(p, ODipaddr, conf.laddr); - p = optaddaddr(p, ODserverid, conf.server); - break; - } - - *p++ = OBend; - - n = p - (uchar*)&bp; - USED(n); - - /* - * We use a maximum size DHCP packet to survive the - * All_Aboard NAT package from Internet Share. It - * always replies to DHCP requests with a packet of the - * same size, so if the request is too short the reply - * is truncated. - */ - if(write(conf.fd, &bp, sizeof bp) != sizeof bp) - warning("dhcpsend: write failed: %r"); -} - -void -dhcprecv(void) -{ - int i, n, type; - ulong lease; - char err[ERRMAX]; - uchar buf[8000], vopts[256], taddr[IPaddrlen]; - Bootp *bp; - - memset(buf, 0, sizeof buf); - alarm(1000); - n = read(conf.fd, buf, sizeof buf); - alarm(0); - - if(n < 0){ - rerrstr(err, sizeof err); - if(strstr(err, "interrupt") == nil) - warning("dhcprecv: bad read: %s", err); - else - DEBUG("dhcprecv: read timed out"); - return; - } - - bp = parsebootp(buf, n); - if(bp == 0) { - DEBUG("parsebootp failed: dropping packet"); - return; - } - - type = optgetbyte(bp->optdata, ODtype); - switch(type) { - default: - warning("dhcprecv: unknown type: %d", type); - break; - case Offer: - DEBUG("got offer from %V ", bp->siaddr); - if(conf.state != Sselecting) - break; - lease = optgetulong(bp->optdata, ODlease); - if(lease == 0){ - /* - * The All_Aboard NAT package from Internet Share - * doesn't give a lease time, so we have to assume one. - */ - warning("Offer with %lud lease, using %d", lease, MinLease); - lease = MinLease; - } - DEBUG("lease=%lud ", lease); - if(!optgetaddr(bp->optdata, ODserverid, conf.server)) { - warning("Offer from server with invalid serverid"); - break; - } - - v4tov6(conf.laddr, bp->yiaddr); - memmove(conf.sname, bp->sname, sizeof conf.sname); - conf.sname[sizeof conf.sname-1] = 0; - DEBUG("server=%I sname=%s", conf.server, conf.sname); - conf.offered = lease; - conf.state = Srequesting; - dhcpsend(Request); - conf.resend = 0; - conf.timeout = time(0) + 4; - break; - case Ack: - DEBUG("got ack from %V ", bp->siaddr); - if (conf.state != Srequesting && conf.state != Srenewing && - conf.state != Srebinding) - break; - - /* ignore a bad lease */ - lease = optgetulong(bp->optdata, ODlease); - if(lease == 0){ - /* - * The All_Aboard NAT package from Internet Share - * doesn't give a lease time, so we have to assume one. - */ - warning("Ack with %lud lease, using %d", lease, MinLease); - lease = MinLease; - } - DEBUG("lease=%lud ", lease); - - /* address and mask */ - if(!validip(conf.laddr) || !Oflag) - v4tov6(conf.laddr, bp->yiaddr); - if(!validip(conf.mask) || !Oflag){ - if(!optgetaddr(bp->optdata, OBmask, conf.mask)) - ipmove(conf.mask, IPnoaddr); - if(ipcmp(conf.mask, IPv4bcast) == 0) - ipmove(conf.mask, IPnoaddr); - } - DEBUG("ipaddr=%I ipmask=%M ", conf.laddr, conf.mask); - - /* - * get a router address either from the router option - * or from the router that forwarded the dhcp packet - */ - if(validip(conf.gaddr) && Oflag) { - DEBUG("ipgw=%I ", conf.gaddr); - } else if(optgetaddr(bp->optdata, OBrouter, conf.gaddr)){ - DEBUG("ipgw=%I ", conf.gaddr); - } else if(memcmp(bp->giaddr, IPnoaddr+IPv4off, IPv4addrlen)!=0){ - v4tov6(conf.gaddr, bp->giaddr); - DEBUG("giaddr=%I ", conf.gaddr); - } - - /* get dns servers */ - memset(conf.dns, 0, sizeof conf.dns); - n = optgetaddrs(bp->optdata, OBdnserver, conf.dns, - sizeof conf.dns/IPaddrlen); - for(i = 0; i < n; i++) - DEBUG("dns=%I ", conf.dns + i*IPaddrlen); - - /* get ntp servers */ - memset(conf.ntp, 0, sizeof conf.ntp); - n = optgetaddrs(bp->optdata, OBntpserver, conf.ntp, - sizeof conf.ntp/IPaddrlen); - for(i = 0; i < n; i++) - DEBUG("ntp=%I ", conf.ntp + i*IPaddrlen); - - /* get names */ - optgetstr(bp->optdata, OBhostname, - conf.hostname, sizeof conf.hostname); - optgetstr(bp->optdata, OBdomainname, - conf.domainname, sizeof conf.domainname); - - /* get anything else we asked for */ - getoptions(bp->optdata); - - /* get plan9-specific options */ - n = optgetvec(bp->optdata, OBvendorinfo, vopts, sizeof vopts-1); - if(n > 0 && parseoptions(vopts, n) == 0){ - if(validip(conf.fs) && Oflag) - n = 1; - else { - n = optgetp9addrs(vopts, OP9fs, conf.fs, 2); - if (n == 0) - n = optgetaddrs(vopts, OP9fsv4, - conf.fs, 2); - } - for(i = 0; i < n; i++) - DEBUG("fs=%I ", conf.fs + i*IPaddrlen); - - if(validip(conf.auth) && Oflag) - n = 1; - else { - n = optgetp9addrs(vopts, OP9auth, conf.auth, 2); - if (n == 0) - n = optgetaddrs(vopts, OP9authv4, - conf.auth, 2); - } - for(i = 0; i < n; i++) - DEBUG("auth=%I ", conf.auth + i*IPaddrlen); - - n = optgetp9addrs(vopts, OP9ipaddr, taddr, 1); - if (n > 0) - memmove(conf.laddr, taddr, IPaddrlen); - n = optgetp9addrs(vopts, OP9ipmask, taddr, 1); - if (n > 0) - memmove(conf.mask, taddr, IPaddrlen); - n = optgetp9addrs(vopts, OP9ipgw, taddr, 1); - if (n > 0) - memmove(conf.gaddr, taddr, IPaddrlen); - DEBUG("new ipaddr=%I new ipmask=%M new ipgw=%I", - conf.laddr, conf.mask, conf.gaddr); - } - conf.lease = lease; - conf.state = Sbound; - DEBUG("server=%I sname=%s", conf.server, conf.sname); - break; - case Nak: - conf.state = Sinit; - warning("recved dhcpnak on %s", conf.mpoint); - break; - } -} - -/* return pseudo-random integer in range low...(hi-1) */ -ulong -randint(ulong low, ulong hi) -{ - if (hi < low) - return low; - return low + nrand(hi - low); -} - -long -jitter(void) /* compute small pseudo-random delay in ms */ -{ - return randint(0, 10*1000); -} - -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; -} - -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 - */ +/* return true if this is not a null address */ 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) +validip(uchar *addr) { - 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; + return ipcmp(addr, IPnoaddr) != 0 && ipcmp(addr, v4prefix) != 0; } -/* put server addresses into the ndb entry */ -char* +/* put server ip addresses into the ndb entry */ +static char* putaddrs(char *p, char *e, char *attr, uchar *a, int len) { int i; @@ -1651,22 +633,20 @@ putaddrs(char *p, char *e, char *attr, uchar *a, int len) return p; } -void -refresh(void) +/* put space separated names into ndb entry */ +static char* +putnames(char *p, char *e, char *attr, char *s) { - char file[64]; - int fd; + char *x; - snprint(file, sizeof file, "%s/cs", conf.mpoint); - if((fd = open(file, OWRITE)) >= 0){ - write(fd, "refresh", 7); - close(fd); - } - snprint(file, sizeof file, "%s/dns", conf.mpoint); - if((fd = open(file, OWRITE)) >= 0){ - write(fd, "refresh", 7); - close(fd); + for(; *s != 0; s = x+1){ + if((x = strchr(s, ' ')) == nil) + x = strchr(s, 0); + p = seprint(p, e, "%s=%.*s\n", attr, (int)(x - s), s); + if(*x == 0) + break; } + return p; } /* make an ndb entry and put it into /net/ndb for the servers to see */ @@ -1693,12 +673,14 @@ putndb(void) if(*conf.domainname) p = seprint(p, e, "\tdom=%s.%s\n", conf.hostname, conf.domainname); + if(*conf.dnsdomain) + p = putnames(p, e, "\tdnsdomain", conf.dnsdomain); + if(validip(conf.dns)) + p = putaddrs(p, e, "\tdns", conf.dns, sizeof conf.dns); if(validip(conf.fs)) p = putaddrs(p, e, "\tfs", conf.fs, sizeof conf.fs); if(validip(conf.auth)) p = putaddrs(p, e, "\tauth", conf.auth, sizeof conf.auth); - if(validip(conf.dns)) - p = putaddrs(p, e, "\tdns", conf.dns, sizeof conf.dns); if(validip(conf.ntp)) p = putaddrs(p, e, "\tntp", conf.ntp, sizeof conf.ntp); if(ndboptions) @@ -1730,23 +712,87 @@ putndb(void) close(fd); } -/* return true if this is a valid v4 address */ -int -validip(uchar *addr) +static int +issrcspec(uchar *src, uchar *smask) { - return ipcmp(addr, IPnoaddr) != 0 && ipcmp(addr, v4prefix) != 0; + return isv4(src)? memcmp(smask+IPv4off, IPnoaddr+IPv4off, 4): ipcmp(smask, IPnoaddr); } -/* look for an action */ -int -parseverb(char *name) +void +addroute(uchar *dst, uchar *mask, uchar *gate, uchar *ia, uchar *src, uchar *smask) { - int i; + char *cmd; - for(i = 0; i < nelem(verbs); i++) - if(verbs[i] != nil && strcmp(name, verbs[i]) == 0) - return i; - return -1; + if(issrcspec(src, smask)) + cmd = "add %I %M %I %I %I %M"; + else + cmd = "add %I %M %I %I"; + fprint(conf.rfd, cmd, dst, mask, gate, ia, src, smask); +} + +void +removeroute(uchar *dst, uchar *mask, uchar *src, uchar *smask) +{ + char *cmd; + + if(issrcspec(src, smask)) + cmd = "remove %I %M %I %M"; + else + cmd = "remove %I %M"; + fprint(conf.rfd, cmd, dst, mask, src, smask); +} + +void +adddefroute(uchar *gaddr, uchar *ia, uchar *src, uchar *smask) +{ + uchar dst[IPaddrlen], mask[IPaddrlen]; + + if(isv4(gaddr)){ + parseip(dst, "0.0.0.0"); + parseipmask(mask, "0.0.0.0"); + if(src == nil) + src = dst; + if(smask == nil) + smask = mask; + } else { + parseip(dst, "2000::"); + parseipmask(mask, "/3"); + if(src == nil) + src = IPnoaddr; + if(smask == nil) + smask = IPnoaddr; + } + addroute(dst, mask, gaddr, ia, src, smask); + + /* also add a source specific route */ + if(ipcmp(src, IPnoaddr) != 0 && ipcmp(src, v4prefix) != 0) + addroute(dst, mask, gaddr, ia, src, IPallbits); +} + +void +refresh(void) +{ + char file[64]; + int fd; + + snprint(file, sizeof file, "%s/cs", conf.mpoint); + if((fd = open(file, OWRITE)) >= 0){ + write(fd, "refresh", 7); + close(fd); + } + snprint(file, sizeof file, "%s/dns", conf.mpoint); + if((fd = open(file, OWRITE)) >= 0){ + write(fd, "refresh", 7); + close(fd); + } +} + +void +catch(void*, char *msg) +{ + if(strstr(msg, "alarm")) + noted(NCONT); + noted(NDFLT); } /* @@ -1774,6 +820,83 @@ procsetname(char *fmt, ...) free(cmdname); } +/* return pseudo-random integer in range low...(hi-1) */ +ulong +randint(ulong low, ulong hi) +{ + if (hi < low) + return low; + return low + nrand(hi - low); +} + +long +jitter(void) /* compute small pseudo-random delay in ms */ +{ + return randint(0, 10*1000); +} + +int +countaddrs(uchar *a, int len) +{ + int i; + + for(i = 0; i < len && validip(a); i += IPaddrlen, a += IPaddrlen) + ; + return i / IPaddrlen; +} + +void +addaddrs(uchar *to, int nto, uchar *from, int nfrom) +{ + int i, j; + + for(i = 0; i < nfrom; i += IPaddrlen, from += IPaddrlen){ + if(!validip(from)) + continue; + for(j = 0; j < nto && validip(to+j); j += IPaddrlen){ + if(ipcmp(to+j, from) == 0) + return; + } + if(j == nto) + return; + ipmove(to+j, from); + } +} + +void +addnames(char *d, char *s, int len) +{ + char *p, *e, *f; + int n; + + for(;;s++){ + if((e = strchr(s, ' ')) == nil) + e = strchr(s, 0); + n = e - s; + if(n == 0) + goto next; + for(p = d;;p++){ + if((f = strchr(p, ' ')) == nil) + f = strchr(p, 0); + if(f - p == n && memcmp(s, p, n) == 0) + goto next; + p = f; + if(*p == 0) + break; + } + if(1 + n + p - d >= len) + break; + if(p > d) + *p++ = ' '; + p[n] = 0; + memmove(p, s, n); +next: + s = e; + if(*s == 0) + break; + } +} + static Ndbtuple* uniquent(Ndbtuple *t) { @@ -1792,148 +915,149 @@ uniquent(Ndbtuple *t) return t; } -/* get everything out of ndb */ +/* read configuration (except laddr) for myip from ndb */ void -ndbconfig(void) +ndb2conf(Ndb *db, uchar *myip) { - int nattr, nauth = 0, ndns = 0, nfs = 0, nntp = 0, ok; - char etheraddr[32]; - char *attrs[10]; - Ndb *db; + int nattr; + char *attrs[10], val[64]; + uchar ip[IPaddrlen]; Ndbtuple *t, *nt; - db = ndbopen(dbfile); + ipmove(conf.mask, defmask(conf.laddr)); + + memset(conf.gaddr, 0, sizeof(conf.gaddr)); + memset(conf.dns, 0, sizeof(conf.dns)); + memset(conf.ntp, 0, sizeof(conf.ntp)); + memset(conf.fs, 0, sizeof(conf.fs)); + memset(conf.auth, 0, sizeof(conf.auth)); + memset(conf.dnsdomain, 0, sizeof(conf.dnsdomain)); + if(db == nil) - sysfatal("can't open ndb: %r"); - if (!isether() || myetheraddr(conf.hwa, conf.dev) != 0) - sysfatal("can't read hardware address"); - sprint(etheraddr, "%E", conf.hwa); + return; + nattr = 0; - attrs[nattr++] = "ip"; attrs[nattr++] = "ipmask"; attrs[nattr++] = "ipgw"; - /* the @ triggers resolution to an IP address; see ndb(2) */ + attrs[nattr++] = "@dns"; attrs[nattr++] = "@ntp"; attrs[nattr++] = "@fs"; attrs[nattr++] = "@auth"; - attrs[nattr] = nil; - t = ndbipinfo(db, "ether", etheraddr, attrs, nattr); + + attrs[nattr++] = "dnsdomain"; + + snprint(val, sizeof(val), "%I", myip); + t = ndbipinfo(db, "ip", val, attrs, nattr); for(nt = t; nt != nil; nt = nt->entry) { - ok = 1; - if(strcmp(nt->attr, "ip") == 0) - ok = parseip(conf.laddr, uniquent(nt)->val); - else if(strcmp(nt->attr, "ipmask") == 0) - parseipmask(conf.mask, uniquent(nt)->val); /* could be -1 */ - else if(strcmp(nt->attr, "ipgw") == 0) - ok = parseip(conf.gaddr, uniquent(nt)->val); - else if(ndns < sizeof(conf.dns)/IPaddrlen && strcmp(nt->attr, "dns") == 0) - ok = parseip(conf.dns+IPaddrlen*ndns++, nt->val); - else if(nntp < sizeof(conf.ntp)/IPaddrlen && strcmp(nt->attr, "ntp") == 0) - ok = parseip(conf.ntp+IPaddrlen*nntp++, nt->val); - else if(nfs < sizeof(conf.fs)/IPaddrlen && strcmp(nt->attr, "fs") == 0) - ok = parseip(conf.fs+IPaddrlen*nfs++, nt->val); - else if(nauth < sizeof(conf.auth)/IPaddrlen && strcmp(nt->attr, "auth") == 0) - ok = parseip(conf.auth+IPaddrlen*nauth++, nt->val); - if(ok == -1) + if(strcmp(nt->attr, "dnsdomain") == 0) { + addnames(conf.dnsdomain, nt->val, sizeof(conf.dnsdomain)); + continue; + } + if(strcmp(nt->attr, "ipmask") == 0) { + nt = uniquent(nt); + parseipmask(conf.mask, nt->val); /* could be -1 */ + continue; + } + if(parseip(ip, nt->val) == -1) { fprint(2, "%s: bad %s address in ndb: %s\n", argv0, nt->attr, nt->val); + continue; + } + if(strcmp(nt->attr, "ipgw") == 0) { + nt = uniquent(nt); + ipmove(conf.gaddr, ip); + } else if(strcmp(nt->attr, "dns") == 0) { + addaddrs(conf.dns, sizeof(conf.dns), ip, IPaddrlen); + } else if(strcmp(nt->attr, "ntp") == 0) { + addaddrs(conf.ntp, sizeof(conf.ntp), ip, IPaddrlen); + } else if(strcmp(nt->attr, "fs") == 0) { + addaddrs(conf.fs, sizeof(conf.fs), ip, IPaddrlen); + } else if(strcmp(nt->attr, "auth") == 0) { + addaddrs(conf.auth, sizeof(conf.auth), ip, IPaddrlen); + } } ndbfree(t); - if(!validip(conf.laddr)) - sysfatal("address not found in ndb"); } -int -addoption(char *opt) +Ndb* +opendatabase(void) { - int i; - Option *o; + static Ndb *db; - if(opt == nil) - return -1; - for(o = option; o < &option[nelem(option)]; o++) - if(o->name && strcmp(opt, o->name) == 0){ - i = o - option; - if(memchr(requested, i, nrequested) == 0 && - nrequested < nelem(requested)) - requested[nrequested++] = i; - return 0; - } - return -1; + if(db != nil) + ndbclose(db); + db = ndbopen(dbfile); + return db; } -char* -optgetx(uchar *p, uchar opt) +/* add addresses for my ethernet address from ndb */ +static void +ndbconfig(void) { - int i, n; - ulong x; - char *s, *ns; - char str[256]; - uchar ip[IPaddrlen], ips[16*IPaddrlen], vec[256]; - Option *o; - - 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; + uchar ips[128*IPaddrlen]; + char etheraddr[32], *attr; + Ndbtuple *t, *nt; + Ndb *db; + int n, i; + + db = opendatabase(); + if(db == nil) + sysfatal("can't open ndb: %r"); + + 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; - - 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); + n = countaddrs(ips, sizeof(ips)); + if(n == 0) + sysfatal("no ip addresses found in ndb"); + + /* add link local address first, if not already done */ + if(!validip(conf.lladdr) && !findllip(conf.lladdr, ifc)){ + for(i = 0; i < n; i++){ + ipmove(conf.laddr, ips+i*IPaddrlen); + if(ISIPV6LINKLOCAL(conf.laddr)){ + ipv6auto = 0; + ipmove(conf.lladdr, conf.laddr); + ndb2conf(db, conf.laddr); + doadd(); + break; + } + } + if(ipv6auto){ + ipmove(conf.laddr, IPnoaddr); + doadd(); + } + } + + /* add v4 addresses and v6 if link local address is available */ + for(i = 0; i < n; i++){ + ipmove(conf.laddr, ips+i*IPaddrlen); + if(isv4(conf.laddr) + || validip(conf.lladdr) && ipcmp(conf.laddr, conf.lladdr) != 0){ + ndb2conf(db, conf.laddr); + doadd(); } - free(s); } } diff --git a/sys/src/cmd/ip/ipconfig/mkfile b/sys/src/cmd/ip/ipconfig/mkfile index d888e9a9b..cdeedb188 100644 --- a/sys/src/cmd/ip/ipconfig/mkfile +++ b/sys/src/cmd/ip/ipconfig/mkfile @@ -4,6 +4,7 @@ TARG=ipconfig\ OFILES=\ main.$O\ + dhcp.$O\ ipv6.$O\ ppp.$O\ diff --git a/sys/src/cmd/ip/ipconfig/ppp.c b/sys/src/cmd/ip/ipconfig/ppp.c index 82d5a5578..1a2ee0138 100644 --- a/sys/src/cmd/ip/ipconfig/ppp.c +++ b/sys/src/cmd/ip/ipconfig/ppp.c @@ -3,7 +3,6 @@ #include <ip.h> #include <bio.h> #include <ndb.h> -#include "../dhcp.h" #include "ipconfig.h" void |