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.
This commit is contained in:
cinap_lenrek 2018-05-01 23:32:28 +02:00
parent 8e53fe132e
commit 190c40c9ff
7 changed files with 1997 additions and 1756 deletions

View file

@ -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,

View file

@ -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;
}

View file

@ -1,3 +1,23 @@
/* possible verbs */
enum
{
/* commands */
Vadd,
Vremove,
Vunbind,
Vaddpref6,
Vra6,
/* media */
Vether,
Vgbe,
Vppp,
Vloopback,
Vtorus,
Vtree,
Vpkt,
};
typedef struct Conf Conf;
typedef struct Ctl Ctl;
@ -22,7 +42,7 @@ struct Conf
uchar laddr[IPaddrlen];
uchar mask[IPaddrlen];
uchar raddr[IPaddrlen];
uchar dns[2*IPaddrlen];
uchar dns[8*IPaddrlen];
uchar fs[2*IPaddrlen];
uchar auth[2*IPaddrlen];
uchar ntp[2*IPaddrlen];
@ -60,12 +80,15 @@ struct Conf
int ttl; /* default 0 (unspecified) */
/* prefix related */
uchar lladdr[IPaddrlen];
uchar v6pref[IPaddrlen];
int prefixlen;
uchar onlink; /* flag: address is `on-link' */
uchar autoflag; /* flag: autonomous */
ulong validlt; /* valid lifetime (seconds) */
ulong preflt; /* preferred lifetime (seconds) */
char dnsdomain[256];
};
struct Ctl
@ -74,152 +97,60 @@ struct Ctl
char *ctl;
};
extern Ctl *firstctl, **ctll;
extern Conf conf;
extern int noconfig;
extern int ipv6auto;
extern int debug;
extern int dodhcp;
extern int dolog;
extern int plan9;
extern int dupl_disc;
extern Conf conf;
extern int myifc;
extern char *vs;
extern int beprimary;
extern int noconfig;
extern int debug;
extern int dolog;
extern int plan9;
extern int Oflag;
extern int dupl_disc;
extern int nodhcpwatch;
extern int sendhostname;
extern char *ndboptions;
void usage(void);
int ip4cfg(void);
void ipunconfig(void);
void adddefroute(uchar*, uchar*, uchar*, uchar*);
void removedefroute(int, uchar*, uchar*);
void doadd(int);
void doremove(void);
void dounbind(void);
int isether(void);
long jitter(void);
void mklladdr(void);
void procsetname(char *fmt, ...);
void catch(void*, char*);
int countaddrs(uchar *a, int len);
void addaddrs(uchar *to, int nto, uchar *from, int nfrom);
void addnames(char *d, char *s, int len);
Ndb* opendatabase(void);
void ndb2conf(Ndb *db, uchar *ip);
void putndb(void);
void refresh(void);
ulong randint(ulong low, ulong hi);
int validip(uchar*);
void warning(char *fmt, ...);
#define DEBUG if(debug)warning
/*
* DHCP
*/
void dhcpinit(void);
void dhcpquery(int, int);
void dhcpwatch(int);
int addoption(char*);
/*
* IPv6
*/
void doipv6(int);
void v6paraminit(Conf*);
typedef struct Headers Headers;
typedef struct Ip4hdr Ip4hdr;
typedef struct Lladdropt Lladdropt;
typedef struct Mtuopt Mtuopt;
typedef struct Prefixopt Prefixopt;
typedef struct Routeradv Routeradv;
typedef struct Routersol Routersol;
enum {
IsRouter = 1,
IsHostRecv = 2,
IsHostNoRecv = 3,
MAClen = 6,
IPv4 = 4,
IPv6 = 6,
Defmtu = 1400,
IP_HOPBYHOP = 0,
ICMPv4 = 1,
IP_IGMPPROTO = 2,
IP_TCPPROTO = 6,
IP_UDPPROTO = 17,
IP_ILPROTO = 40,
IP_v6ROUTE = 43,
IP_v6FRAG = 44,
IP_IPsecESP = 50,
IP_IPsecAH = 51,
IP_v6NOMORE = 59,
ICMP6_RS = 133,
ICMP6_RA = 134,
IP_IN_IP = 41,
};
enum {
MFMASK = 1 << 7,
OCMASK = 1 << 6,
OLMASK = 1 << 7,
AFMASK = 1 << 6,
RFMASK = 1 << 5,
};
enum {
MAXTTL = 255,
D64HLEN = IPV6HDR_LEN - IPV4HDR_LEN,
IP_MAX = 32*1024,
};
struct Headers {
uchar dst[IPaddrlen];
uchar src[IPaddrlen];
};
struct Routersol {
uchar vcf[4]; /* version:4, traffic class:8, flow label:20 */
uchar ploadlen[2]; /* payload length: packet length - 40 */
uchar proto; /* next header type */
uchar ttl; /* hop limit */
uchar src[IPaddrlen];
uchar dst[IPaddrlen];
uchar type;
uchar code;
uchar cksum[2];
uchar res[4];
};
struct Routeradv {
uchar vcf[4]; /* version:4, traffic class:8, flow label:20 */
uchar ploadlen[2]; /* payload length: packet length - 40 */
uchar proto; /* next header type */
uchar ttl; /* hop limit */
uchar src[IPaddrlen];
uchar dst[IPaddrlen];
uchar type;
uchar code;
uchar cksum[2];
uchar cttl;
uchar mor;
uchar routerlt[2];
uchar rchbltime[4];
uchar rxmtimer[4];
};
struct Lladdropt {
uchar type;
uchar len;
uchar lladdr[MAClen];
};
struct Prefixopt {
uchar type;
uchar len;
uchar plen;
uchar lar;
uchar validlt[4];
uchar preflt[4];
uchar reserv[4];
uchar pref[IPaddrlen];
};
struct Mtuopt {
uchar type;
uchar len;
uchar reserv[2];
uchar mtu[4];
};
void parse6pref(int argc, char **argv);
void parse6ra(int argc, char **argv);
void doipv6(int);
void ea2lla(uchar *lla, uchar *ea);
void ipv62smcast(uchar *smcast, uchar *a);
int findllip(uchar *ip, Ipifc *ifc);
int ip6cfg(void);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,7 @@ TARG=ipconfig\
OFILES=\
main.$O\
dhcp.$O\
ipv6.$O\
ppp.$O\

View file

@ -3,7 +3,6 @@
#include <ip.h>
#include <bio.h>
#include <ndb.h>
#include "../dhcp.h"
#include "ipconfig.h"
void