xref: /freebsd/sbin/dhclient/dhclient.c (revision 884a2a699669ec61e2366e3e358342dbc94be24a)
1 /*	$OpenBSD: dhclient.c,v 1.63 2005/02/06 17:10:13 krw Exp $	*/
2 
3 /*
4  * Copyright 2004 Henning Brauer <henning@openbsd.org>
5  * Copyright (c) 1995, 1996, 1997, 1998, 1999
6  * The Internet Software Consortium.    All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of The Internet Software Consortium nor the names
18  *    of its contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
22  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
26  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * This software has been written for the Internet Software Consortium
36  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
37  * Enterprises.  To learn more about the Internet Software Consortium,
38  * see ``http://www.vix.com/isc''.  To learn more about Vixie
39  * Enterprises, see ``http://www.vix.com''.
40  *
41  * This client was substantially modified and enhanced by Elliot Poger
42  * for use on Linux while he was working on the MosquitoNet project at
43  * Stanford.
44  *
45  * The current version owes much to Elliot's Linux enhancements, but
46  * was substantially reorganized and partially rewritten by Ted Lemon
47  * so as to use the same networking framework that the Internet Software
48  * Consortium DHCP server uses.   Much system-specific configuration code
49  * was moved into a shell script so that as support for more operating
50  * systems is added, it will not be necessary to port and maintain
51  * system-specific configuration code to these operating systems - instead,
52  * the shell script can invoke the native tools to accomplish the same
53  * purpose.
54  */
55 
56 #include <sys/cdefs.h>
57 __FBSDID("$FreeBSD$");
58 
59 #include "dhcpd.h"
60 #include "privsep.h"
61 
62 #include <net80211/ieee80211_freebsd.h>
63 
64 #ifndef _PATH_VAREMPTY
65 #define	_PATH_VAREMPTY	"/var/empty"
66 #endif
67 
68 #define	PERIOD 0x2e
69 #define	hyphenchar(c) ((c) == 0x2d)
70 #define	bslashchar(c) ((c) == 0x5c)
71 #define	periodchar(c) ((c) == PERIOD)
72 #define	asterchar(c) ((c) == 0x2a)
73 #define	alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
74 	    ((c) >= 0x61 && (c) <= 0x7a))
75 #define	digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
76 #define	whitechar(c) ((c) == ' ' || (c) == '\t')
77 
78 #define	borderchar(c) (alphachar(c) || digitchar(c))
79 #define	middlechar(c) (borderchar(c) || hyphenchar(c))
80 #define	domainchar(c) ((c) > 0x20 && (c) < 0x7f)
81 
82 #define	CLIENT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
83 
84 time_t cur_time;
85 time_t default_lease_time = 43200; /* 12 hours... */
86 
87 char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
88 char *path_dhclient_db = NULL;
89 
90 int log_perror = 1;
91 int privfd;
92 int nullfd = -1;
93 
94 struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
95 struct in_addr inaddr_any;
96 struct sockaddr_in sockaddr_broadcast;
97 
98 /*
99  * ASSERT_STATE() does nothing now; it used to be
100  * assert (state_is == state_shouldbe).
101  */
102 #define ASSERT_STATE(state_is, state_shouldbe) {}
103 
104 #define TIME_MAX 2147483647
105 
106 int		log_priority;
107 int		no_daemon;
108 int		unknown_ok = 1;
109 int		routefd;
110 
111 struct interface_info	*ifi;
112 
113 int		 findproto(char *, int);
114 struct sockaddr	*get_ifa(char *, int);
115 void		 routehandler(struct protocol *);
116 void		 usage(void);
117 int		 check_option(struct client_lease *l, int option);
118 int		 check_classless_option(unsigned char *data, int len);
119 int		 ipv4addrs(char * buf);
120 int		 res_hnok(const char *dn);
121 int		 check_search(const char *srch);
122 char		*option_as_string(unsigned int code, unsigned char *data, int len);
123 int		 fork_privchld(int, int);
124 
125 #define	ROUNDUP(a) \
126 	    ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
127 #define	ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
128 
129 static time_t	scripttime;
130 
131 int
132 findproto(char *cp, int n)
133 {
134 	struct sockaddr *sa;
135 	int i;
136 
137 	if (n == 0)
138 		return -1;
139 	for (i = 1; i; i <<= 1) {
140 		if (i & n) {
141 			sa = (struct sockaddr *)cp;
142 			switch (i) {
143 			case RTA_IFA:
144 			case RTA_DST:
145 			case RTA_GATEWAY:
146 			case RTA_NETMASK:
147 				if (sa->sa_family == AF_INET)
148 					return AF_INET;
149 				if (sa->sa_family == AF_INET6)
150 					return AF_INET6;
151 				break;
152 			case RTA_IFP:
153 				break;
154 			}
155 			ADVANCE(cp, sa);
156 		}
157 	}
158 	return (-1);
159 }
160 
161 struct sockaddr *
162 get_ifa(char *cp, int n)
163 {
164 	struct sockaddr *sa;
165 	int i;
166 
167 	if (n == 0)
168 		return (NULL);
169 	for (i = 1; i; i <<= 1)
170 		if (i & n) {
171 			sa = (struct sockaddr *)cp;
172 			if (i == RTA_IFA)
173 				return (sa);
174 			ADVANCE(cp, sa);
175 		}
176 
177 	return (NULL);
178 }
179 
180 struct iaddr defaddr = { 4 };
181 uint8_t curbssid[6];
182 
183 static void
184 disassoc(void *arg)
185 {
186 	struct interface_info *ifi = arg;
187 
188 	/*
189 	 * Clear existing state.
190 	 */
191 	if (ifi->client->active != NULL) {
192 		script_init("EXPIRE", NULL);
193 		script_write_params("old_",
194 		    ifi->client->active);
195 		if (ifi->client->alias)
196 			script_write_params("alias_",
197 				ifi->client->alias);
198 		script_go();
199 	}
200 	ifi->client->state = S_INIT;
201 }
202 
203 /* ARGSUSED */
204 void
205 routehandler(struct protocol *p)
206 {
207 	char msg[2048], *addr;
208 	struct rt_msghdr *rtm;
209 	struct if_msghdr *ifm;
210 	struct ifa_msghdr *ifam;
211 	struct if_announcemsghdr *ifan;
212 	struct ieee80211_join_event *jev;
213 	struct client_lease *l;
214 	time_t t = time(NULL);
215 	struct sockaddr *sa;
216 	struct iaddr a;
217 	ssize_t n;
218 
219 	n = read(routefd, &msg, sizeof(msg));
220 	rtm = (struct rt_msghdr *)msg;
221 	if (n < sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen ||
222 	    rtm->rtm_version != RTM_VERSION)
223 		return;
224 
225 	switch (rtm->rtm_type) {
226 	case RTM_NEWADDR:
227 	case RTM_DELADDR:
228 		ifam = (struct ifa_msghdr *)rtm;
229 
230 		if (ifam->ifam_index != ifi->index)
231 			break;
232 		if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
233 			break;
234 		if (scripttime == 0 || t < scripttime + 10)
235 			break;
236 
237 		sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs);
238 		if (sa == NULL)
239 			break;
240 
241 		if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf))
242 			error("king bula sez: len mismatch");
243 		memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len);
244 		if (addr_eq(a, defaddr))
245 			break;
246 
247 		for (l = ifi->client->active; l != NULL; l = l->next)
248 			if (addr_eq(a, l->address))
249 				break;
250 
251 		if (l == NULL)	/* added/deleted addr is not the one we set */
252 			break;
253 
254 		addr = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
255 		if (rtm->rtm_type == RTM_NEWADDR)  {
256 			/*
257 			 * XXX: If someone other than us adds our address,
258 			 * should we assume they are taking over from us,
259 			 * delete the lease record, and exit without modifying
260 			 * the interface?
261 			 */
262 			warning("My address (%s) was re-added", addr);
263 		} else {
264 			warning("My address (%s) was deleted, dhclient exiting",
265 			    addr);
266 			goto die;
267 		}
268 		break;
269 	case RTM_IFINFO:
270 		ifm = (struct if_msghdr *)rtm;
271 		if (ifm->ifm_index != ifi->index)
272 			break;
273 		if ((rtm->rtm_flags & RTF_UP) == 0) {
274 			warning("Interface %s is down, dhclient exiting",
275 			    ifi->name);
276 			goto die;
277 		}
278 		break;
279 	case RTM_IFANNOUNCE:
280 		ifan = (struct if_announcemsghdr *)rtm;
281 		if (ifan->ifan_what == IFAN_DEPARTURE &&
282 		    ifan->ifan_index == ifi->index) {
283 			warning("Interface %s is gone, dhclient exiting",
284 			    ifi->name);
285 			goto die;
286 		}
287 		break;
288 	case RTM_IEEE80211:
289 		ifan = (struct if_announcemsghdr *)rtm;
290 		if (ifan->ifan_index != ifi->index)
291 			break;
292 		switch (ifan->ifan_what) {
293 		case RTM_IEEE80211_ASSOC:
294 		case RTM_IEEE80211_REASSOC:
295 			/*
296 			 * Use assoc/reassoc event to kick state machine
297 			 * in case we roam.  Otherwise fall back to the
298 			 * normal state machine just like a wired network.
299 			 */
300 			jev = (struct ieee80211_join_event *) &ifan[1];
301 			if (memcmp(curbssid, jev->iev_addr, 6)) {
302 				disassoc(ifi);
303 				state_reboot(ifi);
304 			}
305 			memcpy(curbssid, jev->iev_addr, 6);
306 			break;
307 		}
308 		break;
309 	default:
310 		break;
311 	}
312 	return;
313 
314 die:
315 	script_init("FAIL", NULL);
316 	if (ifi->client->alias)
317 		script_write_params("alias_", ifi->client->alias);
318 	script_go();
319 	exit(1);
320 }
321 
322 int
323 main(int argc, char *argv[])
324 {
325 	extern char		*__progname;
326 	int			 ch, fd, quiet = 0, i = 0;
327 	int			 pipe_fd[2];
328 	int			 immediate_daemon = 0;
329 	struct passwd		*pw;
330 
331 	/* Initially, log errors to stderr as well as to syslogd. */
332 	openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
333 	setlogmask(LOG_UPTO(LOG_DEBUG));
334 
335 	while ((ch = getopt(argc, argv, "bc:dl:qu")) != -1)
336 		switch (ch) {
337 		case 'b':
338 			immediate_daemon = 1;
339 			break;
340 		case 'c':
341 			path_dhclient_conf = optarg;
342 			break;
343 		case 'd':
344 			no_daemon = 1;
345 			break;
346 		case 'l':
347 			path_dhclient_db = optarg;
348 			break;
349 		case 'q':
350 			quiet = 1;
351 			break;
352 		case 'u':
353 			unknown_ok = 0;
354 			break;
355 		default:
356 			usage();
357 		}
358 
359 	argc -= optind;
360 	argv += optind;
361 
362 	if (argc != 1)
363 		usage();
364 
365 	if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL)
366 		error("calloc");
367 	if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
368 		error("Interface name too long");
369 	if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s",
370 	    _PATH_DHCLIENT_DB, ifi->name) == -1)
371 		error("asprintf");
372 
373 	if (quiet)
374 		log_perror = 0;
375 
376 	tzset();
377 	time(&cur_time);
378 
379 	memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
380 	sockaddr_broadcast.sin_family = AF_INET;
381 	sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
382 	sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
383 	sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast);
384 	inaddr_any.s_addr = INADDR_ANY;
385 
386 	read_client_conf();
387 
388 	if (!interface_link_status(ifi->name)) {
389 		fprintf(stderr, "%s: no link ...", ifi->name);
390 		fflush(stderr);
391 		sleep(1);
392 		while (!interface_link_status(ifi->name)) {
393 			fprintf(stderr, ".");
394 			fflush(stderr);
395 			if (++i > 10) {
396 				fprintf(stderr, " giving up\n");
397 				exit(1);
398 			}
399 			sleep(1);
400 		}
401 		fprintf(stderr, " got link\n");
402 	}
403 
404 	if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
405 		error("cannot open %s: %m", _PATH_DEVNULL);
406 
407 	if ((pw = getpwnam("_dhcp")) == NULL) {
408 		warning("no such user: _dhcp, falling back to \"nobody\"");
409 		if ((pw = getpwnam("nobody")) == NULL)
410 			error("no such user: nobody");
411 	}
412 
413 	if (pipe(pipe_fd) == -1)
414 		error("pipe");
415 
416 	fork_privchld(pipe_fd[0], pipe_fd[1]);
417 
418 	close(pipe_fd[0]);
419 	privfd = pipe_fd[1];
420 
421 	if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
422 		error("can't open and lock %s: %m", path_dhclient_db);
423 	read_client_leases();
424 	rewrite_client_leases();
425 	close(fd);
426 
427 	priv_script_init("PREINIT", NULL);
428 	if (ifi->client->alias)
429 		priv_script_write_params("alias_", ifi->client->alias);
430 	priv_script_go();
431 
432 	if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
433 		add_protocol("AF_ROUTE", routefd, routehandler, ifi);
434 
435 	/* set up the interface */
436 	discover_interfaces(ifi);
437 
438 	if (chroot(_PATH_VAREMPTY) == -1)
439 		error("chroot");
440 	if (chdir("/") == -1)
441 		error("chdir(\"/\")");
442 
443 	if (setgroups(1, &pw->pw_gid) ||
444 	    setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
445 	    seteuid(pw->pw_uid) || setuid(pw->pw_uid))
446 		error("can't drop privileges: %m");
447 
448 	endpwent();
449 
450 	setproctitle("%s", ifi->name);
451 
452 	if (immediate_daemon)
453 		go_daemon();
454 
455 	ifi->client->state = S_INIT;
456 	state_reboot(ifi);
457 
458 	bootp_packet_handler = do_packet;
459 
460 	dispatch();
461 
462 	/* not reached */
463 	return (0);
464 }
465 
466 void
467 usage(void)
468 {
469 	extern char	*__progname;
470 
471 	fprintf(stderr, "usage: %s [-bdqu] ", __progname);
472 	fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
473 	exit(1);
474 }
475 
476 /*
477  * Individual States:
478  *
479  * Each routine is called from the dhclient_state_machine() in one of
480  * these conditions:
481  * -> entering INIT state
482  * -> recvpacket_flag == 0: timeout in this state
483  * -> otherwise: received a packet in this state
484  *
485  * Return conditions as handled by dhclient_state_machine():
486  * Returns 1, sendpacket_flag = 1: send packet, reset timer.
487  * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
488  * Returns 0: finish the nap which was interrupted for no good reason.
489  *
490  * Several per-interface variables are used to keep track of the process:
491  *   active_lease: the lease that is being used on the interface
492  *                 (null pointer if not configured yet).
493  *   offered_leases: leases corresponding to DHCPOFFER messages that have
494  *                   been sent to us by DHCP servers.
495  *   acked_leases: leases corresponding to DHCPACK messages that have been
496  *                 sent to us by DHCP servers.
497  *   sendpacket: DHCP packet we're trying to send.
498  *   destination: IP address to send sendpacket to
499  * In addition, there are several relevant per-lease variables.
500  *   T1_expiry, T2_expiry, lease_expiry: lease milestones
501  * In the active lease, these control the process of renewing the lease;
502  * In leases on the acked_leases list, this simply determines when we
503  * can no longer legitimately use the lease.
504  */
505 
506 void
507 state_reboot(void *ipp)
508 {
509 	struct interface_info *ip = ipp;
510 
511 	/* If we don't remember an active lease, go straight to INIT. */
512 	if (!ip->client->active || ip->client->active->is_bootp) {
513 		state_init(ip);
514 		return;
515 	}
516 
517 	/* We are in the rebooting state. */
518 	ip->client->state = S_REBOOTING;
519 
520 	/* make_request doesn't initialize xid because it normally comes
521 	   from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
522 	   so pick an xid now. */
523 	ip->client->xid = arc4random();
524 
525 	/* Make a DHCPREQUEST packet, and set appropriate per-interface
526 	   flags. */
527 	make_request(ip, ip->client->active);
528 	ip->client->destination = iaddr_broadcast;
529 	ip->client->first_sending = cur_time;
530 	ip->client->interval = ip->client->config->initial_interval;
531 
532 	/* Zap the medium list... */
533 	ip->client->medium = NULL;
534 
535 	/* Send out the first DHCPREQUEST packet. */
536 	send_request(ip);
537 }
538 
539 /*
540  * Called when a lease has completely expired and we've
541  * been unable to renew it.
542  */
543 void
544 state_init(void *ipp)
545 {
546 	struct interface_info *ip = ipp;
547 
548 	ASSERT_STATE(state, S_INIT);
549 
550 	/* Make a DHCPDISCOVER packet, and set appropriate per-interface
551 	   flags. */
552 	make_discover(ip, ip->client->active);
553 	ip->client->xid = ip->client->packet.xid;
554 	ip->client->destination = iaddr_broadcast;
555 	ip->client->state = S_SELECTING;
556 	ip->client->first_sending = cur_time;
557 	ip->client->interval = ip->client->config->initial_interval;
558 
559 	/* Add an immediate timeout to cause the first DHCPDISCOVER packet
560 	   to go out. */
561 	send_discover(ip);
562 }
563 
564 /*
565  * state_selecting is called when one or more DHCPOFFER packets
566  * have been received and a configurable period of time has passed.
567  */
568 void
569 state_selecting(void *ipp)
570 {
571 	struct interface_info *ip = ipp;
572 	struct client_lease *lp, *next, *picked;
573 
574 	ASSERT_STATE(state, S_SELECTING);
575 
576 	/* Cancel state_selecting and send_discover timeouts, since either
577 	   one could have got us here. */
578 	cancel_timeout(state_selecting, ip);
579 	cancel_timeout(send_discover, ip);
580 
581 	/* We have received one or more DHCPOFFER packets.   Currently,
582 	   the only criterion by which we judge leases is whether or
583 	   not we get a response when we arp for them. */
584 	picked = NULL;
585 	for (lp = ip->client->offered_leases; lp; lp = next) {
586 		next = lp->next;
587 
588 		/* Check to see if we got an ARPREPLY for the address
589 		   in this particular lease. */
590 		if (!picked) {
591 			script_init("ARPCHECK", lp->medium);
592 			script_write_params("check_", lp);
593 
594 			/* If the ARPCHECK code detects another
595 			   machine using the offered address, it exits
596 			   nonzero.  We need to send a DHCPDECLINE and
597 			   toss the lease. */
598 			if (script_go()) {
599 				make_decline(ip, lp);
600 				send_decline(ip);
601 				goto freeit;
602 			}
603 			picked = lp;
604 			picked->next = NULL;
605 		} else {
606 freeit:
607 			free_client_lease(lp);
608 		}
609 	}
610 	ip->client->offered_leases = NULL;
611 
612 	/* If we just tossed all the leases we were offered, go back
613 	   to square one. */
614 	if (!picked) {
615 		ip->client->state = S_INIT;
616 		state_init(ip);
617 		return;
618 	}
619 
620 	/* If it was a BOOTREPLY, we can just take the address right now. */
621 	if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
622 		ip->client->new = picked;
623 
624 		/* Make up some lease expiry times
625 		   XXX these should be configurable. */
626 		ip->client->new->expiry = cur_time + 12000;
627 		ip->client->new->renewal += cur_time + 8000;
628 		ip->client->new->rebind += cur_time + 10000;
629 
630 		ip->client->state = S_REQUESTING;
631 
632 		/* Bind to the address we received. */
633 		bind_lease(ip);
634 		return;
635 	}
636 
637 	/* Go to the REQUESTING state. */
638 	ip->client->destination = iaddr_broadcast;
639 	ip->client->state = S_REQUESTING;
640 	ip->client->first_sending = cur_time;
641 	ip->client->interval = ip->client->config->initial_interval;
642 
643 	/* Make a DHCPREQUEST packet from the lease we picked. */
644 	make_request(ip, picked);
645 	ip->client->xid = ip->client->packet.xid;
646 
647 	/* Toss the lease we picked - we'll get it back in a DHCPACK. */
648 	free_client_lease(picked);
649 
650 	/* Add an immediate timeout to send the first DHCPREQUEST packet. */
651 	send_request(ip);
652 }
653 
654 /* state_requesting is called when we receive a DHCPACK message after
655    having sent out one or more DHCPREQUEST packets. */
656 
657 void
658 dhcpack(struct packet *packet)
659 {
660 	struct interface_info *ip = packet->interface;
661 	struct client_lease *lease;
662 
663 	/* If we're not receptive to an offer right now, or if the offer
664 	   has an unrecognizable transaction id, then just drop it. */
665 	if (packet->interface->client->xid != packet->raw->xid ||
666 	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
667 	    (memcmp(packet->interface->hw_address.haddr,
668 	    packet->raw->chaddr, packet->raw->hlen)))
669 		return;
670 
671 	if (ip->client->state != S_REBOOTING &&
672 	    ip->client->state != S_REQUESTING &&
673 	    ip->client->state != S_RENEWING &&
674 	    ip->client->state != S_REBINDING)
675 		return;
676 
677 	note("DHCPACK from %s", piaddr(packet->client_addr));
678 
679 	lease = packet_to_lease(packet);
680 	if (!lease) {
681 		note("packet_to_lease failed.");
682 		return;
683 	}
684 
685 	ip->client->new = lease;
686 
687 	/* Stop resending DHCPREQUEST. */
688 	cancel_timeout(send_request, ip);
689 
690 	/* Figure out the lease time. */
691 	if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
692 		ip->client->new->expiry = getULong(
693 		    ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
694 	else
695 		ip->client->new->expiry = default_lease_time;
696 	/* A number that looks negative here is really just very large,
697 	   because the lease expiry offset is unsigned. */
698 	if (ip->client->new->expiry < 0)
699 		ip->client->new->expiry = TIME_MAX;
700 	/* XXX should be fixed by resetting the client state */
701 	if (ip->client->new->expiry < 60)
702 		ip->client->new->expiry = 60;
703 
704 	/* Take the server-provided renewal time if there is one;
705 	   otherwise figure it out according to the spec. */
706 	if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
707 		ip->client->new->renewal = getULong(
708 		    ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
709 	else
710 		ip->client->new->renewal = ip->client->new->expiry / 2;
711 
712 	/* Same deal with the rebind time. */
713 	if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
714 		ip->client->new->rebind = getULong(
715 		    ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
716 	else
717 		ip->client->new->rebind = ip->client->new->renewal +
718 		    ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
719 
720 	ip->client->new->expiry += cur_time;
721 	/* Lease lengths can never be negative. */
722 	if (ip->client->new->expiry < cur_time)
723 		ip->client->new->expiry = TIME_MAX;
724 	ip->client->new->renewal += cur_time;
725 	if (ip->client->new->renewal < cur_time)
726 		ip->client->new->renewal = TIME_MAX;
727 	ip->client->new->rebind += cur_time;
728 	if (ip->client->new->rebind < cur_time)
729 		ip->client->new->rebind = TIME_MAX;
730 
731 	bind_lease(ip);
732 }
733 
734 void
735 bind_lease(struct interface_info *ip)
736 {
737 	/* Remember the medium. */
738 	ip->client->new->medium = ip->client->medium;
739 
740 	/* Write out the new lease. */
741 	write_client_lease(ip, ip->client->new, 0);
742 
743 	/* Run the client script with the new parameters. */
744 	script_init((ip->client->state == S_REQUESTING ? "BOUND" :
745 	    (ip->client->state == S_RENEWING ? "RENEW" :
746 	    (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))),
747 	    ip->client->new->medium);
748 	if (ip->client->active && ip->client->state != S_REBOOTING)
749 		script_write_params("old_", ip->client->active);
750 	script_write_params("new_", ip->client->new);
751 	if (ip->client->alias)
752 		script_write_params("alias_", ip->client->alias);
753 	script_go();
754 
755 	/* Replace the old active lease with the new one. */
756 	if (ip->client->active)
757 		free_client_lease(ip->client->active);
758 	ip->client->active = ip->client->new;
759 	ip->client->new = NULL;
760 
761 	/* Set up a timeout to start the renewal process. */
762 	add_timeout(ip->client->active->renewal, state_bound, ip);
763 
764 	note("bound to %s -- renewal in %d seconds.",
765 	    piaddr(ip->client->active->address),
766 	    (int)(ip->client->active->renewal - cur_time));
767 	ip->client->state = S_BOUND;
768 	reinitialize_interfaces();
769 	go_daemon();
770 }
771 
772 /*
773  * state_bound is called when we've successfully bound to a particular
774  * lease, but the renewal time on that lease has expired.   We are
775  * expected to unicast a DHCPREQUEST to the server that gave us our
776  * original lease.
777  */
778 void
779 state_bound(void *ipp)
780 {
781 	struct interface_info *ip = ipp;
782 
783 	ASSERT_STATE(state, S_BOUND);
784 
785 	/* T1 has expired. */
786 	make_request(ip, ip->client->active);
787 	ip->client->xid = ip->client->packet.xid;
788 
789 	if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
790 		memcpy(ip->client->destination.iabuf, ip->client->active->
791 		    options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
792 		ip->client->destination.len = 4;
793 	} else
794 		ip->client->destination = iaddr_broadcast;
795 
796 	ip->client->first_sending = cur_time;
797 	ip->client->interval = ip->client->config->initial_interval;
798 	ip->client->state = S_RENEWING;
799 
800 	/* Send the first packet immediately. */
801 	send_request(ip);
802 }
803 
804 void
805 bootp(struct packet *packet)
806 {
807 	struct iaddrlist *ap;
808 
809 	if (packet->raw->op != BOOTREPLY)
810 		return;
811 
812 	/* If there's a reject list, make sure this packet's sender isn't
813 	   on it. */
814 	for (ap = packet->interface->client->config->reject_list;
815 	    ap; ap = ap->next) {
816 		if (addr_eq(packet->client_addr, ap->addr)) {
817 			note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
818 			return;
819 		}
820 	}
821 	dhcpoffer(packet);
822 }
823 
824 void
825 dhcp(struct packet *packet)
826 {
827 	struct iaddrlist *ap;
828 	void (*handler)(struct packet *);
829 	char *type;
830 
831 	switch (packet->packet_type) {
832 	case DHCPOFFER:
833 		handler = dhcpoffer;
834 		type = "DHCPOFFER";
835 		break;
836 	case DHCPNAK:
837 		handler = dhcpnak;
838 		type = "DHCPNACK";
839 		break;
840 	case DHCPACK:
841 		handler = dhcpack;
842 		type = "DHCPACK";
843 		break;
844 	default:
845 		return;
846 	}
847 
848 	/* If there's a reject list, make sure this packet's sender isn't
849 	   on it. */
850 	for (ap = packet->interface->client->config->reject_list;
851 	    ap; ap = ap->next) {
852 		if (addr_eq(packet->client_addr, ap->addr)) {
853 			note("%s from %s rejected.", type, piaddr(ap->addr));
854 			return;
855 		}
856 	}
857 	(*handler)(packet);
858 }
859 
860 void
861 dhcpoffer(struct packet *packet)
862 {
863 	struct interface_info *ip = packet->interface;
864 	struct client_lease *lease, *lp;
865 	int i;
866 	int arp_timeout_needed, stop_selecting;
867 	char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
868 	    "DHCPOFFER" : "BOOTREPLY";
869 
870 	/* If we're not receptive to an offer right now, or if the offer
871 	   has an unrecognizable transaction id, then just drop it. */
872 	if (ip->client->state != S_SELECTING ||
873 	    packet->interface->client->xid != packet->raw->xid ||
874 	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
875 	    (memcmp(packet->interface->hw_address.haddr,
876 	    packet->raw->chaddr, packet->raw->hlen)))
877 		return;
878 
879 	note("%s from %s", name, piaddr(packet->client_addr));
880 
881 
882 	/* If this lease doesn't supply the minimum required parameters,
883 	   blow it off. */
884 	for (i = 0; ip->client->config->required_options[i]; i++) {
885 		if (!packet->options[ip->client->config->
886 		    required_options[i]].len) {
887 			note("%s isn't satisfactory.", name);
888 			return;
889 		}
890 	}
891 
892 	/* If we've already seen this lease, don't record it again. */
893 	for (lease = ip->client->offered_leases;
894 	    lease; lease = lease->next) {
895 		if (lease->address.len == sizeof(packet->raw->yiaddr) &&
896 		    !memcmp(lease->address.iabuf,
897 		    &packet->raw->yiaddr, lease->address.len)) {
898 			debug("%s already seen.", name);
899 			return;
900 		}
901 	}
902 
903 	lease = packet_to_lease(packet);
904 	if (!lease) {
905 		note("packet_to_lease failed.");
906 		return;
907 	}
908 
909 	/* If this lease was acquired through a BOOTREPLY, record that
910 	   fact. */
911 	if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
912 		lease->is_bootp = 1;
913 
914 	/* Record the medium under which this lease was offered. */
915 	lease->medium = ip->client->medium;
916 
917 	/* Send out an ARP Request for the offered IP address. */
918 	script_init("ARPSEND", lease->medium);
919 	script_write_params("check_", lease);
920 	/* If the script can't send an ARP request without waiting,
921 	   we'll be waiting when we do the ARPCHECK, so don't wait now. */
922 	if (script_go())
923 		arp_timeout_needed = 0;
924 	else
925 		arp_timeout_needed = 2;
926 
927 	/* Figure out when we're supposed to stop selecting. */
928 	stop_selecting =
929 	    ip->client->first_sending + ip->client->config->select_interval;
930 
931 	/* If this is the lease we asked for, put it at the head of the
932 	   list, and don't mess with the arp request timeout. */
933 	if (lease->address.len == ip->client->requested_address.len &&
934 	    !memcmp(lease->address.iabuf,
935 	    ip->client->requested_address.iabuf,
936 	    ip->client->requested_address.len)) {
937 		lease->next = ip->client->offered_leases;
938 		ip->client->offered_leases = lease;
939 	} else {
940 		/* If we already have an offer, and arping for this
941 		   offer would take us past the selection timeout,
942 		   then don't extend the timeout - just hope for the
943 		   best. */
944 		if (ip->client->offered_leases &&
945 		    (cur_time + arp_timeout_needed) > stop_selecting)
946 			arp_timeout_needed = 0;
947 
948 		/* Put the lease at the end of the list. */
949 		lease->next = NULL;
950 		if (!ip->client->offered_leases)
951 			ip->client->offered_leases = lease;
952 		else {
953 			for (lp = ip->client->offered_leases; lp->next;
954 			    lp = lp->next)
955 				;	/* nothing */
956 			lp->next = lease;
957 		}
958 	}
959 
960 	/* If we're supposed to stop selecting before we've had time
961 	   to wait for the ARPREPLY, add some delay to wait for
962 	   the ARPREPLY. */
963 	if (stop_selecting - cur_time < arp_timeout_needed)
964 		stop_selecting = cur_time + arp_timeout_needed;
965 
966 	/* If the selecting interval has expired, go immediately to
967 	   state_selecting().  Otherwise, time out into
968 	   state_selecting at the select interval. */
969 	if (stop_selecting <= 0)
970 		state_selecting(ip);
971 	else {
972 		add_timeout(stop_selecting, state_selecting, ip);
973 		cancel_timeout(send_discover, ip);
974 	}
975 }
976 
977 /* Allocate a client_lease structure and initialize it from the parameters
978    in the specified packet. */
979 
980 struct client_lease *
981 packet_to_lease(struct packet *packet)
982 {
983 	struct client_lease *lease;
984 	int i;
985 
986 	lease = malloc(sizeof(struct client_lease));
987 
988 	if (!lease) {
989 		warning("dhcpoffer: no memory to record lease.");
990 		return (NULL);
991 	}
992 
993 	memset(lease, 0, sizeof(*lease));
994 
995 	/* Copy the lease options. */
996 	for (i = 0; i < 256; i++) {
997 		if (packet->options[i].len) {
998 			lease->options[i].data =
999 			    malloc(packet->options[i].len + 1);
1000 			if (!lease->options[i].data) {
1001 				warning("dhcpoffer: no memory for option %d", i);
1002 				free_client_lease(lease);
1003 				return (NULL);
1004 			} else {
1005 				memcpy(lease->options[i].data,
1006 				    packet->options[i].data,
1007 				    packet->options[i].len);
1008 				lease->options[i].len =
1009 				    packet->options[i].len;
1010 				lease->options[i].data[lease->options[i].len] =
1011 				    0;
1012 			}
1013 			if (!check_option(lease,i)) {
1014 				/* ignore a bogus lease offer */
1015 				warning("Invalid lease option - ignoring offer");
1016 				free_client_lease(lease);
1017 				return (NULL);
1018 			}
1019 		}
1020 	}
1021 
1022 	lease->address.len = sizeof(packet->raw->yiaddr);
1023 	memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
1024 
1025 	/* If the server name was filled out, copy it.
1026 	   Do not attempt to validate the server name as a host name.
1027 	   RFC 2131 merely states that sname is NUL-terminated (which do
1028 	   do not assume) and that it is the server's host name.  Since
1029 	   the ISC client and server allow arbitrary characters, we do
1030 	   as well. */
1031 	if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1032 	    !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
1033 	    packet->raw->sname[0]) {
1034 		lease->server_name = malloc(DHCP_SNAME_LEN + 1);
1035 		if (!lease->server_name) {
1036 			warning("dhcpoffer: no memory for server name.");
1037 			free_client_lease(lease);
1038 			return (NULL);
1039 		}
1040 		memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
1041 		lease->server_name[DHCP_SNAME_LEN]='\0';
1042 	}
1043 
1044 	/* Ditto for the filename. */
1045 	if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1046 	    !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
1047 	    packet->raw->file[0]) {
1048 		/* Don't count on the NUL terminator. */
1049 		lease->filename = malloc(DHCP_FILE_LEN + 1);
1050 		if (!lease->filename) {
1051 			warning("dhcpoffer: no memory for filename.");
1052 			free_client_lease(lease);
1053 			return (NULL);
1054 		}
1055 		memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
1056 		lease->filename[DHCP_FILE_LEN]='\0';
1057 	}
1058 	return lease;
1059 }
1060 
1061 void
1062 dhcpnak(struct packet *packet)
1063 {
1064 	struct interface_info *ip = packet->interface;
1065 
1066 	/* If we're not receptive to an offer right now, or if the offer
1067 	   has an unrecognizable transaction id, then just drop it. */
1068 	if (packet->interface->client->xid != packet->raw->xid ||
1069 	    (packet->interface->hw_address.hlen != packet->raw->hlen) ||
1070 	    (memcmp(packet->interface->hw_address.haddr,
1071 	    packet->raw->chaddr, packet->raw->hlen)))
1072 		return;
1073 
1074 	if (ip->client->state != S_REBOOTING &&
1075 	    ip->client->state != S_REQUESTING &&
1076 	    ip->client->state != S_RENEWING &&
1077 	    ip->client->state != S_REBINDING)
1078 		return;
1079 
1080 	note("DHCPNAK from %s", piaddr(packet->client_addr));
1081 
1082 	if (!ip->client->active) {
1083 		note("DHCPNAK with no active lease.\n");
1084 		return;
1085 	}
1086 
1087 	free_client_lease(ip->client->active);
1088 	ip->client->active = NULL;
1089 
1090 	/* Stop sending DHCPREQUEST packets... */
1091 	cancel_timeout(send_request, ip);
1092 
1093 	ip->client->state = S_INIT;
1094 	state_init(ip);
1095 }
1096 
1097 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1098    one after the right interval has expired.  If we don't get an offer by
1099    the time we reach the panic interval, call the panic function. */
1100 
1101 void
1102 send_discover(void *ipp)
1103 {
1104 	struct interface_info *ip = ipp;
1105 	int interval, increase = 1;
1106 
1107 	/* Figure out how long it's been since we started transmitting. */
1108 	interval = cur_time - ip->client->first_sending;
1109 
1110 	/* If we're past the panic timeout, call the script and tell it
1111 	   we haven't found anything for this interface yet. */
1112 	if (interval > ip->client->config->timeout) {
1113 		state_panic(ip);
1114 		return;
1115 	}
1116 
1117 	/* If we're selecting media, try the whole list before doing
1118 	   the exponential backoff, but if we've already received an
1119 	   offer, stop looping, because we obviously have it right. */
1120 	if (!ip->client->offered_leases &&
1121 	    ip->client->config->media) {
1122 		int fail = 0;
1123 again:
1124 		if (ip->client->medium) {
1125 			ip->client->medium = ip->client->medium->next;
1126 			increase = 0;
1127 		}
1128 		if (!ip->client->medium) {
1129 			if (fail)
1130 				error("No valid media types for %s!", ip->name);
1131 			ip->client->medium = ip->client->config->media;
1132 			increase = 1;
1133 		}
1134 
1135 		note("Trying medium \"%s\" %d", ip->client->medium->string,
1136 		    increase);
1137 		script_init("MEDIUM", ip->client->medium);
1138 		if (script_go())
1139 			goto again;
1140 	}
1141 
1142 	/*
1143 	 * If we're supposed to increase the interval, do so.  If it's
1144 	 * currently zero (i.e., we haven't sent any packets yet), set
1145 	 * it to one; otherwise, add to it a random number between zero
1146 	 * and two times itself.  On average, this means that it will
1147 	 * double with every transmission.
1148 	 */
1149 	if (increase) {
1150 		if (!ip->client->interval)
1151 			ip->client->interval =
1152 			    ip->client->config->initial_interval;
1153 		else {
1154 			ip->client->interval += (arc4random() >> 2) %
1155 			    (2 * ip->client->interval);
1156 		}
1157 
1158 		/* Don't backoff past cutoff. */
1159 		if (ip->client->interval >
1160 		    ip->client->config->backoff_cutoff)
1161 			ip->client->interval =
1162 				((ip->client->config->backoff_cutoff / 2)
1163 				 + ((arc4random() >> 2) %
1164 				    ip->client->config->backoff_cutoff));
1165 	} else if (!ip->client->interval)
1166 		ip->client->interval =
1167 			ip->client->config->initial_interval;
1168 
1169 	/* If the backoff would take us to the panic timeout, just use that
1170 	   as the interval. */
1171 	if (cur_time + ip->client->interval >
1172 	    ip->client->first_sending + ip->client->config->timeout)
1173 		ip->client->interval =
1174 			(ip->client->first_sending +
1175 			 ip->client->config->timeout) - cur_time + 1;
1176 
1177 	/* Record the number of seconds since we started sending. */
1178 	if (interval < 65536)
1179 		ip->client->packet.secs = htons(interval);
1180 	else
1181 		ip->client->packet.secs = htons(65535);
1182 	ip->client->secs = ip->client->packet.secs;
1183 
1184 	note("DHCPDISCOVER on %s to %s port %d interval %d",
1185 	    ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
1186 	    ntohs(sockaddr_broadcast.sin_port),
1187 	    (int)ip->client->interval);
1188 
1189 	/* Send out a packet. */
1190 	(void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
1191 	    inaddr_any, &sockaddr_broadcast, NULL);
1192 
1193 	add_timeout(cur_time + ip->client->interval, send_discover, ip);
1194 }
1195 
1196 /*
1197  * state_panic gets called if we haven't received any offers in a preset
1198  * amount of time.   When this happens, we try to use existing leases
1199  * that haven't yet expired, and failing that, we call the client script
1200  * and hope it can do something.
1201  */
1202 void
1203 state_panic(void *ipp)
1204 {
1205 	struct interface_info *ip = ipp;
1206 	struct client_lease *loop = ip->client->active;
1207 	struct client_lease *lp;
1208 
1209 	note("No DHCPOFFERS received.");
1210 
1211 	/* We may not have an active lease, but we may have some
1212 	   predefined leases that we can try. */
1213 	if (!ip->client->active && ip->client->leases)
1214 		goto activate_next;
1215 
1216 	/* Run through the list of leases and see if one can be used. */
1217 	while (ip->client->active) {
1218 		if (ip->client->active->expiry > cur_time) {
1219 			note("Trying recorded lease %s",
1220 			    piaddr(ip->client->active->address));
1221 			/* Run the client script with the existing
1222 			   parameters. */
1223 			script_init("TIMEOUT",
1224 			    ip->client->active->medium);
1225 			script_write_params("new_", ip->client->active);
1226 			if (ip->client->alias)
1227 				script_write_params("alias_",
1228 				    ip->client->alias);
1229 
1230 			/* If the old lease is still good and doesn't
1231 			   yet need renewal, go into BOUND state and
1232 			   timeout at the renewal time. */
1233 			if (!script_go()) {
1234 				if (cur_time <
1235 				    ip->client->active->renewal) {
1236 					ip->client->state = S_BOUND;
1237 					note("bound: renewal in %d seconds.",
1238 					    (int)(ip->client->active->renewal -
1239 					    cur_time));
1240 					add_timeout(
1241 					    ip->client->active->renewal,
1242 					    state_bound, ip);
1243 				} else {
1244 					ip->client->state = S_BOUND;
1245 					note("bound: immediate renewal.");
1246 					state_bound(ip);
1247 				}
1248 				reinitialize_interfaces();
1249 				go_daemon();
1250 				return;
1251 			}
1252 		}
1253 
1254 		/* If there are no other leases, give up. */
1255 		if (!ip->client->leases) {
1256 			ip->client->leases = ip->client->active;
1257 			ip->client->active = NULL;
1258 			break;
1259 		}
1260 
1261 activate_next:
1262 		/* Otherwise, put the active lease at the end of the
1263 		   lease list, and try another lease.. */
1264 		for (lp = ip->client->leases; lp->next; lp = lp->next)
1265 			;
1266 		lp->next = ip->client->active;
1267 		if (lp->next)
1268 			lp->next->next = NULL;
1269 		ip->client->active = ip->client->leases;
1270 		ip->client->leases = ip->client->leases->next;
1271 
1272 		/* If we already tried this lease, we've exhausted the
1273 		   set of leases, so we might as well give up for
1274 		   now. */
1275 		if (ip->client->active == loop)
1276 			break;
1277 		else if (!loop)
1278 			loop = ip->client->active;
1279 	}
1280 
1281 	/* No leases were available, or what was available didn't work, so
1282 	   tell the shell script that we failed to allocate an address,
1283 	   and try again later. */
1284 	note("No working leases in persistent database - sleeping.\n");
1285 	script_init("FAIL", NULL);
1286 	if (ip->client->alias)
1287 		script_write_params("alias_", ip->client->alias);
1288 	script_go();
1289 	ip->client->state = S_INIT;
1290 	add_timeout(cur_time + ip->client->config->retry_interval, state_init,
1291 	    ip);
1292 	go_daemon();
1293 }
1294 
1295 void
1296 send_request(void *ipp)
1297 {
1298 	struct interface_info *ip = ipp;
1299 	struct sockaddr_in destination;
1300 	struct in_addr from;
1301 	int interval;
1302 
1303 	/* Figure out how long it's been since we started transmitting. */
1304 	interval = cur_time - ip->client->first_sending;
1305 
1306 	/* If we're in the INIT-REBOOT or REQUESTING state and we're
1307 	   past the reboot timeout, go to INIT and see if we can
1308 	   DISCOVER an address... */
1309 	/* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1310 	   means either that we're on a network with no DHCP server,
1311 	   or that our server is down.  In the latter case, assuming
1312 	   that there is a backup DHCP server, DHCPDISCOVER will get
1313 	   us a new address, but we could also have successfully
1314 	   reused our old address.  In the former case, we're hosed
1315 	   anyway.  This is not a win-prone situation. */
1316 	if ((ip->client->state == S_REBOOTING ||
1317 	    ip->client->state == S_REQUESTING) &&
1318 	    interval > ip->client->config->reboot_timeout) {
1319 cancel:
1320 		ip->client->state = S_INIT;
1321 		cancel_timeout(send_request, ip);
1322 		state_init(ip);
1323 		return;
1324 	}
1325 
1326 	/* If we're in the reboot state, make sure the media is set up
1327 	   correctly. */
1328 	if (ip->client->state == S_REBOOTING &&
1329 	    !ip->client->medium &&
1330 	    ip->client->active->medium ) {
1331 		script_init("MEDIUM", ip->client->active->medium);
1332 
1333 		/* If the medium we chose won't fly, go to INIT state. */
1334 		if (script_go())
1335 			goto cancel;
1336 
1337 		/* Record the medium. */
1338 		ip->client->medium = ip->client->active->medium;
1339 	}
1340 
1341 	/* If the lease has expired, relinquish the address and go back
1342 	   to the INIT state. */
1343 	if (ip->client->state != S_REQUESTING &&
1344 	    cur_time > ip->client->active->expiry) {
1345 		/* Run the client script with the new parameters. */
1346 		script_init("EXPIRE", NULL);
1347 		script_write_params("old_", ip->client->active);
1348 		if (ip->client->alias)
1349 			script_write_params("alias_", ip->client->alias);
1350 		script_go();
1351 
1352 		/* Now do a preinit on the interface so that we can
1353 		   discover a new address. */
1354 		script_init("PREINIT", NULL);
1355 		if (ip->client->alias)
1356 			script_write_params("alias_", ip->client->alias);
1357 		script_go();
1358 
1359 		ip->client->state = S_INIT;
1360 		state_init(ip);
1361 		return;
1362 	}
1363 
1364 	/* Do the exponential backoff... */
1365 	if (!ip->client->interval)
1366 		ip->client->interval = ip->client->config->initial_interval;
1367 	else
1368 		ip->client->interval += ((arc4random() >> 2) %
1369 		    (2 * ip->client->interval));
1370 
1371 	/* Don't backoff past cutoff. */
1372 	if (ip->client->interval >
1373 	    ip->client->config->backoff_cutoff)
1374 		ip->client->interval =
1375 		    ((ip->client->config->backoff_cutoff / 2) +
1376 		    ((arc4random() >> 2) % ip->client->interval));
1377 
1378 	/* If the backoff would take us to the expiry time, just set the
1379 	   timeout to the expiry time. */
1380 	if (ip->client->state != S_REQUESTING &&
1381 	    cur_time + ip->client->interval >
1382 	    ip->client->active->expiry)
1383 		ip->client->interval =
1384 		    ip->client->active->expiry - cur_time + 1;
1385 
1386 	/* If the lease T2 time has elapsed, or if we're not yet bound,
1387 	   broadcast the DHCPREQUEST rather than unicasting. */
1388 	memset(&destination, 0, sizeof(destination));
1389 	if (ip->client->state == S_REQUESTING ||
1390 	    ip->client->state == S_REBOOTING ||
1391 	    cur_time > ip->client->active->rebind)
1392 		destination.sin_addr.s_addr = INADDR_BROADCAST;
1393 	else
1394 		memcpy(&destination.sin_addr.s_addr,
1395 		    ip->client->destination.iabuf,
1396 		    sizeof(destination.sin_addr.s_addr));
1397 	destination.sin_port = htons(REMOTE_PORT);
1398 	destination.sin_family = AF_INET;
1399 	destination.sin_len = sizeof(destination);
1400 
1401 	if (ip->client->state != S_REQUESTING)
1402 		memcpy(&from, ip->client->active->address.iabuf,
1403 		    sizeof(from));
1404 	else
1405 		from.s_addr = INADDR_ANY;
1406 
1407 	/* Record the number of seconds since we started sending. */
1408 	if (ip->client->state == S_REQUESTING)
1409 		ip->client->packet.secs = ip->client->secs;
1410 	else {
1411 		if (interval < 65536)
1412 			ip->client->packet.secs = htons(interval);
1413 		else
1414 			ip->client->packet.secs = htons(65535);
1415 	}
1416 
1417 	note("DHCPREQUEST on %s to %s port %d", ip->name,
1418 	    inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
1419 
1420 	/* Send out a packet. */
1421 	(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1422 	    from, &destination, NULL);
1423 
1424 	add_timeout(cur_time + ip->client->interval, send_request, ip);
1425 }
1426 
1427 void
1428 send_decline(void *ipp)
1429 {
1430 	struct interface_info *ip = ipp;
1431 
1432 	note("DHCPDECLINE on %s to %s port %d", ip->name,
1433 	    inet_ntoa(sockaddr_broadcast.sin_addr),
1434 	    ntohs(sockaddr_broadcast.sin_port));
1435 
1436 	/* Send out a packet. */
1437 	(void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1438 	    inaddr_any, &sockaddr_broadcast, NULL);
1439 }
1440 
1441 void
1442 make_discover(struct interface_info *ip, struct client_lease *lease)
1443 {
1444 	unsigned char discover = DHCPDISCOVER;
1445 	struct tree_cache *options[256];
1446 	struct tree_cache option_elements[256];
1447 	int i;
1448 
1449 	memset(option_elements, 0, sizeof(option_elements));
1450 	memset(options, 0, sizeof(options));
1451 	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1452 
1453 	/* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1454 	i = DHO_DHCP_MESSAGE_TYPE;
1455 	options[i] = &option_elements[i];
1456 	options[i]->value = &discover;
1457 	options[i]->len = sizeof(discover);
1458 	options[i]->buf_size = sizeof(discover);
1459 	options[i]->timeout = 0xFFFFFFFF;
1460 
1461 	/* Request the options we want */
1462 	i  = DHO_DHCP_PARAMETER_REQUEST_LIST;
1463 	options[i] = &option_elements[i];
1464 	options[i]->value = ip->client->config->requested_options;
1465 	options[i]->len = ip->client->config->requested_option_count;
1466 	options[i]->buf_size =
1467 		ip->client->config->requested_option_count;
1468 	options[i]->timeout = 0xFFFFFFFF;
1469 
1470 	/* If we had an address, try to get it again. */
1471 	if (lease) {
1472 		ip->client->requested_address = lease->address;
1473 		i = DHO_DHCP_REQUESTED_ADDRESS;
1474 		options[i] = &option_elements[i];
1475 		options[i]->value = lease->address.iabuf;
1476 		options[i]->len = lease->address.len;
1477 		options[i]->buf_size = lease->address.len;
1478 		options[i]->timeout = 0xFFFFFFFF;
1479 	} else
1480 		ip->client->requested_address.len = 0;
1481 
1482 	/* Send any options requested in the config file. */
1483 	for (i = 0; i < 256; i++)
1484 		if (!options[i] &&
1485 		    ip->client->config->send_options[i].data) {
1486 			options[i] = &option_elements[i];
1487 			options[i]->value =
1488 			    ip->client->config->send_options[i].data;
1489 			options[i]->len =
1490 			    ip->client->config->send_options[i].len;
1491 			options[i]->buf_size =
1492 			    ip->client->config->send_options[i].len;
1493 			options[i]->timeout = 0xFFFFFFFF;
1494 		}
1495 
1496 	/* send host name if not set via config file. */
1497 	char hostname[_POSIX_HOST_NAME_MAX+1];
1498 	if (!options[DHO_HOST_NAME]) {
1499 		if (gethostname(hostname, sizeof(hostname)) == 0) {
1500 			size_t len;
1501 			char* posDot = strchr(hostname, '.');
1502 			if (posDot != NULL)
1503 				len = posDot - hostname;
1504 			else
1505 				len = strlen(hostname);
1506 			options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1507 			options[DHO_HOST_NAME]->value = hostname;
1508 			options[DHO_HOST_NAME]->len = len;
1509 			options[DHO_HOST_NAME]->buf_size = len;
1510 			options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1511 		}
1512 	}
1513 
1514 	/* set unique client identifier */
1515 	char client_ident[sizeof(struct hardware)];
1516 	if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1517 		int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1518 				ip->hw_address.hlen : sizeof(client_ident)-1;
1519 		client_ident[0] = ip->hw_address.htype;
1520 		memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1521 		options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1522 		options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1523 		options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1524 		options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1525 		options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1526 	}
1527 
1528 	/* Set up the option buffer... */
1529 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1530 	    options, 0, 0, 0, NULL, 0);
1531 	if (ip->client->packet_length < BOOTP_MIN_LEN)
1532 		ip->client->packet_length = BOOTP_MIN_LEN;
1533 
1534 	ip->client->packet.op = BOOTREQUEST;
1535 	ip->client->packet.htype = ip->hw_address.htype;
1536 	ip->client->packet.hlen = ip->hw_address.hlen;
1537 	ip->client->packet.hops = 0;
1538 	ip->client->packet.xid = arc4random();
1539 	ip->client->packet.secs = 0; /* filled in by send_discover. */
1540 	ip->client->packet.flags = 0;
1541 
1542 	memset(&(ip->client->packet.ciaddr),
1543 	    0, sizeof(ip->client->packet.ciaddr));
1544 	memset(&(ip->client->packet.yiaddr),
1545 	    0, sizeof(ip->client->packet.yiaddr));
1546 	memset(&(ip->client->packet.siaddr),
1547 	    0, sizeof(ip->client->packet.siaddr));
1548 	memset(&(ip->client->packet.giaddr),
1549 	    0, sizeof(ip->client->packet.giaddr));
1550 	memcpy(ip->client->packet.chaddr,
1551 	    ip->hw_address.haddr, ip->hw_address.hlen);
1552 }
1553 
1554 
1555 void
1556 make_request(struct interface_info *ip, struct client_lease * lease)
1557 {
1558 	unsigned char request = DHCPREQUEST;
1559 	struct tree_cache *options[256];
1560 	struct tree_cache option_elements[256];
1561 	int i;
1562 
1563 	memset(options, 0, sizeof(options));
1564 	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1565 
1566 	/* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1567 	i = DHO_DHCP_MESSAGE_TYPE;
1568 	options[i] = &option_elements[i];
1569 	options[i]->value = &request;
1570 	options[i]->len = sizeof(request);
1571 	options[i]->buf_size = sizeof(request);
1572 	options[i]->timeout = 0xFFFFFFFF;
1573 
1574 	/* Request the options we want */
1575 	i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1576 	options[i] = &option_elements[i];
1577 	options[i]->value = ip->client->config->requested_options;
1578 	options[i]->len = ip->client->config->requested_option_count;
1579 	options[i]->buf_size =
1580 		ip->client->config->requested_option_count;
1581 	options[i]->timeout = 0xFFFFFFFF;
1582 
1583 	/* If we are requesting an address that hasn't yet been assigned
1584 	   to us, use the DHCP Requested Address option. */
1585 	if (ip->client->state == S_REQUESTING) {
1586 		/* Send back the server identifier... */
1587 		i = DHO_DHCP_SERVER_IDENTIFIER;
1588 		options[i] = &option_elements[i];
1589 		options[i]->value = lease->options[i].data;
1590 		options[i]->len = lease->options[i].len;
1591 		options[i]->buf_size = lease->options[i].len;
1592 		options[i]->timeout = 0xFFFFFFFF;
1593 	}
1594 	if (ip->client->state == S_REQUESTING ||
1595 	    ip->client->state == S_REBOOTING) {
1596 		ip->client->requested_address = lease->address;
1597 		i = DHO_DHCP_REQUESTED_ADDRESS;
1598 		options[i] = &option_elements[i];
1599 		options[i]->value = lease->address.iabuf;
1600 		options[i]->len = lease->address.len;
1601 		options[i]->buf_size = lease->address.len;
1602 		options[i]->timeout = 0xFFFFFFFF;
1603 	} else
1604 		ip->client->requested_address.len = 0;
1605 
1606 	/* Send any options requested in the config file. */
1607 	for (i = 0; i < 256; i++)
1608 		if (!options[i] &&
1609 		    ip->client->config->send_options[i].data) {
1610 			options[i] = &option_elements[i];
1611 			options[i]->value =
1612 			    ip->client->config->send_options[i].data;
1613 			options[i]->len =
1614 			    ip->client->config->send_options[i].len;
1615 			options[i]->buf_size =
1616 			    ip->client->config->send_options[i].len;
1617 			options[i]->timeout = 0xFFFFFFFF;
1618 		}
1619 
1620 	/* send host name if not set via config file. */
1621 	char hostname[_POSIX_HOST_NAME_MAX+1];
1622 	if (!options[DHO_HOST_NAME]) {
1623 		if (gethostname(hostname, sizeof(hostname)) == 0) {
1624 			size_t len;
1625 			char* posDot = strchr(hostname, '.');
1626 			if (posDot != NULL)
1627 				len = posDot - hostname;
1628 			else
1629 				len = strlen(hostname);
1630 			options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1631 			options[DHO_HOST_NAME]->value = hostname;
1632 			options[DHO_HOST_NAME]->len = len;
1633 			options[DHO_HOST_NAME]->buf_size = len;
1634 			options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1635 		}
1636 	}
1637 
1638 	/* set unique client identifier */
1639 	char client_ident[sizeof(struct hardware)];
1640 	if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1641 		int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1642 				ip->hw_address.hlen : sizeof(client_ident)-1;
1643 		client_ident[0] = ip->hw_address.htype;
1644 		memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1645 		options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1646 		options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1647 		options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1648 		options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1649 		options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1650 	}
1651 
1652 	/* Set up the option buffer... */
1653 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1654 	    options, 0, 0, 0, NULL, 0);
1655 	if (ip->client->packet_length < BOOTP_MIN_LEN)
1656 		ip->client->packet_length = BOOTP_MIN_LEN;
1657 
1658 	ip->client->packet.op = BOOTREQUEST;
1659 	ip->client->packet.htype = ip->hw_address.htype;
1660 	ip->client->packet.hlen = ip->hw_address.hlen;
1661 	ip->client->packet.hops = 0;
1662 	ip->client->packet.xid = ip->client->xid;
1663 	ip->client->packet.secs = 0; /* Filled in by send_request. */
1664 
1665 	/* If we own the address we're requesting, put it in ciaddr;
1666 	   otherwise set ciaddr to zero. */
1667 	if (ip->client->state == S_BOUND ||
1668 	    ip->client->state == S_RENEWING ||
1669 	    ip->client->state == S_REBINDING) {
1670 		memcpy(&ip->client->packet.ciaddr,
1671 		    lease->address.iabuf, lease->address.len);
1672 		ip->client->packet.flags = 0;
1673 	} else {
1674 		memset(&ip->client->packet.ciaddr, 0,
1675 		    sizeof(ip->client->packet.ciaddr));
1676 		ip->client->packet.flags = 0;
1677 	}
1678 
1679 	memset(&ip->client->packet.yiaddr, 0,
1680 	    sizeof(ip->client->packet.yiaddr));
1681 	memset(&ip->client->packet.siaddr, 0,
1682 	    sizeof(ip->client->packet.siaddr));
1683 	memset(&ip->client->packet.giaddr, 0,
1684 	    sizeof(ip->client->packet.giaddr));
1685 	memcpy(ip->client->packet.chaddr,
1686 	    ip->hw_address.haddr, ip->hw_address.hlen);
1687 }
1688 
1689 void
1690 make_decline(struct interface_info *ip, struct client_lease *lease)
1691 {
1692 	struct tree_cache *options[256], message_type_tree;
1693 	struct tree_cache requested_address_tree;
1694 	struct tree_cache server_id_tree, client_id_tree;
1695 	unsigned char decline = DHCPDECLINE;
1696 	int i;
1697 
1698 	memset(options, 0, sizeof(options));
1699 	memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1700 
1701 	/* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1702 	i = DHO_DHCP_MESSAGE_TYPE;
1703 	options[i] = &message_type_tree;
1704 	options[i]->value = &decline;
1705 	options[i]->len = sizeof(decline);
1706 	options[i]->buf_size = sizeof(decline);
1707 	options[i]->timeout = 0xFFFFFFFF;
1708 
1709 	/* Send back the server identifier... */
1710 	i = DHO_DHCP_SERVER_IDENTIFIER;
1711 	options[i] = &server_id_tree;
1712 	options[i]->value = lease->options[i].data;
1713 	options[i]->len = lease->options[i].len;
1714 	options[i]->buf_size = lease->options[i].len;
1715 	options[i]->timeout = 0xFFFFFFFF;
1716 
1717 	/* Send back the address we're declining. */
1718 	i = DHO_DHCP_REQUESTED_ADDRESS;
1719 	options[i] = &requested_address_tree;
1720 	options[i]->value = lease->address.iabuf;
1721 	options[i]->len = lease->address.len;
1722 	options[i]->buf_size = lease->address.len;
1723 	options[i]->timeout = 0xFFFFFFFF;
1724 
1725 	/* Send the uid if the user supplied one. */
1726 	i = DHO_DHCP_CLIENT_IDENTIFIER;
1727 	if (ip->client->config->send_options[i].len) {
1728 		options[i] = &client_id_tree;
1729 		options[i]->value = ip->client->config->send_options[i].data;
1730 		options[i]->len = ip->client->config->send_options[i].len;
1731 		options[i]->buf_size = ip->client->config->send_options[i].len;
1732 		options[i]->timeout = 0xFFFFFFFF;
1733 	}
1734 
1735 
1736 	/* Set up the option buffer... */
1737 	ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1738 	    options, 0, 0, 0, NULL, 0);
1739 	if (ip->client->packet_length < BOOTP_MIN_LEN)
1740 		ip->client->packet_length = BOOTP_MIN_LEN;
1741 
1742 	ip->client->packet.op = BOOTREQUEST;
1743 	ip->client->packet.htype = ip->hw_address.htype;
1744 	ip->client->packet.hlen = ip->hw_address.hlen;
1745 	ip->client->packet.hops = 0;
1746 	ip->client->packet.xid = ip->client->xid;
1747 	ip->client->packet.secs = 0; /* Filled in by send_request. */
1748 	ip->client->packet.flags = 0;
1749 
1750 	/* ciaddr must always be zero. */
1751 	memset(&ip->client->packet.ciaddr, 0,
1752 	    sizeof(ip->client->packet.ciaddr));
1753 	memset(&ip->client->packet.yiaddr, 0,
1754 	    sizeof(ip->client->packet.yiaddr));
1755 	memset(&ip->client->packet.siaddr, 0,
1756 	    sizeof(ip->client->packet.siaddr));
1757 	memset(&ip->client->packet.giaddr, 0,
1758 	    sizeof(ip->client->packet.giaddr));
1759 	memcpy(ip->client->packet.chaddr,
1760 	    ip->hw_address.haddr, ip->hw_address.hlen);
1761 }
1762 
1763 void
1764 free_client_lease(struct client_lease *lease)
1765 {
1766 	int i;
1767 
1768 	if (lease->server_name)
1769 		free(lease->server_name);
1770 	if (lease->filename)
1771 		free(lease->filename);
1772 	for (i = 0; i < 256; i++) {
1773 		if (lease->options[i].len)
1774 			free(lease->options[i].data);
1775 	}
1776 	free(lease);
1777 }
1778 
1779 FILE *leaseFile;
1780 
1781 void
1782 rewrite_client_leases(void)
1783 {
1784 	struct client_lease *lp;
1785 
1786 	if (!leaseFile) {
1787 		leaseFile = fopen(path_dhclient_db, "w");
1788 		if (!leaseFile)
1789 			error("can't create %s: %m", path_dhclient_db);
1790 	} else {
1791 		fflush(leaseFile);
1792 		rewind(leaseFile);
1793 	}
1794 
1795 	for (lp = ifi->client->leases; lp; lp = lp->next)
1796 		write_client_lease(ifi, lp, 1);
1797 	if (ifi->client->active)
1798 		write_client_lease(ifi, ifi->client->active, 1);
1799 
1800 	fflush(leaseFile);
1801 	ftruncate(fileno(leaseFile), ftello(leaseFile));
1802 	fsync(fileno(leaseFile));
1803 }
1804 
1805 void
1806 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1807     int rewrite)
1808 {
1809 	static int leases_written;
1810 	struct tm *t;
1811 	int i;
1812 
1813 	if (!rewrite) {
1814 		if (leases_written++ > 20) {
1815 			rewrite_client_leases();
1816 			leases_written = 0;
1817 		}
1818 	}
1819 
1820 	/* If the lease came from the config file, we don't need to stash
1821 	   a copy in the lease database. */
1822 	if (lease->is_static)
1823 		return;
1824 
1825 	if (!leaseFile) {	/* XXX */
1826 		leaseFile = fopen(path_dhclient_db, "w");
1827 		if (!leaseFile)
1828 			error("can't create %s: %m", path_dhclient_db);
1829 	}
1830 
1831 	fprintf(leaseFile, "lease {\n");
1832 	if (lease->is_bootp)
1833 		fprintf(leaseFile, "  bootp;\n");
1834 	fprintf(leaseFile, "  interface \"%s\";\n", ip->name);
1835 	fprintf(leaseFile, "  fixed-address %s;\n", piaddr(lease->address));
1836 	if (lease->filename)
1837 		fprintf(leaseFile, "  filename \"%s\";\n", lease->filename);
1838 	if (lease->server_name)
1839 		fprintf(leaseFile, "  server-name \"%s\";\n",
1840 		    lease->server_name);
1841 	if (lease->medium)
1842 		fprintf(leaseFile, "  medium \"%s\";\n", lease->medium->string);
1843 	for (i = 0; i < 256; i++)
1844 		if (lease->options[i].len)
1845 			fprintf(leaseFile, "  option %s %s;\n",
1846 			    dhcp_options[i].name,
1847 			    pretty_print_option(i, lease->options[i].data,
1848 			    lease->options[i].len, 1, 1));
1849 
1850 	t = gmtime(&lease->renewal);
1851 	fprintf(leaseFile, "  renew %d %d/%d/%d %02d:%02d:%02d;\n",
1852 	    t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1853 	    t->tm_hour, t->tm_min, t->tm_sec);
1854 	t = gmtime(&lease->rebind);
1855 	fprintf(leaseFile, "  rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1856 	    t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1857 	    t->tm_hour, t->tm_min, t->tm_sec);
1858 	t = gmtime(&lease->expiry);
1859 	fprintf(leaseFile, "  expire %d %d/%d/%d %02d:%02d:%02d;\n",
1860 	    t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1861 	    t->tm_hour, t->tm_min, t->tm_sec);
1862 	fprintf(leaseFile, "}\n");
1863 	fflush(leaseFile);
1864 }
1865 
1866 void
1867 script_init(char *reason, struct string_list *medium)
1868 {
1869 	size_t		 len, mediumlen = 0;
1870 	struct imsg_hdr	 hdr;
1871 	struct buf	*buf;
1872 	int		 errs;
1873 
1874 	if (medium != NULL && medium->string != NULL)
1875 		mediumlen = strlen(medium->string);
1876 
1877 	hdr.code = IMSG_SCRIPT_INIT;
1878 	hdr.len = sizeof(struct imsg_hdr) +
1879 	    sizeof(size_t) + mediumlen +
1880 	    sizeof(size_t) + strlen(reason);
1881 
1882 	if ((buf = buf_open(hdr.len)) == NULL)
1883 		error("buf_open: %m");
1884 
1885 	errs = 0;
1886 	errs += buf_add(buf, &hdr, sizeof(hdr));
1887 	errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
1888 	if (mediumlen > 0)
1889 		errs += buf_add(buf, medium->string, mediumlen);
1890 	len = strlen(reason);
1891 	errs += buf_add(buf, &len, sizeof(len));
1892 	errs += buf_add(buf, reason, len);
1893 
1894 	if (errs)
1895 		error("buf_add: %m");
1896 
1897 	if (buf_close(privfd, buf) == -1)
1898 		error("buf_close: %m");
1899 }
1900 
1901 void
1902 priv_script_init(char *reason, char *medium)
1903 {
1904 	struct interface_info *ip = ifi;
1905 
1906 	if (ip) {
1907 		ip->client->scriptEnvsize = 100;
1908 		if (ip->client->scriptEnv == NULL)
1909 			ip->client->scriptEnv =
1910 			    malloc(ip->client->scriptEnvsize * sizeof(char *));
1911 		if (ip->client->scriptEnv == NULL)
1912 			error("script_init: no memory for environment");
1913 
1914 		ip->client->scriptEnv[0] = strdup(CLIENT_PATH);
1915 		if (ip->client->scriptEnv[0] == NULL)
1916 			error("script_init: no memory for environment");
1917 
1918 		ip->client->scriptEnv[1] = NULL;
1919 
1920 		script_set_env(ip->client, "", "interface", ip->name);
1921 
1922 		if (medium)
1923 			script_set_env(ip->client, "", "medium", medium);
1924 
1925 		script_set_env(ip->client, "", "reason", reason);
1926 	}
1927 }
1928 
1929 void
1930 priv_script_write_params(char *prefix, struct client_lease *lease)
1931 {
1932 	struct interface_info *ip = ifi;
1933 	u_int8_t dbuf[1500], *dp = NULL;
1934 	int i, len;
1935 	char tbuf[128];
1936 
1937 	script_set_env(ip->client, prefix, "ip_address",
1938 	    piaddr(lease->address));
1939 
1940 	if (ip->client->config->default_actions[DHO_SUBNET_MASK] ==
1941 	    ACTION_SUPERSEDE) {
1942 		dp = ip->client->config->defaults[DHO_SUBNET_MASK].data;
1943 		len = ip->client->config->defaults[DHO_SUBNET_MASK].len;
1944 	} else {
1945 		dp = lease->options[DHO_SUBNET_MASK].data;
1946 		len = lease->options[DHO_SUBNET_MASK].len;
1947 	}
1948 	if (len && (len < sizeof(lease->address.iabuf))) {
1949 		struct iaddr netmask, subnet, broadcast;
1950 
1951 		memcpy(netmask.iabuf, dp, len);
1952 		netmask.len = len;
1953 		subnet = subnet_number(lease->address, netmask);
1954 		if (subnet.len) {
1955 			script_set_env(ip->client, prefix, "network_number",
1956 			    piaddr(subnet));
1957 			if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
1958 				broadcast = broadcast_addr(subnet, netmask);
1959 				if (broadcast.len)
1960 					script_set_env(ip->client, prefix,
1961 					    "broadcast_address",
1962 					    piaddr(broadcast));
1963 			}
1964 		}
1965 	}
1966 
1967 	if (lease->filename)
1968 		script_set_env(ip->client, prefix, "filename", lease->filename);
1969 	if (lease->server_name)
1970 		script_set_env(ip->client, prefix, "server_name",
1971 		    lease->server_name);
1972 	for (i = 0; i < 256; i++) {
1973 		len = 0;
1974 
1975 		if (ip->client->config->defaults[i].len) {
1976 			if (lease->options[i].len) {
1977 				switch (
1978 				    ip->client->config->default_actions[i]) {
1979 				case ACTION_DEFAULT:
1980 					dp = lease->options[i].data;
1981 					len = lease->options[i].len;
1982 					break;
1983 				case ACTION_SUPERSEDE:
1984 supersede:
1985 					dp = ip->client->
1986 						config->defaults[i].data;
1987 					len = ip->client->
1988 						config->defaults[i].len;
1989 					break;
1990 				case ACTION_PREPEND:
1991 					len = ip->client->
1992 					    config->defaults[i].len +
1993 					    lease->options[i].len;
1994 					if (len >= sizeof(dbuf)) {
1995 						warning("no space to %s %s",
1996 						    "prepend option",
1997 						    dhcp_options[i].name);
1998 						goto supersede;
1999 					}
2000 					dp = dbuf;
2001 					memcpy(dp,
2002 						ip->client->
2003 						config->defaults[i].data,
2004 						ip->client->
2005 						config->defaults[i].len);
2006 					memcpy(dp + ip->client->
2007 						config->defaults[i].len,
2008 						lease->options[i].data,
2009 						lease->options[i].len);
2010 					dp[len] = '\0';
2011 					break;
2012 				case ACTION_APPEND:
2013 					/*
2014 					 * When we append, we assume that we're
2015 					 * appending to text.  Some MS servers
2016 					 * include a NUL byte at the end of
2017 					 * the search string provided.
2018 					 */
2019 					len = ip->client->
2020 					    config->defaults[i].len +
2021 					    lease->options[i].len;
2022 					if (len >= sizeof(dbuf)) {
2023 						warning("no space to %s %s",
2024 						    "append option",
2025 						    dhcp_options[i].name);
2026 						goto supersede;
2027 					}
2028 					memcpy(dbuf,
2029 						lease->options[i].data,
2030 						lease->options[i].len);
2031 					for (dp = dbuf + lease->options[i].len;
2032 					    dp > dbuf; dp--, len--)
2033 						if (dp[-1] != '\0')
2034 							break;
2035 					memcpy(dp,
2036 						ip->client->
2037 						config->defaults[i].data,
2038 						ip->client->
2039 						config->defaults[i].len);
2040 					dp = dbuf;
2041 					dp[len] = '\0';
2042 				}
2043 			} else {
2044 				dp = ip->client->
2045 					config->defaults[i].data;
2046 				len = ip->client->
2047 					config->defaults[i].len;
2048 			}
2049 		} else if (lease->options[i].len) {
2050 			len = lease->options[i].len;
2051 			dp = lease->options[i].data;
2052 		} else {
2053 			len = 0;
2054 		}
2055 		if (len) {
2056 			char name[256];
2057 
2058 			if (dhcp_option_ev_name(name, sizeof(name),
2059 			    &dhcp_options[i]))
2060 				script_set_env(ip->client, prefix, name,
2061 				    pretty_print_option(i, dp, len, 0, 0));
2062 		}
2063 	}
2064 	snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
2065 	script_set_env(ip->client, prefix, "expiry", tbuf);
2066 }
2067 
2068 void
2069 script_write_params(char *prefix, struct client_lease *lease)
2070 {
2071 	size_t		 fn_len = 0, sn_len = 0, pr_len = 0;
2072 	struct imsg_hdr	 hdr;
2073 	struct buf	*buf;
2074 	int		 errs, i;
2075 
2076 	if (lease->filename != NULL)
2077 		fn_len = strlen(lease->filename);
2078 	if (lease->server_name != NULL)
2079 		sn_len = strlen(lease->server_name);
2080 	if (prefix != NULL)
2081 		pr_len = strlen(prefix);
2082 
2083 	hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
2084 	hdr.len = sizeof(hdr) + sizeof(struct client_lease) +
2085 	    sizeof(size_t) + fn_len + sizeof(size_t) + sn_len +
2086 	    sizeof(size_t) + pr_len;
2087 
2088 	for (i = 0; i < 256; i++)
2089 		hdr.len += sizeof(int) + lease->options[i].len;
2090 
2091 	scripttime = time(NULL);
2092 
2093 	if ((buf = buf_open(hdr.len)) == NULL)
2094 		error("buf_open: %m");
2095 
2096 	errs = 0;
2097 	errs += buf_add(buf, &hdr, sizeof(hdr));
2098 	errs += buf_add(buf, lease, sizeof(struct client_lease));
2099 	errs += buf_add(buf, &fn_len, sizeof(fn_len));
2100 	errs += buf_add(buf, lease->filename, fn_len);
2101 	errs += buf_add(buf, &sn_len, sizeof(sn_len));
2102 	errs += buf_add(buf, lease->server_name, sn_len);
2103 	errs += buf_add(buf, &pr_len, sizeof(pr_len));
2104 	errs += buf_add(buf, prefix, pr_len);
2105 
2106 	for (i = 0; i < 256; i++) {
2107 		errs += buf_add(buf, &lease->options[i].len,
2108 		    sizeof(lease->options[i].len));
2109 		errs += buf_add(buf, lease->options[i].data,
2110 		    lease->options[i].len);
2111 	}
2112 
2113 	if (errs)
2114 		error("buf_add: %m");
2115 
2116 	if (buf_close(privfd, buf) == -1)
2117 		error("buf_close: %m");
2118 }
2119 
2120 int
2121 script_go(void)
2122 {
2123 	struct imsg_hdr	 hdr;
2124 	struct buf	*buf;
2125 	int		 ret;
2126 
2127 	hdr.code = IMSG_SCRIPT_GO;
2128 	hdr.len = sizeof(struct imsg_hdr);
2129 
2130 	if ((buf = buf_open(hdr.len)) == NULL)
2131 		error("buf_open: %m");
2132 
2133 	if (buf_add(buf, &hdr, sizeof(hdr)))
2134 		error("buf_add: %m");
2135 
2136 	if (buf_close(privfd, buf) == -1)
2137 		error("buf_close: %m");
2138 
2139 	bzero(&hdr, sizeof(hdr));
2140 	buf_read(privfd, &hdr, sizeof(hdr));
2141 	if (hdr.code != IMSG_SCRIPT_GO_RET)
2142 		error("unexpected msg type %u", hdr.code);
2143 	if (hdr.len != sizeof(hdr) + sizeof(int))
2144 		error("received corrupted message");
2145 	buf_read(privfd, &ret, sizeof(ret));
2146 
2147 	scripttime = time(NULL);
2148 
2149 	return (ret);
2150 }
2151 
2152 int
2153 priv_script_go(void)
2154 {
2155 	char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI";
2156 	static char client_path[] = CLIENT_PATH;
2157 	struct interface_info *ip = ifi;
2158 	int pid, wpid, wstatus;
2159 
2160 	scripttime = time(NULL);
2161 
2162 	if (ip) {
2163 		scriptName = ip->client->config->script_name;
2164 		envp = ip->client->scriptEnv;
2165 	} else {
2166 		scriptName = top_level_config.script_name;
2167 		epp[0] = reason;
2168 		epp[1] = client_path;
2169 		epp[2] = NULL;
2170 		envp = epp;
2171 	}
2172 
2173 	argv[0] = scriptName;
2174 	argv[1] = NULL;
2175 
2176 	pid = fork();
2177 	if (pid < 0) {
2178 		error("fork: %m");
2179 		wstatus = 0;
2180 	} else if (pid) {
2181 		do {
2182 			wpid = wait(&wstatus);
2183 		} while (wpid != pid && wpid > 0);
2184 		if (wpid < 0) {
2185 			error("wait: %m");
2186 			wstatus = 0;
2187 		}
2188 	} else {
2189 		execve(scriptName, argv, envp);
2190 		error("execve (%s, ...): %m", scriptName);
2191 	}
2192 
2193 	if (ip)
2194 		script_flush_env(ip->client);
2195 
2196 	return (wstatus & 0xff);
2197 }
2198 
2199 void
2200 script_set_env(struct client_state *client, const char *prefix,
2201     const char *name, const char *value)
2202 {
2203 	int i, j, namelen;
2204 
2205 	namelen = strlen(name);
2206 
2207 	for (i = 0; client->scriptEnv[i]; i++)
2208 		if (strncmp(client->scriptEnv[i], name, namelen) == 0 &&
2209 		    client->scriptEnv[i][namelen] == '=')
2210 			break;
2211 
2212 	if (client->scriptEnv[i])
2213 		/* Reuse the slot. */
2214 		free(client->scriptEnv[i]);
2215 	else {
2216 		/* New variable.  Expand if necessary. */
2217 		if (i >= client->scriptEnvsize - 1) {
2218 			char **newscriptEnv;
2219 			int newscriptEnvsize = client->scriptEnvsize + 50;
2220 
2221 			newscriptEnv = realloc(client->scriptEnv,
2222 			    newscriptEnvsize);
2223 			if (newscriptEnv == NULL) {
2224 				free(client->scriptEnv);
2225 				client->scriptEnv = NULL;
2226 				client->scriptEnvsize = 0;
2227 				error("script_set_env: no memory for variable");
2228 			}
2229 			client->scriptEnv = newscriptEnv;
2230 			client->scriptEnvsize = newscriptEnvsize;
2231 		}
2232 		/* need to set the NULL pointer at end of array beyond
2233 		   the new slot. */
2234 		client->scriptEnv[i + 1] = NULL;
2235 	}
2236 	/* Allocate space and format the variable in the appropriate slot. */
2237 	client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 +
2238 	    strlen(value) + 1);
2239 	if (client->scriptEnv[i] == NULL)
2240 		error("script_set_env: no memory for variable assignment");
2241 
2242 	/* No `` or $() command substitution allowed in environment values! */
2243 	for (j=0; j < strlen(value); j++)
2244 		switch (value[j]) {
2245 		case '`':
2246 		case '$':
2247 			error("illegal character (%c) in value '%s'", value[j],
2248 			    value);
2249 			/* not reached */
2250 		}
2251 	snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
2252 	    1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
2253 }
2254 
2255 void
2256 script_flush_env(struct client_state *client)
2257 {
2258 	int i;
2259 
2260 	for (i = 0; client->scriptEnv[i]; i++) {
2261 		free(client->scriptEnv[i]);
2262 		client->scriptEnv[i] = NULL;
2263 	}
2264 	client->scriptEnvsize = 0;
2265 }
2266 
2267 int
2268 dhcp_option_ev_name(char *buf, size_t buflen, struct option *option)
2269 {
2270 	int i;
2271 
2272 	for (i = 0; option->name[i]; i++) {
2273 		if (i + 1 == buflen)
2274 			return 0;
2275 		if (option->name[i] == '-')
2276 			buf[i] = '_';
2277 		else
2278 			buf[i] = option->name[i];
2279 	}
2280 
2281 	buf[i] = 0;
2282 	return 1;
2283 }
2284 
2285 void
2286 go_daemon(void)
2287 {
2288 	static int state = 0;
2289 
2290 	if (no_daemon || state)
2291 		return;
2292 
2293 	state = 1;
2294 
2295 	/* Stop logging to stderr... */
2296 	log_perror = 0;
2297 
2298 	if (daemon(1, 0) == -1)
2299 		error("daemon");
2300 
2301 	/* we are chrooted, daemon(3) fails to open /dev/null */
2302 	if (nullfd != -1) {
2303 		dup2(nullfd, STDIN_FILENO);
2304 		dup2(nullfd, STDOUT_FILENO);
2305 		dup2(nullfd, STDERR_FILENO);
2306 		close(nullfd);
2307 		nullfd = -1;
2308 	}
2309 }
2310 
2311 int
2312 check_option(struct client_lease *l, int option)
2313 {
2314 	char *opbuf;
2315 	char *sbuf;
2316 
2317 	/* we use this, since this is what gets passed to dhclient-script */
2318 
2319 	opbuf = pretty_print_option(option, l->options[option].data,
2320 	    l->options[option].len, 0, 0);
2321 
2322 	sbuf = option_as_string(option, l->options[option].data,
2323 	    l->options[option].len);
2324 
2325 	switch (option) {
2326 	case DHO_SUBNET_MASK:
2327 	case DHO_TIME_SERVERS:
2328 	case DHO_NAME_SERVERS:
2329 	case DHO_ROUTERS:
2330 	case DHO_DOMAIN_NAME_SERVERS:
2331 	case DHO_LOG_SERVERS:
2332 	case DHO_COOKIE_SERVERS:
2333 	case DHO_LPR_SERVERS:
2334 	case DHO_IMPRESS_SERVERS:
2335 	case DHO_RESOURCE_LOCATION_SERVERS:
2336 	case DHO_SWAP_SERVER:
2337 	case DHO_BROADCAST_ADDRESS:
2338 	case DHO_NIS_SERVERS:
2339 	case DHO_NTP_SERVERS:
2340 	case DHO_NETBIOS_NAME_SERVERS:
2341 	case DHO_NETBIOS_DD_SERVER:
2342 	case DHO_FONT_SERVERS:
2343 	case DHO_DHCP_SERVER_IDENTIFIER:
2344 	case DHO_NISPLUS_SERVERS:
2345 	case DHO_MOBILE_IP_HOME_AGENT:
2346 	case DHO_SMTP_SERVER:
2347 	case DHO_POP_SERVER:
2348 	case DHO_NNTP_SERVER:
2349 	case DHO_WWW_SERVER:
2350 	case DHO_FINGER_SERVER:
2351 	case DHO_IRC_SERVER:
2352 	case DHO_STREETTALK_SERVER:
2353 	case DHO_STREETTALK_DA_SERVER:
2354 		if (!ipv4addrs(opbuf)) {
2355 			warning("Invalid IP address in option: %s", opbuf);
2356 			return (0);
2357 		}
2358 		return (1)  ;
2359 	case DHO_HOST_NAME:
2360 	case DHO_NIS_DOMAIN:
2361 	case DHO_NISPLUS_DOMAIN:
2362 	case DHO_TFTP_SERVER_NAME:
2363 		if (!res_hnok(sbuf)) {
2364 			warning("Bogus Host Name option %d: %s (%s)", option,
2365 			    sbuf, opbuf);
2366 			l->options[option].len = 0;
2367 			free(l->options[option].data);
2368 		}
2369 		return (1);
2370 	case DHO_DOMAIN_NAME:
2371 		if (!res_hnok(sbuf)) {
2372 			if (!check_search(sbuf)) {
2373 				warning("Bogus domain search list %d: %s (%s)",
2374 				    option, sbuf, opbuf);
2375 				l->options[option].len = 0;
2376 				free(l->options[option].data);
2377 			}
2378 		}
2379 		return (1);
2380 	case DHO_PAD:
2381 	case DHO_TIME_OFFSET:
2382 	case DHO_BOOT_SIZE:
2383 	case DHO_MERIT_DUMP:
2384 	case DHO_ROOT_PATH:
2385 	case DHO_EXTENSIONS_PATH:
2386 	case DHO_IP_FORWARDING:
2387 	case DHO_NON_LOCAL_SOURCE_ROUTING:
2388 	case DHO_POLICY_FILTER:
2389 	case DHO_MAX_DGRAM_REASSEMBLY:
2390 	case DHO_DEFAULT_IP_TTL:
2391 	case DHO_PATH_MTU_AGING_TIMEOUT:
2392 	case DHO_PATH_MTU_PLATEAU_TABLE:
2393 	case DHO_INTERFACE_MTU:
2394 	case DHO_ALL_SUBNETS_LOCAL:
2395 	case DHO_PERFORM_MASK_DISCOVERY:
2396 	case DHO_MASK_SUPPLIER:
2397 	case DHO_ROUTER_DISCOVERY:
2398 	case DHO_ROUTER_SOLICITATION_ADDRESS:
2399 	case DHO_STATIC_ROUTES:
2400 	case DHO_TRAILER_ENCAPSULATION:
2401 	case DHO_ARP_CACHE_TIMEOUT:
2402 	case DHO_IEEE802_3_ENCAPSULATION:
2403 	case DHO_DEFAULT_TCP_TTL:
2404 	case DHO_TCP_KEEPALIVE_INTERVAL:
2405 	case DHO_TCP_KEEPALIVE_GARBAGE:
2406 	case DHO_VENDOR_ENCAPSULATED_OPTIONS:
2407 	case DHO_NETBIOS_NODE_TYPE:
2408 	case DHO_NETBIOS_SCOPE:
2409 	case DHO_X_DISPLAY_MANAGER:
2410 	case DHO_DHCP_REQUESTED_ADDRESS:
2411 	case DHO_DHCP_LEASE_TIME:
2412 	case DHO_DHCP_OPTION_OVERLOAD:
2413 	case DHO_DHCP_MESSAGE_TYPE:
2414 	case DHO_DHCP_PARAMETER_REQUEST_LIST:
2415 	case DHO_DHCP_MESSAGE:
2416 	case DHO_DHCP_MAX_MESSAGE_SIZE:
2417 	case DHO_DHCP_RENEWAL_TIME:
2418 	case DHO_DHCP_REBINDING_TIME:
2419 	case DHO_DHCP_CLASS_IDENTIFIER:
2420 	case DHO_DHCP_CLIENT_IDENTIFIER:
2421 	case DHO_BOOTFILE_NAME:
2422 	case DHO_DHCP_USER_CLASS_ID:
2423 	case DHO_END:
2424 		return (1);
2425 	case DHO_CLASSLESS_ROUTES:
2426 		return (check_classless_option(l->options[option].data,
2427 		    l->options[option].len));
2428 	default:
2429 		warning("unknown dhcp option value 0x%x", option);
2430 		return (unknown_ok);
2431 	}
2432 }
2433 
2434 /* RFC 3442 The Classless Static Routes option checks */
2435 int
2436 check_classless_option(unsigned char *data, int len)
2437 {
2438 	int i = 0;
2439 	unsigned char width;
2440 	in_addr_t addr, mask;
2441 
2442 	if (len < 5) {
2443 		warning("Too small length: %d", len);
2444 		return (0);
2445 	}
2446 	while(i < len) {
2447 		width = data[i++];
2448 		if (width == 0) {
2449 			i += 4;
2450 			continue;
2451 		} else if (width < 9) {
2452 			addr =  (in_addr_t)(data[i] 	<< 24);
2453 			i += 1;
2454 		} else if (width < 17) {
2455 			addr =  (in_addr_t)(data[i] 	<< 24) +
2456 				(in_addr_t)(data[i + 1]	<< 16);
2457 			i += 2;
2458 		} else if (width < 25) {
2459 			addr =  (in_addr_t)(data[i] 	<< 24) +
2460 				(in_addr_t)(data[i + 1]	<< 16) +
2461 				(in_addr_t)(data[i + 2]	<< 8);
2462 			i += 3;
2463 		} else if (width < 33) {
2464 			addr =  (in_addr_t)(data[i] 	<< 24) +
2465 				(in_addr_t)(data[i + 1]	<< 16) +
2466 				(in_addr_t)(data[i + 2]	<< 8)  +
2467 				data[i + 3];
2468 			i += 4;
2469 		} else {
2470 			warning("Incorrect subnet width: %d", width);
2471 			return (0);
2472 		}
2473 		mask = (in_addr_t)(~0) << (32 - width);
2474 		addr = ntohl(addr);
2475 		mask = ntohl(mask);
2476 
2477 		/*
2478 		 * From RFC 3442:
2479 		 * ... After deriving a subnet number and subnet mask
2480 		 * from each destination descriptor, the DHCP client
2481 		 * MUST zero any bits in the subnet number where the
2482 		 * corresponding bit in the mask is zero...
2483 		 */
2484 		if ((addr & mask) != addr) {
2485 			addr &= mask;
2486 			data[i - 1] = (unsigned char)(
2487 				(addr >> (((32 - width)/8)*8)) & 0xFF);
2488 		}
2489 		i += 4;
2490 	}
2491 	if (i > len) {
2492 		warning("Incorrect data length: %d (must be %d)", len, i);
2493 		return (0);
2494 	}
2495 	return (1);
2496 }
2497 
2498 int
2499 res_hnok(const char *dn)
2500 {
2501 	int pch = PERIOD, ch = *dn++;
2502 
2503 	while (ch != '\0') {
2504 		int nch = *dn++;
2505 
2506 		if (periodchar(ch)) {
2507 			;
2508 		} else if (periodchar(pch)) {
2509 			if (!borderchar(ch))
2510 				return (0);
2511 		} else if (periodchar(nch) || nch == '\0') {
2512 			if (!borderchar(ch))
2513 				return (0);
2514 		} else {
2515 			if (!middlechar(ch))
2516 				return (0);
2517 		}
2518 		pch = ch, ch = nch;
2519 	}
2520 	return (1);
2521 }
2522 
2523 int
2524 check_search(const char *srch)
2525 {
2526         int pch = PERIOD, ch = *srch++;
2527 	int domains = 1;
2528 
2529 	/* 256 char limit re resolv.conf(5) */
2530 	if (strlen(srch) > 256)
2531 		return (0);
2532 
2533 	while (whitechar(ch))
2534 		ch = *srch++;
2535 
2536         while (ch != '\0') {
2537                 int nch = *srch++;
2538 
2539                 if (periodchar(ch) || whitechar(ch)) {
2540                         ;
2541                 } else if (periodchar(pch)) {
2542                         if (!borderchar(ch))
2543                                 return (0);
2544                 } else if (periodchar(nch) || nch == '\0') {
2545                         if (!borderchar(ch))
2546                                 return (0);
2547                 } else {
2548                         if (!middlechar(ch))
2549                                 return (0);
2550                 }
2551 		if (!whitechar(ch)) {
2552 			pch = ch;
2553 		} else {
2554 			while (whitechar(nch)) {
2555 				nch = *srch++;
2556 			}
2557 			if (nch != '\0')
2558 				domains++;
2559 			pch = PERIOD;
2560 		}
2561 		ch = nch;
2562         }
2563 	/* 6 domain limit re resolv.conf(5) */
2564 	if (domains > 6)
2565 		return (0);
2566         return (1);
2567 }
2568 
2569 /* Does buf consist only of dotted decimal ipv4 addrs?
2570  * return how many if so,
2571  * otherwise, return 0
2572  */
2573 int
2574 ipv4addrs(char * buf)
2575 {
2576 	struct in_addr jnk;
2577 	int count = 0;
2578 
2579 	while (inet_aton(buf, &jnk) == 1){
2580 		count++;
2581 		while (periodchar(*buf) || digitchar(*buf))
2582 			buf++;
2583 		if (*buf == '\0')
2584 			return (count);
2585 		while (*buf ==  ' ')
2586 			buf++;
2587 	}
2588 	return (0);
2589 }
2590 
2591 
2592 char *
2593 option_as_string(unsigned int code, unsigned char *data, int len)
2594 {
2595 	static char optbuf[32768]; /* XXX */
2596 	char *op = optbuf;
2597 	int opleft = sizeof(optbuf);
2598 	unsigned char *dp = data;
2599 
2600 	if (code > 255)
2601 		error("option_as_string: bad code %d", code);
2602 
2603 	for (; dp < data + len; dp++) {
2604 		if (!isascii(*dp) || !isprint(*dp)) {
2605 			if (dp + 1 != data + len || *dp != 0) {
2606 				snprintf(op, opleft, "\\%03o", *dp);
2607 				op += 4;
2608 				opleft -= 4;
2609 			}
2610 		} else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
2611 		    *dp == '`' || *dp == '\\') {
2612 			*op++ = '\\';
2613 			*op++ = *dp;
2614 			opleft -= 2;
2615 		} else {
2616 			*op++ = *dp;
2617 			opleft--;
2618 		}
2619 	}
2620 	if (opleft < 1)
2621 		goto toobig;
2622 	*op = 0;
2623 	return optbuf;
2624 toobig:
2625 	warning("dhcp option too large");
2626 	return "<error>";
2627 }
2628 
2629 int
2630 fork_privchld(int fd, int fd2)
2631 {
2632 	struct pollfd pfd[1];
2633 	int nfds;
2634 
2635 	switch (fork()) {
2636 	case -1:
2637 		error("cannot fork");
2638 	case 0:
2639 		break;
2640 	default:
2641 		return (0);
2642 	}
2643 
2644 	setproctitle("%s [priv]", ifi->name);
2645 
2646 	setsid();
2647 	dup2(nullfd, STDIN_FILENO);
2648 	dup2(nullfd, STDOUT_FILENO);
2649 	dup2(nullfd, STDERR_FILENO);
2650 	close(nullfd);
2651 	close(fd2);
2652 
2653 	for (;;) {
2654 		pfd[0].fd = fd;
2655 		pfd[0].events = POLLIN;
2656 		if ((nfds = poll(pfd, 1, INFTIM)) == -1)
2657 			if (errno != EINTR)
2658 				error("poll error");
2659 
2660 		if (nfds == 0 || !(pfd[0].revents & POLLIN))
2661 			continue;
2662 
2663 		dispatch_imsg(fd);
2664 	}
2665 }
2666