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