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