xref: /plan9/sys/src/cmd/ip/ipconfig/main.c (revision 0400b64795cb7922fbea5587531527b381e1e588)
1 /*
2  * ipconfig - configure parameters of an ip stack
3  */
4 #include <u.h>
5 #include <libc.h>
6 #include <ip.h>
7 #include <bio.h>
8 #include <ndb.h>
9 #include "../dhcp.h"
10 #include "ipconfig.h"
11 
12 #define DEBUG if(debug)warning
13 
14 /* possible verbs */
15 enum
16 {
17 	/* commands */
18 	Vadd,
19 	Vremove,
20 	Vunbind,
21 	Vaddpref6,
22 	Vra6,
23 	/* media */
24 	Vether,
25 	Vgbe,
26 	Vppp,
27 	Vloopback,
28 	Vtorus,
29 	Vtree,
30 	Vpkt,
31 };
32 
33 enum
34 {
35 	Taddr,
36 	Taddrs,
37 	Tstr,
38 	Tbyte,
39 	Tulong,
40 	Tvec,
41 };
42 
43 typedef struct Option Option;
44 struct Option
45 {
46 	char	*name;
47 	int	type;
48 };
49 
50 /*
51  * I was too lazy to look up the types for each of these
52  * options.  If someone feels like it, please mail me a
53  * corrected array -- presotto
54  */
55 Option option[256] =
56 {
57 [OBmask]		{ "ipmask",		Taddr },
58 [OBtimeoff]		{ "timeoff",		Tulong },
59 [OBrouter]		{ "ipgw",		Taddrs },
60 [OBtimeserver]		{ "time",		Taddrs },
61 [OBnameserver]		{ "name",		Taddrs },
62 [OBdnserver]		{ "dns",		Taddrs },
63 [OBlogserver]		{ "log",		Taddrs },
64 [OBcookieserver]	{ "cookie",		Taddrs },
65 [OBlprserver]		{ "lpr",		Taddrs },
66 [OBimpressserver]	{ "impress",		Taddrs },
67 [OBrlserver]		{ "rl",			Taddrs },
68 [OBhostname]		{ "sys",		Tstr },
69 [OBbflen]		{ "bflen",		Tulong },
70 [OBdumpfile]		{ "dumpfile",		Tstr },
71 [OBdomainname]		{ "dom",		Tstr },
72 [OBswapserver]		{ "swap",		Taddrs },
73 [OBrootpath]		{ "rootpath",		Tstr },
74 [OBextpath]		{ "extpath",		Tstr },
75 [OBipforward]		{ "ipforward",		Taddrs },
76 [OBnonlocal]		{ "nonlocal",		Taddrs },
77 [OBpolicyfilter]	{ "policyfilter",	Taddrs },
78 [OBmaxdatagram]		{ "maxdatagram",	Tulong },
79 [OBttl]			{ "ttl",		Tulong },
80 [OBpathtimeout]		{ "pathtimeout",	Taddrs },
81 [OBpathplateau]		{ "pathplateau",	Taddrs },
82 [OBmtu]			{ "mtu",		Tulong },
83 [OBsubnetslocal]	{ "subnetslocal",	Taddrs },
84 [OBbaddr]		{ "baddr",		Taddrs },
85 [OBdiscovermask]	{ "discovermask",	Taddrs },
86 [OBsupplymask]		{ "supplymask",		Taddrs },
87 [OBdiscoverrouter]	{ "discoverrouter",	Taddrs },
88 [OBrsserver]		{ "rs",			Taddrs },
89 [OBstaticroutes]	{ "staticroutes",	Taddrs },
90 [OBtrailerencap]	{ "trailerencap",	Taddrs },
91 [OBarptimeout]		{ "arptimeout",		Tulong },
92 [OBetherencap]		{ "etherencap",		Taddrs },
93 [OBtcpttl]		{ "tcpttl",		Tulong },
94 [OBtcpka]		{ "tcpka",		Tulong },
95 [OBtcpkag]		{ "tcpkag",		Tulong },
96 [OBnisdomain]		{ "nisdomain",		Tstr },
97 [OBniserver]		{ "ni",			Taddrs },
98 [OBntpserver]		{ "ntp",		Taddrs },
99 [OBnetbiosns]		{ "netbiosns",		Taddrs },
100 [OBnetbiosdds]		{ "netbiosdds",		Taddrs },
101 [OBnetbiostype]		{ "netbiostype",	Taddrs },
102 [OBnetbiosscope]	{ "netbiosscope",	Taddrs },
103 [OBxfontserver]		{ "xfont",		Taddrs },
104 [OBxdispmanager]	{ "xdispmanager",	Taddrs },
105 [OBnisplusdomain]	{ "nisplusdomain",	Tstr },
106 [OBnisplusserver]	{ "nisplus",		Taddrs },
107 [OBhomeagent]		{ "homeagent",		Taddrs },
108 [OBsmtpserver]		{ "smtp",		Taddrs },
109 [OBpop3server]		{ "pop3",		Taddrs },
110 [OBnntpserver]		{ "nntp",		Taddrs },
111 [OBwwwserver]		{ "www",		Taddrs },
112 [OBfingerserver]	{ "finger",		Taddrs },
113 [OBircserver]		{ "irc",		Taddrs },
114 [OBstserver]		{ "st",			Taddrs },
115 [OBstdaserver]		{ "stdar",		Taddrs },
116 
117 [ODipaddr]		{ "ipaddr",		Taddr },
118 [ODlease]		{ "lease",		Tulong },
119 [ODoverload]		{ "overload",		Taddr },
120 [ODtype]		{ "type",		Tbyte },
121 [ODserverid]		{ "serverid",		Taddr },
122 [ODparams]		{ "params",		Tvec },
123 [ODmessage]		{ "message",		Tstr },
124 [ODmaxmsg]		{ "maxmsg",		Tulong },
125 [ODrenewaltime]		{ "renewaltime",	Tulong },
126 [ODrebindingtime]	{ "rebindingtime",	Tulong },
127 [ODvendorclass]		{ "vendorclass",	Tvec },
128 [ODclientid]		{ "clientid",		Tvec },
129 [ODtftpserver]		{ "tftp",		Taddr },
130 [ODbootfile]		{ "bootfile",		Tstr },
131 };
132 
133 uchar defrequested[] = {
134 	OBmask, OBrouter, OBdnserver, OBhostname, OBdomainname, OBntpserver,
135 };
136 
137 uchar	requested[256];
138 int	nrequested;
139 
140 int	Oflag;
141 int	beprimary = -1;
142 Conf	conf;
143 int	debug;
144 int	dodhcp;
145 int	dolog;
146 int	dondbconfig = 0;
147 int	dupl_disc = 1;		/* flag: V6 duplicate neighbor discovery */
148 Ctl	*firstctl, **ctll;
149 Ipifc	*ifc;
150 int	ipv6auto = 0;
151 int	myifc = -1;
152 char	*ndboptions;
153 int	nip;
154 int	noconfig;
155 int	nodhcpwatch;
156 char 	optmagic[4] = { 0x63, 0x82, 0x53, 0x63 };
157 int	plan9 = 1;
158 int	sendhostname;
159 
160 static char logfile[] = "ipconfig";
161 
162 char *verbs[] = {
163 [Vadd]		"add",
164 [Vremove]	"remove",
165 [Vunbind]	"unbind",
166 [Vether]	"ether",
167 [Vgbe]		"gbe",
168 [Vppp]		"ppp",
169 [Vloopback]	"loopback",
170 [Vaddpref6]	"add6",
171 [Vra6]		"ra6",
172 [Vtorus]	"torus",
173 [Vtree]		"tree",
174 [Vpkt]		"pkt",
175 };
176 
177 void	adddefroute(char*, uchar*);
178 int	addoption(char*);
179 void	binddevice(void);
180 void	bootprequest(void);
181 void	controldevice(void);
182 void	dhcpquery(int, int);
183 void	dhcprecv(void);
184 void	dhcpsend(int);
185 int	dhcptimer(void);
186 void	dhcpwatch(int);
187 void	doadd(int);
188 void	doremove(void);
189 void	dounbind(void);
190 int	getndb(void);
191 void	getoptions(uchar*);
192 int	ip4cfg(void);
193 int	ip6cfg(int a);
194 void	lookforip(char*);
195 void	mkclientid(void);
196 void	ndbconfig(void);
197 int	nipifcs(char*);
198 int	openlisten(void);
199 uchar*	optaddaddr(uchar*, int, uchar*);
200 uchar*	optaddbyte(uchar*, int, int);
201 uchar*	optaddstr(uchar*, int, char*);
202 uchar*	optadd(uchar*, int, void*, int);
203 uchar*	optaddulong(uchar*, int, ulong);
204 uchar*	optaddvec(uchar*, int, uchar*, int);
205 int	optgetaddrs(uchar*, int, uchar*, int);
206 int	optgetp9addrs(uchar*, int, uchar*, int);
207 int	optgetaddr(uchar*, int, uchar*);
208 int	optgetbyte(uchar*, int);
209 int	optgetstr(uchar*, int, char*, int);
210 uchar*	optget(uchar*, int, int*);
211 ulong	optgetulong(uchar*, int);
212 int	optgetvec(uchar*, int, uchar*, int);
213 char*	optgetx(uchar*, uchar);
214 Bootp*	parsebootp(uchar*, int);
215 int	parseoptions(uchar *p, int n);
216 int	parseverb(char*);
217 void	pppbinddev(void);
218 void	putndb(void);
219 void	tweakservers(void);
220 void	usage(void);
221 int	validip(uchar*);
222 void	writendb(char*, int, int);
223 
224 void
usage(void)225 usage(void)
226 {
227 	fprint(2, "usage: %s [-6dDGnNOpPruX][-b baud][-c ctl]* [-g gw]"
228 		"[-h host][-m mtu]\n"
229 		"\t[-x mtpt][-o dhcpopt] type dev [verb] [laddr [mask "
230 		"[raddr [fs [auth]]]]]\n", argv0);
231 	exits("usage");
232 }
233 
234 void
warning(char * fmt,...)235 warning(char *fmt, ...)
236 {
237 	char buf[1024];
238 	va_list arg;
239 
240 	va_start(arg, fmt);
241 	vseprint(buf, buf + sizeof buf, fmt, arg);
242 	va_end(arg);
243 	if (dolog)
244 		syslog(0, logfile, "%s", buf);
245 	else
246 		fprint(2, "%s: %s\n", argv0, buf);
247 }
248 
249 static void
parsenorm(int argc,char ** argv)250 parsenorm(int argc, char **argv)
251 {
252 	switch(argc){
253 	case 5:
254 		 if (parseip(conf.auth, argv[4]) == -1)
255 			usage();
256 		/* fall through */
257 	case 4:
258 		 if (parseip(conf.fs, argv[3]) == -1)
259 			usage();
260 		/* fall through */
261 	case 3:
262 		 if (parseip(conf.raddr, argv[2]) == -1)
263 			usage();
264 		/* fall through */
265 	case 2:
266 		/*
267 		 * can't test for parseipmask()==-1 cuz 255.255.255.255
268 		 * looks like that.
269 		 */
270 		if (strcmp(argv[1], "0") != 0)
271 			parseipmask(conf.mask, argv[1]);
272 		/* fall through */
273 	case 1:
274 		 if (parseip(conf.laddr, argv[0]) == -1)
275 			usage();
276 		/* fall through */
277 	case 0:
278 		break;
279 	default:
280 		usage();
281 	}
282 }
283 
284 static void
parse6pref(int argc,char ** argv)285 parse6pref(int argc, char **argv)
286 {
287 	switch(argc){
288 	case 6:
289 		conf.preflt = strtoul(argv[5], 0, 10);
290 		/* fall through */
291 	case 5:
292 		conf.validlt = strtoul(argv[4], 0, 10);
293 		/* fall through */
294 	case 4:
295 		conf.autoflag = (atoi(argv[3]) != 0);
296 		/* fall through */
297 	case 3:
298 		conf.onlink = (atoi(argv[2]) != 0);
299 		/* fall through */
300 	case 2:
301 		conf.prefixlen = atoi(argv[1]);
302 		/* fall through */
303 	case 1:
304 		if (parseip(conf.v6pref, argv[0]) == -1)
305 			sysfatal("bad address %s", argv[0]);
306 		break;
307 	}
308 	DEBUG("parse6pref: pref %I len %d", conf.v6pref, conf.prefixlen);
309 }
310 
311 /* parse router advertisement (keyword, value) pairs */
312 static void
parse6ra(int argc,char ** argv)313 parse6ra(int argc, char **argv)
314 {
315 	int i, argsleft;
316 	char *kw, *val;
317 
318 	if (argc % 2 != 0)
319 		usage();
320 
321 	i = 0;
322 	for (argsleft = argc; argsleft > 1; argsleft -= 2) {
323 		kw =  argv[i];
324 		val = argv[i+1];
325 		if (strcmp(kw, "recvra") == 0)
326 			conf.recvra = (atoi(val) != 0);
327 		else if (strcmp(kw, "sendra") == 0)
328 			conf.sendra = (atoi(val) != 0);
329 		else if (strcmp(kw, "mflag") == 0)
330 			conf.mflag = (atoi(val) != 0);
331 		else if (strcmp(kw, "oflag") == 0)
332 			conf.oflag = (atoi(val) != 0);
333 		else if (strcmp(kw, "maxraint") == 0)
334 			conf.maxraint = atoi(val);
335 		else if (strcmp(kw, "minraint") == 0)
336 			conf.minraint = atoi(val);
337 		else if (strcmp(kw, "linkmtu") == 0)
338 			conf.linkmtu = atoi(val);
339 		else if (strcmp(kw, "reachtime") == 0)
340 			conf.reachtime = atoi(val);
341 		else if (strcmp(kw, "rxmitra") == 0)
342 			conf.rxmitra = atoi(val);
343 		else if (strcmp(kw, "ttl") == 0)
344 			conf.ttl = atoi(val);
345 		else if (strcmp(kw, "routerlt") == 0)
346 			conf.routerlt = atoi(val);
347 		else {
348 			warning("bad ra6 keyword %s", kw);
349 			usage();
350 		}
351 		i += 2;
352 	}
353 
354 	/* consistency check */
355 	if (conf.maxraint < conf.minraint)
356 		sysfatal("maxraint %d < minraint %d",
357 			conf.maxraint, conf.minraint);
358 }
359 
360 static void
init(void)361 init(void)
362 {
363 	srand(truerand());
364 	fmtinstall('E', eipfmt);
365 	fmtinstall('I', eipfmt);
366 	fmtinstall('M', eipfmt);
367 	fmtinstall('V', eipfmt);
368  	nsec();			/* make sure time file is open before forking */
369 
370 	setnetmtpt(conf.mpoint, sizeof conf.mpoint, nil);
371 	conf.cputype = getenv("cputype");
372 	if(conf.cputype == nil)
373 		conf.cputype = "386";
374 
375 	ctll = &firstctl;
376 	v6paraminit(&conf);
377 
378 	/* init set of requested dhcp parameters with the default */
379 	nrequested = sizeof defrequested;
380 	memcpy(requested, defrequested, nrequested);
381 }
382 
383 static int
parseargs(int argc,char ** argv)384 parseargs(int argc, char **argv)
385 {
386 	char *p;
387 	int action, verb;
388 
389 	/* default to any host name we already have */
390 	if(*conf.hostname == 0){
391 		p = getenv("sysname");
392 		if(p == nil || *p == 0)
393 			p = sysname();
394 		if(p != nil)
395 			strncpy(conf.hostname, p, sizeof conf.hostname-1);
396 	}
397 
398 	/* defaults */
399 	conf.type = "ether";
400 	conf.dev = "/net/ether0";
401 	action = Vadd;
402 
403 	/* get optional medium and device */
404 	if (argc > 0){
405 		verb = parseverb(*argv);
406 		switch(verb){
407 		case Vether:
408 		case Vgbe:
409 		case Vppp:
410 		case Vloopback:
411 		case Vtorus:
412 		case Vtree:
413 		case Vpkt:
414 			conf.type = *argv++;
415 			argc--;
416 			if(argc > 0){
417 				conf.dev = *argv++;
418 				argc--;
419 			} else if(verb == Vppp)
420 				conf.dev = "/dev/eia0";
421 			break;
422 		}
423 	}
424 
425 	/* get optional verb */
426 	if (argc > 0){
427 		verb = parseverb(*argv);
428 		switch(verb){
429 		case Vether:
430 		case Vgbe:
431 		case Vppp:
432 		case Vloopback:
433 		case Vtorus:
434 		case Vtree:
435 		case Vpkt:
436 			sysfatal("medium %s already specified", conf.type);
437 		case Vadd:
438 		case Vremove:
439 		case Vunbind:
440 		case Vaddpref6:
441 		case Vra6:
442 			argv++;
443 			argc--;
444 			action = verb;
445 			break;
446 		}
447 	}
448 
449 	/* get verb-dependent arguments */
450 	switch (action) {
451 	case Vadd:
452 	case Vremove:
453 	case Vunbind:
454 		parsenorm(argc, argv);
455 		break;
456 	case Vaddpref6:
457 		parse6pref(argc, argv);
458 		break;
459 	case Vra6:
460 		parse6ra(argc, argv);
461 		break;
462 	}
463 	return action;
464 }
465 
466 void
main(int argc,char ** argv)467 main(int argc, char **argv)
468 {
469 	int retry, action;
470 	Ctl *cp;
471 
472 	init();
473 	retry = 0;
474 	ARGBEGIN {
475 	case '6': 			/* IPv6 auto config */
476 		ipv6auto = 1;
477 		break;
478 	case 'b':
479 		conf.baud = EARGF(usage());
480 		break;
481 	case 'c':
482 		cp = malloc(sizeof *cp);
483 		if(cp == nil)
484 			sysfatal("%r");
485 		*ctll = cp;
486 		ctll = &cp->next;
487 		cp->next = nil;
488 		cp->ctl = EARGF(usage());
489 		break;
490 	case 'd':
491 		dodhcp = 1;
492 		break;
493 	case 'D':
494 		debug = 1;
495 		break;
496 	case 'g':
497 		if (parseip(conf.gaddr, EARGF(usage())) == -1)
498 			usage();
499 		break;
500 	case 'G':
501 		plan9 = 0;
502 		break;
503 	case 'h':
504 		snprint(conf.hostname, sizeof conf.hostname, "%s",
505 			EARGF(usage()));
506 		sendhostname = 1;
507 		break;
508 	case 'm':
509 		conf.mtu = atoi(EARGF(usage()));
510 		break;
511 	case 'n':
512 		noconfig = 1;
513 		break;
514 	case 'N':
515 		dondbconfig = 1;
516 		break;
517 	case 'o':
518 		if(addoption(EARGF(usage())) < 0)
519 			usage();
520 		break;
521 	case 'O':
522 		Oflag = 1;
523 		break;
524 	case 'p':
525 		beprimary = 1;
526 		break;
527 	case 'P':
528 		beprimary = 0;
529 		break;
530 	case 'r':
531 		retry = 1;
532 		break;
533 	case 'u':		/* IPv6: duplicate neighbour disc. off */
534 		dupl_disc = 0;
535 		break;
536 	case 'x':
537 		setnetmtpt(conf.mpoint, sizeof conf.mpoint, EARGF(usage()));
538 		break;
539 	case 'X':
540 		nodhcpwatch = 1;
541 		break;
542 	default:
543 		usage();
544 	} ARGEND;
545 	argv0 = "ipconfig";		/* boot invokes us as tcp? */
546 
547 	action = parseargs(argc, argv);
548 	switch(action){
549 	case Vadd:
550 		doadd(retry);
551 		break;
552 	case Vremove:
553 		doremove();
554 		break;
555 	case Vunbind:
556 		dounbind();
557 		break;
558 	case Vaddpref6:
559 	case Vra6:
560 		doipv6(action);
561 		break;
562 	}
563 	exits(0);
564 }
565 
566 int
havendb(char * net)567 havendb(char *net)
568 {
569 	Dir *d;
570 	char buf[128];
571 
572 	snprint(buf, sizeof buf, "%s/ndb", net);
573 	if((d = dirstat(buf)) == nil)
574 		return 0;
575 	if(d->length == 0){
576 		free(d);
577 		return 0;
578 	}
579 	free(d);
580 	return 1;
581 }
582 
583 void
doadd(int retry)584 doadd(int retry)
585 {
586 	int tries, ppp;
587 
588 	ppp = strcmp(conf.type, "ppp") == 0;
589 
590 	/* get number of preexisting interfaces */
591 	nip = nipifcs(conf.mpoint);
592 	if(beprimary == -1 && (nip == 0 || !havendb(conf.mpoint)))
593 		beprimary = 1;
594 
595 	/* get ipifc into name space and condition device for ip */
596 	if(!noconfig){
597 		lookforip(conf.mpoint);
598 		controldevice();
599 		binddevice();
600 	}
601 
602 	if (ipv6auto && !ppp) {
603 		if (ip6cfg(ipv6auto) < 0)
604 			sysfatal("can't automatically start IPv6 on %s",
605 				conf.dev);
606 //		return;
607 	} else if (validip(conf.laddr) && !isv4(conf.laddr)) {
608 		if (ip6cfg(0) < 0)
609 			sysfatal("can't start IPv6 on %s, address %I",
610 				conf.dev, conf.laddr);
611 //		return;
612 	}
613 
614 	if(!validip(conf.laddr) && !ppp)
615 		if(dondbconfig)
616 			ndbconfig();
617 		else
618 			dodhcp = 1;
619 
620 	/* run dhcp if we need something */
621 	if(dodhcp){
622 		mkclientid();
623 		for(tries = 0; tries < 30; tries++){
624 			dhcpquery(!noconfig, Sselecting);
625 			if(conf.state == Sbound)
626 				break;
627 			sleep(1000);
628 		}
629 	}
630 
631 	if(!validip(conf.laddr))
632 		if(retry && dodhcp && !noconfig){
633 			warning("couldn't determine ip address, retrying");
634 			dhcpwatch(1);
635 			return;
636 		} else
637 			sysfatal("no success with DHCP");
638 
639 	if(!noconfig)
640 		if(ip4cfg() < 0)
641 			sysfatal("can't start ip");
642 		else if(dodhcp && conf.lease != Lforever)
643 			dhcpwatch(0);
644 
645 	/* leave everything we've learned somewhere other procs can find it */
646 	if(beprimary == 1){
647 		putndb();
648 		tweakservers();
649 	}
650 }
651 
652 void
doremove(void)653 doremove(void)
654 {
655 	char file[128];
656 	int cfd;
657 	Ipifc *nifc;
658 	Iplifc *lifc;
659 
660 	if(!validip(conf.laddr))
661 		sysfatal("remove requires an address");
662 	ifc = readipifc(conf.mpoint, ifc, -1);
663 	for(nifc = ifc; nifc != nil; nifc = nifc->next){
664 		if(strcmp(nifc->dev, conf.dev) != 0)
665 			continue;
666 		for(lifc = nifc->lifc; lifc != nil; lifc = lifc->next){
667 			if(ipcmp(conf.laddr, lifc->ip) != 0)
668 				continue;
669 			if (validip(conf.mask) &&
670 			    ipcmp(conf.mask, lifc->mask) != 0)
671 				continue;
672 			if (validip(conf.raddr) &&
673 			    ipcmp(conf.raddr, lifc->net) != 0)
674 				continue;
675 
676 			snprint(file, sizeof file, "%s/ipifc/%d/ctl",
677 				conf.mpoint, nifc->index);
678 			cfd = open(file, ORDWR);
679 			if(cfd < 0){
680 				warning("can't open %s: %r", conf.mpoint);
681 				continue;
682 			}
683 			if(fprint(cfd, "remove %I %M", lifc->ip, lifc->mask) < 0)
684 				warning("can't remove %I %M from %s: %r",
685 					lifc->ip, lifc->mask, file);
686 		}
687 	}
688 }
689 
690 void
dounbind(void)691 dounbind(void)
692 {
693 	Ipifc *nifc;
694 	char file[128];
695 	int cfd;
696 
697 	ifc = readipifc(conf.mpoint, ifc, -1);
698 	for(nifc = ifc; nifc != nil; nifc = nifc->next){
699 		if(strcmp(nifc->dev, conf.dev) == 0){
700 			snprint(file, sizeof file, "%s/ipifc/%d/ctl",
701 				conf.mpoint, nifc->index);
702 			cfd = open(file, ORDWR);
703 			if(cfd < 0){
704 				warning("can't open %s: %r", conf.mpoint);
705 				break;
706 			}
707 			if(fprint(cfd, "unbind") < 0)
708 				warning("can't unbind from %s: %r", file);
709 			break;
710 		}
711 	}
712 }
713 
714 /* set the default route */
715 void
adddefroute(char * mpoint,uchar * gaddr)716 adddefroute(char *mpoint, uchar *gaddr)
717 {
718 	char buf[256];
719 	int cfd;
720 
721 	sprint(buf, "%s/iproute", mpoint);
722 	cfd = open(buf, ORDWR);
723 	if(cfd < 0)
724 		return;
725 
726 	if(isv4(gaddr))
727 		fprint(cfd, "add 0 0 %I", gaddr);
728 	else
729 		fprint(cfd, "add :: /0 %I", gaddr);
730 	close(cfd);
731 }
732 
733 /* create a client id */
734 void
mkclientid(void)735 mkclientid(void)
736 {
737 	if(strcmp(conf.type, "ether") == 0 || strcmp(conf.type, "gbe") == 0)
738 		if(myetheraddr(conf.hwa, conf.dev) == 0){
739 			conf.hwalen = 6;
740 			conf.hwatype = 1;
741 			conf.cid[0] = conf.hwatype;
742 			memmove(&conf.cid[1], conf.hwa, conf.hwalen);
743 			conf.cidlen = conf.hwalen+1;
744 		} else {
745 			conf.hwatype = -1;
746 			snprint((char*)conf.cid, sizeof conf.cid,
747 				"plan9_%ld.%d", lrand(), getpid());
748 			conf.cidlen = strlen((char*)conf.cid);
749 		}
750 }
751 
752 /* bind ip into the namespace */
753 void
lookforip(char * net)754 lookforip(char *net)
755 {
756 	char proto[64];
757 
758 	snprint(proto, sizeof proto, "%s/ipifc", net);
759 	if(access(proto, 0) == 0)
760 		return;
761 	sysfatal("no ip stack bound onto %s", net);
762 }
763 
764 /* send some ctls to a device */
765 void
controldevice(void)766 controldevice(void)
767 {
768 	char ctlfile[256];
769 	int fd;
770 	Ctl *cp;
771 
772 	if (firstctl == nil ||
773 	    strcmp(conf.type, "ether") != 0 && strcmp(conf.type, "gbe") != 0)
774 		return;
775 
776 	snprint(ctlfile, sizeof ctlfile, "%s/clone", conf.dev);
777 	fd = open(ctlfile, ORDWR);
778 	if(fd < 0)
779 		sysfatal("can't open %s", ctlfile);
780 
781 	for(cp = firstctl; cp != nil; cp = cp->next){
782 		if(write(fd, cp->ctl, strlen(cp->ctl)) < 0)
783 			sysfatal("ctl message %s: %r", cp->ctl);
784 		seek(fd, 0, 0);
785 	}
786 //	close(fd);		/* or does it need to be left hanging? */
787 }
788 
789 /* bind an ip stack to a device, leave the control channel open */
790 void
binddevice(void)791 binddevice(void)
792 {
793 	char buf[256];
794 
795 	if(strcmp(conf.type, "ppp") == 0)
796 		pppbinddev();
797 	else if(myifc < 0){
798 		/* get a new ip interface */
799 		snprint(buf, sizeof buf, "%s/ipifc/clone", conf.mpoint);
800 		conf.cfd = open(buf, ORDWR);
801 		if(conf.cfd < 0)
802 			sysfatal("opening %s/ipifc/clone: %r", conf.mpoint);
803 
804 		/* specify medium as ethernet, bind the interface to it */
805 		if(fprint(conf.cfd, "bind %s %s", conf.type, conf.dev) < 0)
806 			sysfatal("%s: bind %s %s: %r", buf, conf.type, conf.dev);
807 	} else {
808 		/* open the old interface */
809 		snprint(buf, sizeof buf, "%s/ipifc/%d/ctl", conf.mpoint, myifc);
810 		conf.cfd = open(buf, ORDWR);
811 		if(conf.cfd < 0)
812 			sysfatal("open %s: %r", buf);
813 	}
814 
815 }
816 
817 /* add a logical interface to the ip stack */
818 int
ip4cfg(void)819 ip4cfg(void)
820 {
821 	char buf[256];
822 	int n;
823 
824 	if(!validip(conf.laddr))
825 		return -1;
826 
827 	n = sprint(buf, "add");
828 	n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
829 
830 	if(!validip(conf.mask))
831 		ipmove(conf.mask, defmask(conf.laddr));
832 	n += snprint(buf+n, sizeof buf-n, " %I", conf.mask);
833 
834 	if(validip(conf.raddr)){
835 		n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
836 		if(conf.mtu != 0)
837 			n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu);
838 	}
839 
840 	if(write(conf.cfd, buf, n) < 0){
841 		warning("write(%s): %r", buf);
842 		return -1;
843 	}
844 
845 	if(beprimary==1 && validip(conf.gaddr))
846 		adddefroute(conf.mpoint, conf.gaddr);
847 
848 	return 0;
849 }
850 
851 /* remove a logical interface to the ip stack */
852 void
ipunconfig(void)853 ipunconfig(void)
854 {
855 	char buf[256];
856 	int n;
857 
858 	if(!validip(conf.laddr))
859 		return;
860 	DEBUG("couldn't renew IP lease, releasing %I", conf.laddr);
861 	n = sprint(buf, "remove");
862 	n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
863 
864 	if(!validip(conf.mask))
865 		ipmove(conf.mask, defmask(conf.laddr));
866 	n += snprint(buf+n, sizeof buf-n, " %I", conf.mask);
867 
868 	write(conf.cfd, buf, n);
869 
870 	ipmove(conf.laddr, IPnoaddr);
871 	ipmove(conf.raddr, IPnoaddr);
872 	ipmove(conf.mask, IPnoaddr);
873 
874 	/* forget configuration info */
875 	if(beprimary==1)
876 		writendb("", 0, 0);
877 }
878 
879 void
ding(void *,char * msg)880 ding(void*, char *msg)
881 {
882 	if(strstr(msg, "alarm"))
883 		noted(NCONT);
884 	noted(NDFLT);
885 }
886 
887 void
dhcpquery(int needconfig,int startstate)888 dhcpquery(int needconfig, int startstate)
889 {
890 	if(needconfig)
891 		fprint(conf.cfd, "add %I %I", IPnoaddr, IPnoaddr);
892 
893 	conf.fd = openlisten();
894 	if(conf.fd < 0){
895 		conf.state = Sinit;
896 		return;
897 	}
898 	notify(ding);
899 
900 	/* try dhcp for 10 seconds */
901 	conf.xid = lrand();
902 	conf.starttime = time(0);
903 	conf.state = startstate;
904 	switch(startstate){
905 	case Sselecting:
906 		conf.offered = 0;
907 		dhcpsend(Discover);
908 		break;
909 	case Srenewing:
910 		dhcpsend(Request);
911 		break;
912 	default:
913 		sysfatal("internal error 0");
914 	}
915 	conf.resend = 0;
916 	conf.timeout = time(0) + 4;
917 
918 	while(conf.state != Sbound){
919 		dhcprecv();
920 		if(dhcptimer() < 0)
921 			break;
922 		if(time(0) - conf.starttime > 10)
923 			break;
924 	}
925 	close(conf.fd);
926 
927 	if(needconfig)
928 		fprint(conf.cfd, "remove %I %I", IPnoaddr, IPnoaddr);
929 
930 }
931 
932 enum {
933 	/*
934 	 * was an hour, needs to be less for the ARM/GS1 until the timer
935 	 * code has been cleaned up (pb).
936 	 */
937 	Maxsleep = 450,
938 };
939 
940 void
dhcpwatch(int needconfig)941 dhcpwatch(int needconfig)
942 {
943 	int secs, s;
944 	ulong t;
945 
946 	if(nodhcpwatch)
947 		return;
948 
949 	switch(rfork(RFPROC|RFFDG|RFNOWAIT|RFNOTEG)){
950 	default:
951 		return;
952 	case 0:
953 		break;
954 	}
955 
956 	dolog = 1;			/* log, don't print */
957 	procsetname("dhcpwatch");
958 	/* keep trying to renew the lease */
959 	for(;;){
960 		if(conf.lease == 0)
961 			secs = 5;
962 		else
963 			secs = conf.lease >> 1;
964 
965 		/* avoid overflows */
966 		for(s = secs; s > 0; s -= t){
967 			if(s > Maxsleep)
968 				t = Maxsleep;
969 			else
970 				t = s;
971 			sleep(t*1000);
972 		}
973 
974 		if(conf.lease > 0){
975 			/*
976 			 * during boot, the starttime can be bogus so avoid
977 			 * spurious ipunconfig's
978 			 */
979 			t = time(0) - conf.starttime;
980 			if(t > (3*secs)/2)
981 				t = secs;
982 			if(t >= conf.lease){
983 				conf.lease = 0;
984 				if(!noconfig){
985 					ipunconfig();
986 					needconfig = 1;
987 				}
988 			} else
989 				conf.lease -= t;
990 		}
991 		dhcpquery(needconfig, needconfig? Sselecting: Srenewing);
992 
993 		if(needconfig && conf.state == Sbound){
994 			if(ip4cfg() < 0)
995 				sysfatal("can't start ip: %r");
996 			needconfig = 0;
997 			/*
998 			 * leave everything we've learned somewhere that
999 			 * other procs can find it.
1000 			 */
1001 			if(beprimary==1){
1002 				putndb();
1003 				tweakservers();
1004 			}
1005 		}
1006 	}
1007 }
1008 
1009 int
dhcptimer(void)1010 dhcptimer(void)
1011 {
1012 	ulong now;
1013 
1014 	now = time(0);
1015 	if(now < conf.timeout)
1016 		return 0;
1017 
1018 	switch(conf.state) {
1019 	default:
1020 		sysfatal("dhcptimer: unknown state %d", conf.state);
1021 	case Sinit:
1022 	case Sbound:
1023 		break;
1024 	case Sselecting:
1025 	case Srequesting:
1026 	case Srebinding:
1027 		dhcpsend(conf.state == Sselecting? Discover: Request);
1028 		conf.timeout = now + 4;
1029 		if(++conf.resend > 5) {
1030 			conf.state = Sinit;
1031 			return -1;
1032 		}
1033 		break;
1034 	case Srenewing:
1035 		dhcpsend(Request);
1036 		conf.timeout = now + 1;
1037 		if(++conf.resend > 3) {
1038 			conf.state = Srebinding;
1039 			conf.resend = 0;
1040 		}
1041 		break;
1042 	}
1043 	return 0;
1044 }
1045 
1046 void
dhcpsend(int type)1047 dhcpsend(int type)
1048 {
1049 	Bootp bp;
1050 	uchar *p;
1051 	int n;
1052 	uchar vendor[64];
1053 	Udphdr *up = (Udphdr*)bp.udphdr;
1054 
1055 	memset(&bp, 0, sizeof bp);
1056 
1057 	hnputs(up->rport, 67);
1058 	bp.op = Bootrequest;
1059 	hnputl(bp.xid, conf.xid);
1060 	hnputs(bp.secs, time(0)-conf.starttime);
1061 	hnputs(bp.flags, 0);
1062 	memmove(bp.optmagic, optmagic, 4);
1063 	if(conf.hwatype >= 0 && conf.hwalen < sizeof bp.chaddr){
1064 		memmove(bp.chaddr, conf.hwa, conf.hwalen);
1065 		bp.hlen = conf.hwalen;
1066 		bp.htype = conf.hwatype;
1067 	}
1068 	p = bp.optdata;
1069 	p = optaddbyte(p, ODtype, type);
1070 	p = optadd(p, ODclientid, conf.cid, conf.cidlen);
1071 	switch(type) {
1072 	default:
1073 		sysfatal("dhcpsend: unknown message type: %d", type);
1074 	case Discover:
1075 		ipmove(up->raddr, IPv4bcast);	/* broadcast */
1076 		if(*conf.hostname && sendhostname)
1077 			p = optaddstr(p, OBhostname, conf.hostname);
1078 		if(plan9){
1079 			n = snprint((char*)vendor, sizeof vendor,
1080 				"plan9_%s", conf.cputype);
1081 			p = optaddvec(p, ODvendorclass, vendor, n);
1082 		}
1083 		p = optaddvec(p, ODparams, requested, nrequested);
1084 		if(validip(conf.laddr))
1085 			p = optaddaddr(p, ODipaddr, conf.laddr);
1086 		break;
1087 	case Request:
1088 		switch(conf.state){
1089 		case Srenewing:
1090 			ipmove(up->raddr, conf.server);
1091 			v6tov4(bp.ciaddr, conf.laddr);
1092 			break;
1093 		case Srebinding:
1094 			ipmove(up->raddr, IPv4bcast);	/* broadcast */
1095 			v6tov4(bp.ciaddr, conf.laddr);
1096 			break;
1097 		case Srequesting:
1098 			ipmove(up->raddr, IPv4bcast);	/* broadcast */
1099 			p = optaddaddr(p, ODipaddr, conf.laddr);
1100 			p = optaddaddr(p, ODserverid, conf.server);
1101 			break;
1102 		}
1103 		p = optaddulong(p, ODlease, conf.offered);
1104 		if(plan9){
1105 			n = snprint((char*)vendor, sizeof vendor,
1106 				"plan9_%s", conf.cputype);
1107 			p = optaddvec(p, ODvendorclass, vendor, n);
1108 		}
1109 		p = optaddvec(p, ODparams, requested, nrequested);
1110 		if(*conf.hostname && sendhostname)
1111 			p = optaddstr(p, OBhostname, conf.hostname);
1112 		break;
1113 	case Release:
1114 		ipmove(up->raddr, conf.server);
1115 		v6tov4(bp.ciaddr, conf.laddr);
1116 		p = optaddaddr(p, ODipaddr, conf.laddr);
1117 		p = optaddaddr(p, ODserverid, conf.server);
1118 		break;
1119 	}
1120 
1121 	*p++ = OBend;
1122 
1123 	n = p - (uchar*)&bp;
1124 	USED(n);
1125 
1126 	/*
1127 	 *  We use a maximum size DHCP packet to survive the
1128 	 *  All_Aboard NAT package from Internet Share.  It
1129 	 *  always replies to DHCP requests with a packet of the
1130 	 *  same size, so if the request is too short the reply
1131 	 *  is truncated.
1132 	 */
1133 	if(write(conf.fd, &bp, sizeof bp) != sizeof bp)
1134 		warning("dhcpsend: write failed: %r");
1135 }
1136 
1137 void
dhcprecv(void)1138 dhcprecv(void)
1139 {
1140 	int i, n, type;
1141 	ulong lease;
1142 	char err[ERRMAX];
1143 	uchar buf[8000], vopts[256], taddr[IPaddrlen];
1144 	Bootp *bp;
1145 
1146 	memset(buf, 0, sizeof buf);
1147 	alarm(1000);
1148 	n = read(conf.fd, buf, sizeof buf);
1149 	alarm(0);
1150 
1151 	if(n < 0){
1152 		rerrstr(err, sizeof err);
1153 		if(strstr(err, "interrupt") == nil)
1154 			warning("dhcprecv: bad read: %s", err);
1155 		else
1156 			DEBUG("dhcprecv: read timed out");
1157 		return;
1158 	}
1159 	if(n == 0){
1160 		warning("dhcprecv: zero-length packet read");
1161 		return;
1162 	}
1163 
1164 	bp = parsebootp(buf, n);
1165 	if(bp == 0) {
1166 		DEBUG("parsebootp failed: dropping packet");
1167 		return;
1168 	}
1169 
1170 	type = optgetbyte(bp->optdata, ODtype);
1171 	switch(type) {
1172 	default:
1173 		warning("dhcprecv: unknown type: %d", type);
1174 		break;
1175 	case Offer:
1176 		DEBUG("got offer from %V ", bp->siaddr);
1177 		if(conf.state != Sselecting){
1178 //			DEBUG("");
1179 			break;
1180 		}
1181 		lease = optgetulong(bp->optdata, ODlease);
1182 		if(lease == 0){
1183 			/*
1184 			 * The All_Aboard NAT package from Internet Share
1185 			 * doesn't give a lease time, so we have to assume one.
1186 			 */
1187 			warning("Offer with %lud lease, using %d", lease, MinLease);
1188 			lease = MinLease;
1189 		}
1190 		DEBUG("lease=%lud ", lease);
1191 		if(!optgetaddr(bp->optdata, ODserverid, conf.server)) {
1192 			warning("Offer from server with invalid serverid");
1193 			break;
1194 		}
1195 
1196 		v4tov6(conf.laddr, bp->yiaddr);
1197 		memmove(conf.sname, bp->sname, sizeof conf.sname);
1198 		conf.sname[sizeof conf.sname-1] = 0;
1199 		DEBUG("server=%I sname=%s", conf.server, conf.sname);
1200 		conf.offered = lease;
1201 		conf.state = Srequesting;
1202 		dhcpsend(Request);
1203 		conf.resend = 0;
1204 		conf.timeout = time(0) + 4;
1205 		break;
1206 	case Ack:
1207 		DEBUG("got ack from %V ", bp->siaddr);
1208 		if (conf.state != Srequesting && conf.state != Srenewing &&
1209 		    conf.state != Srebinding)
1210 			break;
1211 
1212 		/* ignore a bad lease */
1213 		lease = optgetulong(bp->optdata, ODlease);
1214 		if(lease == 0){
1215 			/*
1216 			 * The All_Aboard NAT package from Internet Share
1217 			 * doesn't give a lease time, so we have to assume one.
1218 			 */
1219 			warning("Ack with %lud lease, using %d", lease, MinLease);
1220 			lease = MinLease;
1221 		}
1222 		DEBUG("lease=%lud ", lease);
1223 
1224 		/* address and mask */
1225 		if(!validip(conf.laddr) || !Oflag)
1226 			v4tov6(conf.laddr, bp->yiaddr);
1227 		if(!validip(conf.mask) || !Oflag){
1228 			if(!optgetaddr(bp->optdata, OBmask, conf.mask))
1229 				ipmove(conf.mask, IPnoaddr);
1230 		}
1231 		DEBUG("ipaddr=%I ipmask=%M ", conf.laddr, conf.mask);
1232 
1233 		/*
1234 		 * get a router address either from the router option
1235 		 * or from the router that forwarded the dhcp packet
1236 		 */
1237 		if(validip(conf.gaddr) && Oflag) {
1238 			DEBUG("ipgw=%I ", conf.gaddr);
1239 		} else if(optgetaddr(bp->optdata, OBrouter, conf.gaddr)){
1240 			DEBUG("ipgw=%I ", conf.gaddr);
1241 		} else if(memcmp(bp->giaddr, IPnoaddr+IPv4off, IPv4addrlen)!=0){
1242 			v4tov6(conf.gaddr, bp->giaddr);
1243 			DEBUG("giaddr=%I ", conf.gaddr);
1244 		}
1245 
1246 		/* get dns servers */
1247 		memset(conf.dns, 0, sizeof conf.dns);
1248 		n = optgetaddrs(bp->optdata, OBdnserver, conf.dns,
1249 			sizeof conf.dns/IPaddrlen);
1250 		for(i = 0; i < n; i++)
1251 			DEBUG("dns=%I ", conf.dns + i*IPaddrlen);
1252 
1253 		/* get ntp servers */
1254 		memset(conf.ntp, 0, sizeof conf.ntp);
1255 		n = optgetaddrs(bp->optdata, OBntpserver, conf.ntp,
1256 			sizeof conf.ntp/IPaddrlen);
1257 		for(i = 0; i < n; i++)
1258 			DEBUG("ntp=%I ", conf.ntp + i*IPaddrlen);
1259 
1260 		/* get names */
1261 		optgetstr(bp->optdata, OBhostname,
1262 			conf.hostname, sizeof conf.hostname);
1263 		optgetstr(bp->optdata, OBdomainname,
1264 			conf.domainname, sizeof conf.domainname);
1265 
1266 		/* get anything else we asked for */
1267 		getoptions(bp->optdata);
1268 
1269 		/* get plan9-specific options */
1270 		n = optgetvec(bp->optdata, OBvendorinfo, vopts, sizeof vopts-1);
1271 		if(n > 0 && parseoptions(vopts, n) == 0){
1272 			if(validip(conf.fs) && Oflag)
1273 				n = 1;
1274 			else {
1275 				n = optgetp9addrs(vopts, OP9fs, conf.fs, 2);
1276 				if (n == 0)
1277 					n = optgetaddrs(vopts, OP9fsv4,
1278 						conf.fs, 2);
1279 			}
1280 			for(i = 0; i < n; i++)
1281 				DEBUG("fs=%I ", conf.fs + i*IPaddrlen);
1282 
1283 			if(validip(conf.auth) && Oflag)
1284 				n = 1;
1285 			else {
1286 				n = optgetp9addrs(vopts, OP9auth, conf.auth, 2);
1287 				if (n == 0)
1288 					n = optgetaddrs(vopts, OP9authv4,
1289 						conf.auth, 2);
1290 			}
1291 			for(i = 0; i < n; i++)
1292 				DEBUG("auth=%I ", conf.auth + i*IPaddrlen);
1293 
1294 			n = optgetp9addrs(vopts, OP9ipaddr, taddr, 1);
1295 			if (n > 0)
1296 				memmove(conf.laddr, taddr, IPaddrlen);
1297 			n = optgetp9addrs(vopts, OP9ipmask, taddr, 1);
1298 			if (n > 0)
1299 				memmove(conf.mask, taddr, IPaddrlen);
1300 			n = optgetp9addrs(vopts, OP9ipgw, taddr, 1);
1301 			if (n > 0)
1302 				memmove(conf.gaddr, taddr, IPaddrlen);
1303 			DEBUG("new ipaddr=%I new ipmask=%M new ipgw=%I",
1304 				conf.laddr, conf.mask, conf.gaddr);
1305 		}
1306 		conf.lease = lease;
1307 		conf.state = Sbound;
1308 		DEBUG("server=%I sname=%s", conf.server, conf.sname);
1309 		break;
1310 	case Nak:
1311 		conf.state = Sinit;
1312 		warning("recved dhcpnak on %s", conf.mpoint);
1313 		break;
1314 	}
1315 }
1316 
1317 /* return pseudo-random integer in range low...(hi-1) */
1318 ulong
randint(ulong low,ulong hi)1319 randint(ulong low, ulong hi)
1320 {
1321 	if (hi < low)
1322 		return low;
1323 	return low + nrand(hi - low);
1324 }
1325 
1326 long
jitter(void)1327 jitter(void)		/* compute small pseudo-random delay in ms */
1328 {
1329 	return randint(0, 10*1000);
1330 }
1331 
1332 int
openlisten(void)1333 openlisten(void)
1334 {
1335 	int n, fd, cfd;
1336 	char data[128], devdir[40];
1337 
1338 	if (validip(conf.laddr) &&
1339 	    (conf.state == Srenewing || conf.state == Srebinding))
1340 		sprint(data, "%s/udp!%I!68", conf.mpoint, conf.laddr);
1341 	else
1342 		sprint(data, "%s/udp!*!68", conf.mpoint);
1343 	for (n = 0; (cfd = announce(data, devdir)) < 0; n++) {
1344 		if(!noconfig)
1345 			sysfatal("can't announce for dhcp: %r");
1346 
1347 		/* might be another client - wait and try again */
1348 		warning("can't announce %s: %r", data);
1349 		sleep(jitter());
1350 		if(n > 10)
1351 			return -1;
1352 	}
1353 
1354 	if(fprint(cfd, "headers") < 0)
1355 		sysfatal("can't set header mode: %r");
1356 
1357 	sprint(data, "%s/data", devdir);
1358 	fd = open(data, ORDWR);
1359 	if(fd < 0)
1360 		sysfatal("open %s: %r", data);
1361 	close(cfd);
1362 	return fd;
1363 }
1364 
1365 uchar*
optadd(uchar * p,int op,void * d,int n)1366 optadd(uchar *p, int op, void *d, int n)
1367 {
1368 	p[0] = op;
1369 	p[1] = n;
1370 	memmove(p+2, d, n);
1371 	return p+n+2;
1372 }
1373 
1374 uchar*
optaddbyte(uchar * p,int op,int b)1375 optaddbyte(uchar *p, int op, int b)
1376 {
1377 	p[0] = op;
1378 	p[1] = 1;
1379 	p[2] = b;
1380 	return p+3;
1381 }
1382 
1383 uchar*
optaddulong(uchar * p,int op,ulong x)1384 optaddulong(uchar *p, int op, ulong x)
1385 {
1386 	p[0] = op;
1387 	p[1] = 4;
1388 	hnputl(p+2, x);
1389 	return p+6;
1390 }
1391 
1392 uchar *
optaddaddr(uchar * p,int op,uchar * ip)1393 optaddaddr(uchar *p, int op, uchar *ip)
1394 {
1395 	p[0] = op;
1396 	p[1] = 4;
1397 	v6tov4(p+2, ip);
1398 	return p+6;
1399 }
1400 
1401 /* add dhcp option op with value v of length n to dhcp option array p */
1402 uchar *
optaddvec(uchar * p,int op,uchar * v,int n)1403 optaddvec(uchar *p, int op, uchar *v, int n)
1404 {
1405 	p[0] = op;
1406 	p[1] = n;
1407 	memmove(p+2, v, n);
1408 	return p+2+n;
1409 }
1410 
1411 uchar *
optaddstr(uchar * p,int op,char * v)1412 optaddstr(uchar *p, int op, char *v)
1413 {
1414 	int n;
1415 
1416 	n = strlen(v)+1;	/* microsoft leaves on the NUL, so we do too */
1417 	p[0] = op;
1418 	p[1] = n;
1419 	memmove(p+2, v, n);
1420 	return p+2+n;
1421 }
1422 
1423 /*
1424  * parse p, looking for option `op'.  if non-nil, np points to minimum length.
1425  * return nil if option is too small, else ptr to opt, and
1426  * store actual length via np if non-nil.
1427  */
1428 uchar*
optget(uchar * p,int op,int * np)1429 optget(uchar *p, int op, int *np)
1430 {
1431 	int len, code;
1432 
1433 	while ((code = *p++) != OBend) {
1434 		if(code == OBpad)
1435 			continue;
1436 		len = *p++;
1437 		if(code != op) {
1438 			p += len;
1439 			continue;
1440 		}
1441 		if(np != nil){
1442 			if(*np > len) {
1443 				return 0;
1444 			}
1445 			*np = len;
1446 		}
1447 		return p;
1448 	}
1449 	return 0;
1450 }
1451 
1452 int
optgetbyte(uchar * p,int op)1453 optgetbyte(uchar *p, int op)
1454 {
1455 	int len;
1456 
1457 	len = 1;
1458 	p = optget(p, op, &len);
1459 	if(p == nil)
1460 		return 0;
1461 	return *p;
1462 }
1463 
1464 ulong
optgetulong(uchar * p,int op)1465 optgetulong(uchar *p, int op)
1466 {
1467 	int len;
1468 
1469 	len = 4;
1470 	p = optget(p, op, &len);
1471 	if(p == nil)
1472 		return 0;
1473 	return nhgetl(p);
1474 }
1475 
1476 int
optgetaddr(uchar * p,int op,uchar * ip)1477 optgetaddr(uchar *p, int op, uchar *ip)
1478 {
1479 	int len;
1480 
1481 	len = 4;
1482 	p = optget(p, op, &len);
1483 	if(p == nil)
1484 		return 0;
1485 	v4tov6(ip, p);
1486 	return 1;
1487 }
1488 
1489 /* expect at most n addresses; ip[] only has room for that many */
1490 int
optgetaddrs(uchar * p,int op,uchar * ip,int n)1491 optgetaddrs(uchar *p, int op, uchar *ip, int n)
1492 {
1493 	int len, i;
1494 
1495 	len = 4;
1496 	p = optget(p, op, &len);
1497 	if(p == nil)
1498 		return 0;
1499 	len /= IPv4addrlen;
1500 	if(len > n)
1501 		len = n;
1502 	for(i = 0; i < len; i++)
1503 		v4tov6(&ip[i*IPaddrlen], &p[i*IPv4addrlen]);
1504 	return i;
1505 }
1506 
1507 /* expect at most n addresses; ip[] only has room for that many */
1508 int
optgetp9addrs(uchar * ap,int op,uchar * ip,int n)1509 optgetp9addrs(uchar *ap, int op, uchar *ip, int n)
1510 {
1511 	int len, i, slen, addrs;
1512 	char *p;
1513 
1514 	len = 1;			/* minimum bytes needed */
1515 	p = (char *)optget(ap, op, &len);
1516 	if(p == nil)
1517 		return 0;
1518 	addrs = *p++;			/* first byte is address count */
1519 	for (i = 0; i < n  && i < addrs && len > 0; i++) {
1520 		slen = strlen(p) + 1;
1521 		if (parseip(&ip[i*IPaddrlen], p) == -1)
1522 			fprint(2, "%s: bad address %s\n", argv0, p);
1523 		DEBUG("got plan 9 option %d addr %I (%s)",
1524 			op, &ip[i*IPaddrlen], p);
1525 		p += slen;
1526 		len -= slen;
1527 	}
1528 	return addrs;
1529 }
1530 
1531 int
optgetvec(uchar * p,int op,uchar * v,int n)1532 optgetvec(uchar *p, int op, uchar *v, int n)
1533 {
1534 	int len;
1535 
1536 	len = 1;
1537 	p = optget(p, op, &len);
1538 	if(p == nil)
1539 		return 0;
1540 	if(len > n)
1541 		len = n;
1542 	memmove(v, p, len);
1543 	return len;
1544 }
1545 
1546 int
optgetstr(uchar * p,int op,char * s,int n)1547 optgetstr(uchar *p, int op, char *s, int n)
1548 {
1549 	int len;
1550 
1551 	len = 1;
1552 	p = optget(p, op, &len);
1553 	if(p == nil)
1554 		return 0;
1555 	if(len >= n)
1556 		len = n-1;
1557 	memmove(s, p, len);
1558 	s[len] = 0;
1559 	return len;
1560 }
1561 
1562 /*
1563  * sanity check options area
1564  * 	- options don't overflow packet
1565  * 	- options end with an OBend
1566  */
1567 int
parseoptions(uchar * p,int n)1568 parseoptions(uchar *p, int n)
1569 {
1570 	int code, len, nin = n;
1571 
1572 	while (n > 0) {
1573 		code = *p++;
1574 		n--;
1575 		if(code == OBend)
1576 			return 0;
1577 		if(code == OBpad)
1578 			continue;
1579 		if(n == 0) {
1580 			warning("parseoptions: bad option: 0x%ux: truncated: "
1581 				"opt length = %d", code, nin);
1582 			return -1;
1583 		}
1584 
1585 		len = *p++;
1586 		n--;
1587 		DEBUG("parseoptions: %s(%d) len %d, bytes left %d",
1588 			option[code].name, code, len, n);
1589 		if(len > n) {
1590 			warning("parseoptions: bad option: 0x%ux: %d > %d: "
1591 				"opt length = %d", code, len, n, nin);
1592 			return -1;
1593 		}
1594 		p += len;
1595 		n -= len;
1596 	}
1597 
1598 	/* make sure packet ends with an OBend after all the optget code */
1599 	*p = OBend;
1600 	return 0;
1601 }
1602 
1603 /*
1604  * sanity check received packet:
1605  * 	- magic is dhcp magic
1606  * 	- options don't overflow packet
1607  */
1608 Bootp *
parsebootp(uchar * p,int n)1609 parsebootp(uchar *p, int n)
1610 {
1611 	Bootp *bp;
1612 
1613 	bp = (Bootp*)p;
1614 	if(n < bp->optmagic - p) {
1615 		warning("parsebootp: short bootp packet; with options, "
1616 			"need %d bytes, got %d", bp->optmagic - p, n);
1617 		return nil;
1618 	}
1619 
1620 	if(conf.xid != nhgetl(bp->xid))		/* not meant for us */
1621 		return nil;
1622 
1623 	if(bp->op != Bootreply) {
1624 		warning("parsebootp: bad op %d", bp->op);
1625 		return nil;
1626 	}
1627 
1628 	n -= bp->optmagic - p;
1629 	p = bp->optmagic;
1630 
1631 	if(n < 4) {
1632 		warning("parsebootp: no option data");
1633 		return nil;
1634 	}
1635 	if(memcmp(optmagic, p, 4) != 0) {
1636 		warning("parsebootp: bad opt magic %ux %ux %ux %ux",
1637 			p[0], p[1], p[2], p[3]);
1638 		return nil;
1639 	}
1640 	p += 4;
1641 	n -= 4;
1642 	DEBUG("parsebootp: new packet");
1643 	if(parseoptions(p, n) < 0)
1644 		return nil;
1645 	return bp;
1646 }
1647 
1648 /* write out an ndb entry */
1649 void
writendb(char * s,int n,int append)1650 writendb(char *s, int n, int append)
1651 {
1652 	char file[64];
1653 	int fd;
1654 
1655 	snprint(file, sizeof file, "%s/ndb", conf.mpoint);
1656 	if(append){
1657 		fd = open(file, OWRITE);
1658 		seek(fd, 0, 2);
1659 	} else
1660 		fd = open(file, OWRITE|OTRUNC);
1661 	write(fd, s, n);
1662 	close(fd);
1663 }
1664 
1665 /* put server addresses into the ndb entry */
1666 char*
putaddrs(char * p,char * e,char * attr,uchar * a,int len)1667 putaddrs(char *p, char *e, char *attr, uchar *a, int len)
1668 {
1669 	int i;
1670 
1671 	for(i = 0; i < len && validip(a); i += IPaddrlen, a += IPaddrlen)
1672 		p = seprint(p, e, "%s=%I\n", attr, a);
1673 	return p;
1674 }
1675 
1676 /* make an ndb entry and put it into /net/ndb for the servers to see */
1677 void
putndb(void)1678 putndb(void)
1679 {
1680 	int append;
1681 	char buf[1024];
1682 	char *p, *e, *np;
1683 
1684 	p = buf;
1685 	e = buf + sizeof buf;
1686 	if(getndb() == 0)
1687 		append = 1;
1688 	else {
1689 		append = 0;
1690 		p = seprint(p, e, "ip=%I ipmask=%M ipgw=%I\n",
1691 			conf.laddr, conf.mask, conf.gaddr);
1692 	}
1693 	if(np = strchr(conf.hostname, '.')){
1694 		if(*conf.domainname == 0)
1695 			strcpy(conf.domainname, np+1);
1696 		*np = 0;
1697 	}
1698 	if(*conf.hostname)
1699 		p = seprint(p, e, "\tsys=%s\n", conf.hostname);
1700 	if(*conf.domainname)
1701 		p = seprint(p, e, "\tdom=%s.%s\n",
1702 			conf.hostname, conf.domainname);
1703 	if(validip(conf.fs))
1704 		p = putaddrs(p, e, "\tfs", conf.fs, sizeof conf.fs);
1705 	if(validip(conf.auth))
1706 		p = putaddrs(p, e, "\tauth", conf.auth, sizeof conf.auth);
1707 	if(validip(conf.dns))
1708 		p = putaddrs(p, e, "\tdns", conf.dns, sizeof conf.dns);
1709 	if(validip(conf.ntp))
1710 		p = putaddrs(p, e, "\tntp", conf.ntp, sizeof conf.ntp);
1711 	if(ndboptions)
1712 		p = seprint(p, e, "%s\n", ndboptions);
1713 	if(p > buf)
1714 		writendb(buf, p-buf, append);
1715 }
1716 
1717 /* get an ndb entry someone else wrote */
1718 int
getndb(void)1719 getndb(void)
1720 {
1721 	char buf[1024];
1722 	int fd, n;
1723 	char *p;
1724 
1725 	snprint(buf, sizeof buf, "%s/ndb", conf.mpoint);
1726 	fd = open(buf, OREAD);
1727 	n = read(fd, buf, sizeof buf-1);
1728 	close(fd);
1729 	if(n <= 0)
1730 		return -1;
1731 	buf[n] = 0;
1732 	p = strstr(buf, "ip=");
1733 	if(p == nil)
1734 		return -1;
1735 	if (parseip(conf.laddr, p+3) == -1)
1736 		fprint(2, "%s: bad address %s\n", argv0, p+3);
1737 	return 0;
1738 }
1739 
1740 /* tell a server to refresh */
1741 void
tweakserver(char * server)1742 tweakserver(char *server)
1743 {
1744 	int fd;
1745 	char file[64];
1746 
1747 	snprint(file, sizeof file, "%s/%s", conf.mpoint, server);
1748 	fd = open(file, ORDWR);
1749 	if(fd < 0)
1750 		return;
1751 	fprint(fd, "refresh");
1752 	close(fd);
1753 }
1754 
1755 /* tell all servers to refresh their information */
1756 void
tweakservers(void)1757 tweakservers(void)
1758 {
1759 	tweakserver("dns");
1760 	tweakserver("cs");
1761 }
1762 
1763 /* return number of networks */
1764 int
nipifcs(char * net)1765 nipifcs(char *net)
1766 {
1767 	int n;
1768 	Ipifc *nifc;
1769 	Iplifc *lifc;
1770 
1771 	n = 0;
1772 	ifc = readipifc(net, ifc, -1);
1773 	for(nifc = ifc; nifc != nil; nifc = nifc->next){
1774 		/*
1775 		 * ignore loopback devices when trying to
1776 		 * figure out if we're the primary interface.
1777 		 */
1778 		if(strcmp(nifc->dev, "/dev/null") != 0)
1779 			for(lifc = nifc->lifc; lifc != nil; lifc = lifc->next)
1780 				if(validip(lifc->ip)){
1781 					n++;
1782 					break;
1783 				}
1784 		if(strcmp(nifc->dev, conf.dev) == 0)
1785 			myifc = nifc->index;
1786 	}
1787 	return n;
1788 }
1789 
1790 /* return true if this is a valid v4 address */
1791 int
validip(uchar * addr)1792 validip(uchar *addr)
1793 {
1794 	return ipcmp(addr, IPnoaddr) != 0 && ipcmp(addr, v4prefix) != 0;
1795 }
1796 
1797 /* look for an action */
1798 int
parseverb(char * name)1799 parseverb(char *name)
1800 {
1801 	int i;
1802 
1803 	for(i = 0; i < nelem(verbs); i++)
1804 		if(verbs[i] != nil && strcmp(name, verbs[i]) == 0)
1805 			return i;
1806 	return -1;
1807 }
1808 
1809 /* get everything out of ndb */
1810 void
ndbconfig(void)1811 ndbconfig(void)
1812 {
1813 	int nattr, nauth = 0, ndns = 0, nfs = 0, ok;
1814 	char etheraddr[32];
1815 	char *attrs[10];
1816 	Ndb *db;
1817 	Ndbtuple *t, *nt;
1818 
1819 	db = ndbopen(0);
1820 	if(db == nil)
1821 		sysfatal("can't open ndb: %r");
1822 	if (strcmp(conf.type, "ether") != 0 && strcmp(conf.type, "gbe") != 0 ||
1823 	    myetheraddr(conf.hwa, conf.dev) != 0)
1824 		sysfatal("can't read hardware address");
1825 	sprint(etheraddr, "%E", conf.hwa);
1826 	nattr = 0;
1827 	attrs[nattr++] = "ip";
1828 	attrs[nattr++] = "ipmask";
1829 	attrs[nattr++] = "ipgw";
1830 	/* the @ triggers resolution to an IP address; see ndb(2) */
1831 	attrs[nattr++] = "@dns";
1832 	attrs[nattr++] = "@ntp";
1833 	attrs[nattr++] = "@fs";
1834 	attrs[nattr++] = "@auth";
1835 	attrs[nattr] = nil;
1836 	t = ndbipinfo(db, "ether", etheraddr, attrs, nattr);
1837 	for(nt = t; nt != nil; nt = nt->entry) {
1838 		ok = 1;
1839 		if(strcmp(nt->attr, "ip") == 0)
1840 			ok = parseip(conf.laddr, nt->val);
1841 		else if(strcmp(nt->attr, "ipmask") == 0)
1842 			parseipmask(conf.mask, nt->val);  /* could be -1 */
1843 		else if(strcmp(nt->attr, "ipgw") == 0)
1844 			ok = parseip(conf.gaddr, nt->val);
1845 		else if(ndns < 2 && strcmp(nt->attr, "dns") == 0)
1846 			ok = parseip(conf.dns+IPaddrlen*ndns, nt->val);
1847 		else if(strcmp(nt->attr, "ntp") == 0)
1848 			ok = parseip(conf.ntp, nt->val);
1849 		else if(nfs < 2 && strcmp(nt->attr, "fs") == 0)
1850 			ok = parseip(conf.fs+IPaddrlen*nfs, nt->val);
1851 		else if(nauth < 2 && strcmp(nt->attr, "auth") == 0)
1852 			ok = parseip(conf.auth+IPaddrlen*nauth, nt->val);
1853 		if (!ok)
1854 			fprint(2, "%s: bad %s address in ndb: %s\n", argv0,
1855 				nt->attr, nt->val);
1856 	}
1857 	ndbfree(t);
1858 	if(!validip(conf.laddr))
1859 		sysfatal("address not found in ndb");
1860 }
1861 
1862 int
addoption(char * opt)1863 addoption(char *opt)
1864 {
1865 	int i;
1866 	Option *o;
1867 
1868 	if(opt == nil)
1869 		return -1;
1870 	for(o = option; o < &option[nelem(option)]; o++)
1871 		if(o->name && strcmp(opt, o->name) == 0){
1872 			i = o - option;
1873 			if(memchr(requested, i, nrequested) == 0 &&
1874 			    nrequested < nelem(requested))
1875 				requested[nrequested++] = i;
1876 			return 0;
1877 		}
1878 	return -1;
1879 }
1880 
1881 char*
optgetx(uchar * p,uchar opt)1882 optgetx(uchar *p, uchar opt)
1883 {
1884 	int i, n;
1885 	ulong x;
1886 	char *s, *ns;
1887 	char str[256];
1888 	uchar ip[IPaddrlen], ips[16*IPaddrlen], vec[256];
1889 	Option *o;
1890 
1891 	o = &option[opt];
1892 	if(o->name == nil)
1893 		return nil;
1894 
1895 	s = nil;
1896 	switch(o->type){
1897 	case Taddr:
1898 		if(optgetaddr(p, opt, ip))
1899 			s = smprint("%s=%I", o->name, ip);
1900 		break;
1901 	case Taddrs:
1902 		n = optgetaddrs(p, opt, ips, 16);
1903 		if(n > 0)
1904 			s = smprint("%s=%I", o->name, ips);
1905 		for(i = 1; i < n; i++){
1906 			ns = smprint("%s %s=%I", s, o->name, &ips[i*IPaddrlen]);
1907 			free(s);
1908 			s = ns;
1909 		}
1910 		break;
1911 	case Tulong:
1912 		x = optgetulong(p, opt);
1913 		if(x != 0)
1914 			s = smprint("%s=%lud", o->name, x);
1915 		break;
1916 	case Tbyte:
1917 		x = optgetbyte(p, opt);
1918 		if(x != 0)
1919 			s = smprint("%s=%lud", o->name, x);
1920 		break;
1921 	case Tstr:
1922 		if(optgetstr(p, opt, str, sizeof str))
1923 			s = smprint("%s=%s", o->name, str);
1924 		break;
1925 	case Tvec:
1926 		n = optgetvec(p, opt, vec, sizeof vec);
1927 		if(n > 0)
1928 			/* what's %H?  it's not installed */
1929 			s = smprint("%s=%.*H", o->name, n, vec);
1930 		break;
1931 	}
1932 	return s;
1933 }
1934 
1935 void
getoptions(uchar * p)1936 getoptions(uchar *p)
1937 {
1938 	int i;
1939 	char *s, *t;
1940 
1941 	for(i = nelem(defrequested); i < nrequested; i++){
1942 		s = optgetx(p, requested[i]);
1943 		if(s != nil)
1944 			DEBUG("%s ", s);
1945 		if(ndboptions == nil)
1946 			ndboptions = smprint("\t%s", s);
1947 		else{
1948 			t = ndboptions;
1949 			ndboptions = smprint("\t%s%s", s, ndboptions);
1950 			free(t);
1951 		}
1952 		free(s);
1953 	}
1954 }
1955