1 /* $OpenBSD: dhclient.c,v 1.63 2005/02/06 17:10:13 krw Exp $ */
4 * Copyright 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 1995, 1996, 1997, 1998, 1999
6 * The Internet Software Consortium. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of The Internet Software Consortium nor the names
18 * of its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
22 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * This software has been written for the Internet Software Consortium
36 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
37 * Enterprises. To learn more about the Internet Software Consortium,
38 * see ``http://www.vix.com/isc''. To learn more about Vixie
39 * Enterprises, see ``http://www.vix.com''.
41 * This client was substantially modified and enhanced by Elliot Poger
42 * for use on Linux while he was working on the MosquitoNet project at
45 * The current version owes much to Elliot's Linux enhancements, but
46 * was substantially reorganized and partially rewritten by Ted Lemon
47 * so as to use the same networking framework that the Internet Software
48 * Consortium DHCP server uses. Much system-specific configuration code
49 * was moved into a shell script so that as support for more operating
50 * systems is added, it will not be necessary to port and maintain
51 * system-specific configuration code to these operating systems - instead,
52 * the shell script can invoke the native tools to accomplish the same
56 #include <sys/cdefs.h>
57 __FBSDID("$FreeBSD$");
62 #include <net80211/ieee80211_freebsd.h>
64 #ifndef _PATH_VAREMPTY
65 #define _PATH_VAREMPTY "/var/empty"
69 #define hyphenchar(c) ((c) == 0x2d)
70 #define bslashchar(c) ((c) == 0x5c)
71 #define periodchar(c) ((c) == PERIOD)
72 #define asterchar(c) ((c) == 0x2a)
73 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
74 ((c) >= 0x61 && (c) <= 0x7a))
75 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
76 #define whitechar(c) ((c) == ' ' || (c) == '\t')
78 #define borderchar(c) (alphachar(c) || digitchar(c))
79 #define middlechar(c) (borderchar(c) || hyphenchar(c))
80 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
82 #define CLIENT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
85 time_t default_lease_time = 43200; /* 12 hours... */
87 char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
88 char *path_dhclient_db = NULL;
94 struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
95 struct in_addr inaddr_any;
96 struct sockaddr_in sockaddr_broadcast;
98 char *path_dhclient_pidfile;
99 struct pidfh *pidfile;
102 * ASSERT_STATE() does nothing now; it used to be
103 * assert (state_is == state_shouldbe).
105 #define ASSERT_STATE(state_is, state_shouldbe) {}
107 #define TIME_MAX 2147483647
114 struct interface_info *ifi;
116 int findproto(char *, int);
117 struct sockaddr *get_ifa(char *, int);
118 void routehandler(struct protocol *);
120 int check_option(struct client_lease *l, int option);
121 int check_classless_option(unsigned char *data, int len);
122 int ipv4addrs(char * buf);
123 int res_hnok(const char *dn);
124 int check_search(const char *srch);
125 char *option_as_string(unsigned int code, unsigned char *data, int len);
126 int fork_privchld(int, int);
129 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
130 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
132 static time_t scripttime;
135 findproto(char *cp, int n)
142 for (i = 1; i; i <<= 1) {
144 sa = (struct sockaddr *)cp;
150 if (sa->sa_family == AF_INET)
152 if (sa->sa_family == AF_INET6)
165 get_ifa(char *cp, int n)
172 for (i = 1; i; i <<= 1)
174 sa = (struct sockaddr *)cp;
183 struct iaddr defaddr = { 4 };
189 struct interface_info *ifi = arg;
192 * Clear existing state.
194 if (ifi->client->active != NULL) {
195 script_init("EXPIRE", NULL);
196 script_write_params("old_",
197 ifi->client->active);
198 if (ifi->client->alias)
199 script_write_params("alias_",
203 ifi->client->state = S_INIT;
208 routehandler(struct protocol *p)
210 char msg[2048], *addr;
211 struct rt_msghdr *rtm;
212 struct if_msghdr *ifm;
213 struct ifa_msghdr *ifam;
214 struct if_announcemsghdr *ifan;
215 struct ieee80211_join_event *jev;
216 struct client_lease *l;
217 time_t t = time(NULL);
223 n = read(routefd, &msg, sizeof(msg));
224 rtm = (struct rt_msghdr *)msg;
225 if (n < sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen ||
226 rtm->rtm_version != RTM_VERSION)
229 switch (rtm->rtm_type) {
232 ifam = (struct ifa_msghdr *)rtm;
234 if (ifam->ifam_index != ifi->index)
236 if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
238 if (scripttime == 0 || t < scripttime + 10)
241 sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs);
245 if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf))
246 error("king bula sez: len mismatch");
247 memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len);
248 if (addr_eq(a, defaddr))
251 for (l = ifi->client->active; l != NULL; l = l->next)
252 if (addr_eq(a, l->address))
255 if (l == NULL) /* added/deleted addr is not the one we set */
258 addr = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
259 if (rtm->rtm_type == RTM_NEWADDR) {
261 * XXX: If someone other than us adds our address,
262 * should we assume they are taking over from us,
263 * delete the lease record, and exit without modifying
266 warning("My address (%s) was re-added", addr);
268 warning("My address (%s) was deleted, dhclient exiting",
274 ifm = (struct if_msghdr *)rtm;
275 if (ifm->ifm_index != ifi->index)
277 if ((rtm->rtm_flags & RTF_UP) == 0) {
278 warning("Interface %s is down, dhclient exiting",
282 linkstat = interface_link_status(ifi->name);
283 if (linkstat != ifi->linkstat) {
284 debug("%s link state %s -> %s", ifi->name,
285 ifi->linkstat ? "up" : "down",
286 linkstat ? "up" : "down");
287 ifi->linkstat = linkstat;
293 ifan = (struct if_announcemsghdr *)rtm;
294 if (ifan->ifan_what == IFAN_DEPARTURE &&
295 ifan->ifan_index == ifi->index) {
296 warning("Interface %s is gone, dhclient exiting",
302 ifan = (struct if_announcemsghdr *)rtm;
303 if (ifan->ifan_index != ifi->index)
305 switch (ifan->ifan_what) {
306 case RTM_IEEE80211_ASSOC:
307 case RTM_IEEE80211_REASSOC:
309 * Use assoc/reassoc event to kick state machine
310 * in case we roam. Otherwise fall back to the
311 * normal state machine just like a wired network.
313 jev = (struct ieee80211_join_event *) &ifan[1];
314 if (memcmp(curbssid, jev->iev_addr, 6)) {
318 memcpy(curbssid, jev->iev_addr, 6);
328 script_init("FAIL", NULL);
329 if (ifi->client->alias)
330 script_write_params("alias_", ifi->client->alias);
333 pidfile_remove(pidfile);
338 main(int argc, char *argv[])
340 extern char *__progname;
341 int ch, fd, quiet = 0, i = 0;
343 int immediate_daemon = 0;
347 /* Initially, log errors to stderr as well as to syslogd. */
348 openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
349 setlogmask(LOG_UPTO(LOG_DEBUG));
351 while ((ch = getopt(argc, argv, "bc:dl:p:qu")) != -1)
354 immediate_daemon = 1;
357 path_dhclient_conf = optarg;
363 path_dhclient_db = optarg;
366 path_dhclient_pidfile = optarg;
384 if (path_dhclient_pidfile == NULL) {
385 asprintf(&path_dhclient_pidfile,
386 "%sdhclient.%s.pid", _PATH_VARRUN, *argv);
387 if (path_dhclient_pidfile == NULL)
390 pidfile = pidfile_open(path_dhclient_pidfile, 0600, &otherpid);
391 if (pidfile == NULL) {
393 error("dhclient already running, pid: %d.", otherpid);
395 error("dhclient already running.");
396 warning("Cannot open or create pidfile: %m");
399 if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL)
401 if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
402 error("Interface name too long");
403 if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s",
404 _PATH_DHCLIENT_DB, ifi->name) == -1)
413 memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
414 sockaddr_broadcast.sin_family = AF_INET;
415 sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
416 sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
417 sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast);
418 inaddr_any.s_addr = INADDR_ANY;
422 /* The next bit is potentially very time-consuming, so write out
423 the pidfile right away. We will write it out again with the
424 correct pid after daemonizing. */
426 pidfile_write(pidfile);
428 if (!interface_link_status(ifi->name)) {
429 fprintf(stderr, "%s: no link ...", ifi->name);
432 while (!interface_link_status(ifi->name)) {
433 fprintf(stderr, ".");
436 fprintf(stderr, " giving up\n");
441 fprintf(stderr, " got link\n");
445 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
446 error("cannot open %s: %m", _PATH_DEVNULL);
448 if ((pw = getpwnam("_dhcp")) == NULL) {
449 warning("no such user: _dhcp, falling back to \"nobody\"");
450 if ((pw = getpwnam("nobody")) == NULL)
451 error("no such user: nobody");
454 if (pipe(pipe_fd) == -1)
457 fork_privchld(pipe_fd[0], pipe_fd[1]);
462 if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
463 error("can't open and lock %s: %m", path_dhclient_db);
464 read_client_leases();
465 rewrite_client_leases();
468 priv_script_init("PREINIT", NULL);
469 if (ifi->client->alias)
470 priv_script_write_params("alias_", ifi->client->alias);
473 if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
474 add_protocol("AF_ROUTE", routefd, routehandler, ifi);
476 /* set up the interface */
477 discover_interfaces(ifi);
479 if (chroot(_PATH_VAREMPTY) == -1)
481 if (chdir("/") == -1)
482 error("chdir(\"/\")");
484 if (setgroups(1, &pw->pw_gid) ||
485 setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
486 seteuid(pw->pw_uid) || setuid(pw->pw_uid))
487 error("can't drop privileges: %m");
491 setproctitle("%s", ifi->name);
493 if (immediate_daemon)
496 ifi->client->state = S_INIT;
499 bootp_packet_handler = do_packet;
510 extern char *__progname;
512 fprintf(stderr, "usage: %s [-bdqu] ", __progname);
513 fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
520 * Each routine is called from the dhclient_state_machine() in one of
522 * -> entering INIT state
523 * -> recvpacket_flag == 0: timeout in this state
524 * -> otherwise: received a packet in this state
526 * Return conditions as handled by dhclient_state_machine():
527 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
528 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
529 * Returns 0: finish the nap which was interrupted for no good reason.
531 * Several per-interface variables are used to keep track of the process:
532 * active_lease: the lease that is being used on the interface
533 * (null pointer if not configured yet).
534 * offered_leases: leases corresponding to DHCPOFFER messages that have
535 * been sent to us by DHCP servers.
536 * acked_leases: leases corresponding to DHCPACK messages that have been
537 * sent to us by DHCP servers.
538 * sendpacket: DHCP packet we're trying to send.
539 * destination: IP address to send sendpacket to
540 * In addition, there are several relevant per-lease variables.
541 * T1_expiry, T2_expiry, lease_expiry: lease milestones
542 * In the active lease, these control the process of renewing the lease;
543 * In leases on the acked_leases list, this simply determines when we
544 * can no longer legitimately use the lease.
548 state_reboot(void *ipp)
550 struct interface_info *ip = ipp;
552 /* If we don't remember an active lease, go straight to INIT. */
553 if (!ip->client->active || ip->client->active->is_bootp) {
558 /* We are in the rebooting state. */
559 ip->client->state = S_REBOOTING;
561 /* make_request doesn't initialize xid because it normally comes
562 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
563 so pick an xid now. */
564 ip->client->xid = arc4random();
566 /* Make a DHCPREQUEST packet, and set appropriate per-interface
568 make_request(ip, ip->client->active);
569 ip->client->destination = iaddr_broadcast;
570 ip->client->first_sending = cur_time;
571 ip->client->interval = ip->client->config->initial_interval;
573 /* Zap the medium list... */
574 ip->client->medium = NULL;
576 /* Send out the first DHCPREQUEST packet. */
581 * Called when a lease has completely expired and we've
582 * been unable to renew it.
585 state_init(void *ipp)
587 struct interface_info *ip = ipp;
589 ASSERT_STATE(state, S_INIT);
591 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
593 make_discover(ip, ip->client->active);
594 ip->client->xid = ip->client->packet.xid;
595 ip->client->destination = iaddr_broadcast;
596 ip->client->state = S_SELECTING;
597 ip->client->first_sending = cur_time;
598 ip->client->interval = ip->client->config->initial_interval;
600 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
606 * state_selecting is called when one or more DHCPOFFER packets
607 * have been received and a configurable period of time has passed.
610 state_selecting(void *ipp)
612 struct interface_info *ip = ipp;
613 struct client_lease *lp, *next, *picked;
615 ASSERT_STATE(state, S_SELECTING);
617 /* Cancel state_selecting and send_discover timeouts, since either
618 one could have got us here. */
619 cancel_timeout(state_selecting, ip);
620 cancel_timeout(send_discover, ip);
622 /* We have received one or more DHCPOFFER packets. Currently,
623 the only criterion by which we judge leases is whether or
624 not we get a response when we arp for them. */
626 for (lp = ip->client->offered_leases; lp; lp = next) {
629 /* Check to see if we got an ARPREPLY for the address
630 in this particular lease. */
632 script_init("ARPCHECK", lp->medium);
633 script_write_params("check_", lp);
635 /* If the ARPCHECK code detects another
636 machine using the offered address, it exits
637 nonzero. We need to send a DHCPDECLINE and
640 make_decline(ip, lp);
648 free_client_lease(lp);
651 ip->client->offered_leases = NULL;
653 /* If we just tossed all the leases we were offered, go back
656 ip->client->state = S_INIT;
661 /* If it was a BOOTREPLY, we can just take the address right now. */
662 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
663 ip->client->new = picked;
665 /* Make up some lease expiry times
666 XXX these should be configurable. */
667 ip->client->new->expiry = cur_time + 12000;
668 ip->client->new->renewal += cur_time + 8000;
669 ip->client->new->rebind += cur_time + 10000;
671 ip->client->state = S_REQUESTING;
673 /* Bind to the address we received. */
678 /* Go to the REQUESTING state. */
679 ip->client->destination = iaddr_broadcast;
680 ip->client->state = S_REQUESTING;
681 ip->client->first_sending = cur_time;
682 ip->client->interval = ip->client->config->initial_interval;
684 /* Make a DHCPREQUEST packet from the lease we picked. */
685 make_request(ip, picked);
686 ip->client->xid = ip->client->packet.xid;
688 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
689 free_client_lease(picked);
691 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
695 /* state_requesting is called when we receive a DHCPACK message after
696 having sent out one or more DHCPREQUEST packets. */
699 dhcpack(struct packet *packet)
701 struct interface_info *ip = packet->interface;
702 struct client_lease *lease;
704 /* If we're not receptive to an offer right now, or if the offer
705 has an unrecognizable transaction id, then just drop it. */
706 if (packet->interface->client->xid != packet->raw->xid ||
707 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
708 (memcmp(packet->interface->hw_address.haddr,
709 packet->raw->chaddr, packet->raw->hlen)))
712 if (ip->client->state != S_REBOOTING &&
713 ip->client->state != S_REQUESTING &&
714 ip->client->state != S_RENEWING &&
715 ip->client->state != S_REBINDING)
718 note("DHCPACK from %s", piaddr(packet->client_addr));
720 lease = packet_to_lease(packet);
722 note("packet_to_lease failed.");
726 ip->client->new = lease;
728 /* Stop resending DHCPREQUEST. */
729 cancel_timeout(send_request, ip);
731 /* Figure out the lease time. */
732 if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
733 ip->client->new->expiry = getULong(
734 ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
736 ip->client->new->expiry = default_lease_time;
737 /* A number that looks negative here is really just very large,
738 because the lease expiry offset is unsigned. */
739 if (ip->client->new->expiry < 0)
740 ip->client->new->expiry = TIME_MAX;
741 /* XXX should be fixed by resetting the client state */
742 if (ip->client->new->expiry < 60)
743 ip->client->new->expiry = 60;
745 /* Take the server-provided renewal time if there is one;
746 otherwise figure it out according to the spec. */
747 if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
748 ip->client->new->renewal = getULong(
749 ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
751 ip->client->new->renewal = ip->client->new->expiry / 2;
753 /* Same deal with the rebind time. */
754 if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
755 ip->client->new->rebind = getULong(
756 ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
758 ip->client->new->rebind = ip->client->new->renewal +
759 ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
761 ip->client->new->expiry += cur_time;
762 /* Lease lengths can never be negative. */
763 if (ip->client->new->expiry < cur_time)
764 ip->client->new->expiry = TIME_MAX;
765 ip->client->new->renewal += cur_time;
766 if (ip->client->new->renewal < cur_time)
767 ip->client->new->renewal = TIME_MAX;
768 ip->client->new->rebind += cur_time;
769 if (ip->client->new->rebind < cur_time)
770 ip->client->new->rebind = TIME_MAX;
776 bind_lease(struct interface_info *ip)
778 /* Remember the medium. */
779 ip->client->new->medium = ip->client->medium;
781 /* Write out the new lease. */
782 write_client_lease(ip, ip->client->new, 0);
784 /* Run the client script with the new parameters. */
785 script_init((ip->client->state == S_REQUESTING ? "BOUND" :
786 (ip->client->state == S_RENEWING ? "RENEW" :
787 (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))),
788 ip->client->new->medium);
789 if (ip->client->active && ip->client->state != S_REBOOTING)
790 script_write_params("old_", ip->client->active);
791 script_write_params("new_", ip->client->new);
792 if (ip->client->alias)
793 script_write_params("alias_", ip->client->alias);
796 /* Replace the old active lease with the new one. */
797 if (ip->client->active)
798 free_client_lease(ip->client->active);
799 ip->client->active = ip->client->new;
800 ip->client->new = NULL;
802 /* Set up a timeout to start the renewal process. */
803 add_timeout(ip->client->active->renewal, state_bound, ip);
805 note("bound to %s -- renewal in %d seconds.",
806 piaddr(ip->client->active->address),
807 (int)(ip->client->active->renewal - cur_time));
808 ip->client->state = S_BOUND;
809 reinitialize_interfaces();
814 * state_bound is called when we've successfully bound to a particular
815 * lease, but the renewal time on that lease has expired. We are
816 * expected to unicast a DHCPREQUEST to the server that gave us our
820 state_bound(void *ipp)
822 struct interface_info *ip = ipp;
824 ASSERT_STATE(state, S_BOUND);
826 /* T1 has expired. */
827 make_request(ip, ip->client->active);
828 ip->client->xid = ip->client->packet.xid;
830 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
831 memcpy(ip->client->destination.iabuf, ip->client->active->
832 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
833 ip->client->destination.len = 4;
835 ip->client->destination = iaddr_broadcast;
837 ip->client->first_sending = cur_time;
838 ip->client->interval = ip->client->config->initial_interval;
839 ip->client->state = S_RENEWING;
841 /* Send the first packet immediately. */
846 bootp(struct packet *packet)
848 struct iaddrlist *ap;
850 if (packet->raw->op != BOOTREPLY)
853 /* If there's a reject list, make sure this packet's sender isn't
855 for (ap = packet->interface->client->config->reject_list;
857 if (addr_eq(packet->client_addr, ap->addr)) {
858 note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
866 dhcp(struct packet *packet)
868 struct iaddrlist *ap;
869 void (*handler)(struct packet *);
872 switch (packet->packet_type) {
889 /* If there's a reject list, make sure this packet's sender isn't
891 for (ap = packet->interface->client->config->reject_list;
893 if (addr_eq(packet->client_addr, ap->addr)) {
894 note("%s from %s rejected.", type, piaddr(ap->addr));
902 dhcpoffer(struct packet *packet)
904 struct interface_info *ip = packet->interface;
905 struct client_lease *lease, *lp;
907 int arp_timeout_needed, stop_selecting;
908 char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
909 "DHCPOFFER" : "BOOTREPLY";
911 /* If we're not receptive to an offer right now, or if the offer
912 has an unrecognizable transaction id, then just drop it. */
913 if (ip->client->state != S_SELECTING ||
914 packet->interface->client->xid != packet->raw->xid ||
915 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
916 (memcmp(packet->interface->hw_address.haddr,
917 packet->raw->chaddr, packet->raw->hlen)))
920 note("%s from %s", name, piaddr(packet->client_addr));
923 /* If this lease doesn't supply the minimum required parameters,
925 for (i = 0; ip->client->config->required_options[i]; i++) {
926 if (!packet->options[ip->client->config->
927 required_options[i]].len) {
928 note("%s isn't satisfactory.", name);
933 /* If we've already seen this lease, don't record it again. */
934 for (lease = ip->client->offered_leases;
935 lease; lease = lease->next) {
936 if (lease->address.len == sizeof(packet->raw->yiaddr) &&
937 !memcmp(lease->address.iabuf,
938 &packet->raw->yiaddr, lease->address.len)) {
939 debug("%s already seen.", name);
944 lease = packet_to_lease(packet);
946 note("packet_to_lease failed.");
950 /* If this lease was acquired through a BOOTREPLY, record that
952 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
955 /* Record the medium under which this lease was offered. */
956 lease->medium = ip->client->medium;
958 /* Send out an ARP Request for the offered IP address. */
959 script_init("ARPSEND", lease->medium);
960 script_write_params("check_", lease);
961 /* If the script can't send an ARP request without waiting,
962 we'll be waiting when we do the ARPCHECK, so don't wait now. */
964 arp_timeout_needed = 0;
966 arp_timeout_needed = 2;
968 /* Figure out when we're supposed to stop selecting. */
970 ip->client->first_sending + ip->client->config->select_interval;
972 /* If this is the lease we asked for, put it at the head of the
973 list, and don't mess with the arp request timeout. */
974 if (lease->address.len == ip->client->requested_address.len &&
975 !memcmp(lease->address.iabuf,
976 ip->client->requested_address.iabuf,
977 ip->client->requested_address.len)) {
978 lease->next = ip->client->offered_leases;
979 ip->client->offered_leases = lease;
981 /* If we already have an offer, and arping for this
982 offer would take us past the selection timeout,
983 then don't extend the timeout - just hope for the
985 if (ip->client->offered_leases &&
986 (cur_time + arp_timeout_needed) > stop_selecting)
987 arp_timeout_needed = 0;
989 /* Put the lease at the end of the list. */
991 if (!ip->client->offered_leases)
992 ip->client->offered_leases = lease;
994 for (lp = ip->client->offered_leases; lp->next;
1001 /* If we're supposed to stop selecting before we've had time
1002 to wait for the ARPREPLY, add some delay to wait for
1004 if (stop_selecting - cur_time < arp_timeout_needed)
1005 stop_selecting = cur_time + arp_timeout_needed;
1007 /* If the selecting interval has expired, go immediately to
1008 state_selecting(). Otherwise, time out into
1009 state_selecting at the select interval. */
1010 if (stop_selecting <= 0)
1011 state_selecting(ip);
1013 add_timeout(stop_selecting, state_selecting, ip);
1014 cancel_timeout(send_discover, ip);
1018 /* Allocate a client_lease structure and initialize it from the parameters
1019 in the specified packet. */
1021 struct client_lease *
1022 packet_to_lease(struct packet *packet)
1024 struct client_lease *lease;
1027 lease = malloc(sizeof(struct client_lease));
1030 warning("dhcpoffer: no memory to record lease.");
1034 memset(lease, 0, sizeof(*lease));
1036 /* Copy the lease options. */
1037 for (i = 0; i < 256; i++) {
1038 if (packet->options[i].len) {
1039 lease->options[i].data =
1040 malloc(packet->options[i].len + 1);
1041 if (!lease->options[i].data) {
1042 warning("dhcpoffer: no memory for option %d", i);
1043 free_client_lease(lease);
1046 memcpy(lease->options[i].data,
1047 packet->options[i].data,
1048 packet->options[i].len);
1049 lease->options[i].len =
1050 packet->options[i].len;
1051 lease->options[i].data[lease->options[i].len] =
1054 if (!check_option(lease,i)) {
1055 /* ignore a bogus lease offer */
1056 warning("Invalid lease option - ignoring offer");
1057 free_client_lease(lease);
1063 lease->address.len = sizeof(packet->raw->yiaddr);
1064 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
1066 /* If the server name was filled out, copy it.
1067 Do not attempt to validate the server name as a host name.
1068 RFC 2131 merely states that sname is NUL-terminated (which do
1069 do not assume) and that it is the server's host name. Since
1070 the ISC client and server allow arbitrary characters, we do
1072 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1073 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
1074 packet->raw->sname[0]) {
1075 lease->server_name = malloc(DHCP_SNAME_LEN + 1);
1076 if (!lease->server_name) {
1077 warning("dhcpoffer: no memory for server name.");
1078 free_client_lease(lease);
1081 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
1082 lease->server_name[DHCP_SNAME_LEN]='\0';
1085 /* Ditto for the filename. */
1086 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1087 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
1088 packet->raw->file[0]) {
1089 /* Don't count on the NUL terminator. */
1090 lease->filename = malloc(DHCP_FILE_LEN + 1);
1091 if (!lease->filename) {
1092 warning("dhcpoffer: no memory for filename.");
1093 free_client_lease(lease);
1096 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
1097 lease->filename[DHCP_FILE_LEN]='\0';
1103 dhcpnak(struct packet *packet)
1105 struct interface_info *ip = packet->interface;
1107 /* If we're not receptive to an offer right now, or if the offer
1108 has an unrecognizable transaction id, then just drop it. */
1109 if (packet->interface->client->xid != packet->raw->xid ||
1110 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
1111 (memcmp(packet->interface->hw_address.haddr,
1112 packet->raw->chaddr, packet->raw->hlen)))
1115 if (ip->client->state != S_REBOOTING &&
1116 ip->client->state != S_REQUESTING &&
1117 ip->client->state != S_RENEWING &&
1118 ip->client->state != S_REBINDING)
1121 note("DHCPNAK from %s", piaddr(packet->client_addr));
1123 if (!ip->client->active) {
1124 note("DHCPNAK with no active lease.\n");
1128 free_client_lease(ip->client->active);
1129 ip->client->active = NULL;
1131 /* Stop sending DHCPREQUEST packets... */
1132 cancel_timeout(send_request, ip);
1134 ip->client->state = S_INIT;
1138 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1139 one after the right interval has expired. If we don't get an offer by
1140 the time we reach the panic interval, call the panic function. */
1143 send_discover(void *ipp)
1145 struct interface_info *ip = ipp;
1146 int interval, increase = 1;
1148 /* Figure out how long it's been since we started transmitting. */
1149 interval = cur_time - ip->client->first_sending;
1151 /* If we're past the panic timeout, call the script and tell it
1152 we haven't found anything for this interface yet. */
1153 if (interval > ip->client->config->timeout) {
1158 /* If we're selecting media, try the whole list before doing
1159 the exponential backoff, but if we've already received an
1160 offer, stop looping, because we obviously have it right. */
1161 if (!ip->client->offered_leases &&
1162 ip->client->config->media) {
1165 if (ip->client->medium) {
1166 ip->client->medium = ip->client->medium->next;
1169 if (!ip->client->medium) {
1171 error("No valid media types for %s!", ip->name);
1172 ip->client->medium = ip->client->config->media;
1176 note("Trying medium \"%s\" %d", ip->client->medium->string,
1178 script_init("MEDIUM", ip->client->medium);
1184 * If we're supposed to increase the interval, do so. If it's
1185 * currently zero (i.e., we haven't sent any packets yet), set
1186 * it to one; otherwise, add to it a random number between zero
1187 * and two times itself. On average, this means that it will
1188 * double with every transmission.
1191 if (!ip->client->interval)
1192 ip->client->interval =
1193 ip->client->config->initial_interval;
1195 ip->client->interval += (arc4random() >> 2) %
1196 (2 * ip->client->interval);
1199 /* Don't backoff past cutoff. */
1200 if (ip->client->interval >
1201 ip->client->config->backoff_cutoff)
1202 ip->client->interval =
1203 ((ip->client->config->backoff_cutoff / 2)
1204 + ((arc4random() >> 2) %
1205 ip->client->config->backoff_cutoff));
1206 } else if (!ip->client->interval)
1207 ip->client->interval =
1208 ip->client->config->initial_interval;
1210 /* If the backoff would take us to the panic timeout, just use that
1212 if (cur_time + ip->client->interval >
1213 ip->client->first_sending + ip->client->config->timeout)
1214 ip->client->interval =
1215 (ip->client->first_sending +
1216 ip->client->config->timeout) - cur_time + 1;
1218 /* Record the number of seconds since we started sending. */
1219 if (interval < 65536)
1220 ip->client->packet.secs = htons(interval);
1222 ip->client->packet.secs = htons(65535);
1223 ip->client->secs = ip->client->packet.secs;
1225 note("DHCPDISCOVER on %s to %s port %d interval %d",
1226 ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
1227 ntohs(sockaddr_broadcast.sin_port),
1228 (int)ip->client->interval);
1230 /* Send out a packet. */
1231 (void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
1232 inaddr_any, &sockaddr_broadcast, NULL);
1234 add_timeout(cur_time + ip->client->interval, send_discover, ip);
1238 * state_panic gets called if we haven't received any offers in a preset
1239 * amount of time. When this happens, we try to use existing leases
1240 * that haven't yet expired, and failing that, we call the client script
1241 * and hope it can do something.
1244 state_panic(void *ipp)
1246 struct interface_info *ip = ipp;
1247 struct client_lease *loop = ip->client->active;
1248 struct client_lease *lp;
1250 note("No DHCPOFFERS received.");
1252 /* We may not have an active lease, but we may have some
1253 predefined leases that we can try. */
1254 if (!ip->client->active && ip->client->leases)
1257 /* Run through the list of leases and see if one can be used. */
1258 while (ip->client->active) {
1259 if (ip->client->active->expiry > cur_time) {
1260 note("Trying recorded lease %s",
1261 piaddr(ip->client->active->address));
1262 /* Run the client script with the existing
1264 script_init("TIMEOUT",
1265 ip->client->active->medium);
1266 script_write_params("new_", ip->client->active);
1267 if (ip->client->alias)
1268 script_write_params("alias_",
1271 /* If the old lease is still good and doesn't
1272 yet need renewal, go into BOUND state and
1273 timeout at the renewal time. */
1276 ip->client->active->renewal) {
1277 ip->client->state = S_BOUND;
1278 note("bound: renewal in %d seconds.",
1279 (int)(ip->client->active->renewal -
1282 ip->client->active->renewal,
1285 ip->client->state = S_BOUND;
1286 note("bound: immediate renewal.");
1289 reinitialize_interfaces();
1295 /* If there are no other leases, give up. */
1296 if (!ip->client->leases) {
1297 ip->client->leases = ip->client->active;
1298 ip->client->active = NULL;
1303 /* Otherwise, put the active lease at the end of the
1304 lease list, and try another lease.. */
1305 for (lp = ip->client->leases; lp->next; lp = lp->next)
1307 lp->next = ip->client->active;
1309 lp->next->next = NULL;
1310 ip->client->active = ip->client->leases;
1311 ip->client->leases = ip->client->leases->next;
1313 /* If we already tried this lease, we've exhausted the
1314 set of leases, so we might as well give up for
1316 if (ip->client->active == loop)
1319 loop = ip->client->active;
1322 /* No leases were available, or what was available didn't work, so
1323 tell the shell script that we failed to allocate an address,
1324 and try again later. */
1325 note("No working leases in persistent database - sleeping.\n");
1326 script_init("FAIL", NULL);
1327 if (ip->client->alias)
1328 script_write_params("alias_", ip->client->alias);
1330 ip->client->state = S_INIT;
1331 add_timeout(cur_time + ip->client->config->retry_interval, state_init,
1337 send_request(void *ipp)
1339 struct interface_info *ip = ipp;
1340 struct sockaddr_in destination;
1341 struct in_addr from;
1344 /* Figure out how long it's been since we started transmitting. */
1345 interval = cur_time - ip->client->first_sending;
1347 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1348 past the reboot timeout, go to INIT and see if we can
1349 DISCOVER an address... */
1350 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1351 means either that we're on a network with no DHCP server,
1352 or that our server is down. In the latter case, assuming
1353 that there is a backup DHCP server, DHCPDISCOVER will get
1354 us a new address, but we could also have successfully
1355 reused our old address. In the former case, we're hosed
1356 anyway. This is not a win-prone situation. */
1357 if ((ip->client->state == S_REBOOTING ||
1358 ip->client->state == S_REQUESTING) &&
1359 interval > ip->client->config->reboot_timeout) {
1361 ip->client->state = S_INIT;
1362 cancel_timeout(send_request, ip);
1367 /* If we're in the reboot state, make sure the media is set up
1369 if (ip->client->state == S_REBOOTING &&
1370 !ip->client->medium &&
1371 ip->client->active->medium ) {
1372 script_init("MEDIUM", ip->client->active->medium);
1374 /* If the medium we chose won't fly, go to INIT state. */
1378 /* Record the medium. */
1379 ip->client->medium = ip->client->active->medium;
1382 /* If the lease has expired, relinquish the address and go back
1383 to the INIT state. */
1384 if (ip->client->state != S_REQUESTING &&
1385 cur_time > ip->client->active->expiry) {
1386 /* Run the client script with the new parameters. */
1387 script_init("EXPIRE", NULL);
1388 script_write_params("old_", ip->client->active);
1389 if (ip->client->alias)
1390 script_write_params("alias_", ip->client->alias);
1393 /* Now do a preinit on the interface so that we can
1394 discover a new address. */
1395 script_init("PREINIT", NULL);
1396 if (ip->client->alias)
1397 script_write_params("alias_", ip->client->alias);
1400 ip->client->state = S_INIT;
1405 /* Do the exponential backoff... */
1406 if (!ip->client->interval)
1407 ip->client->interval = ip->client->config->initial_interval;
1409 ip->client->interval += ((arc4random() >> 2) %
1410 (2 * ip->client->interval));
1412 /* Don't backoff past cutoff. */
1413 if (ip->client->interval >
1414 ip->client->config->backoff_cutoff)
1415 ip->client->interval =
1416 ((ip->client->config->backoff_cutoff / 2) +
1417 ((arc4random() >> 2) % ip->client->interval));
1419 /* If the backoff would take us to the expiry time, just set the
1420 timeout to the expiry time. */
1421 if (ip->client->state != S_REQUESTING &&
1422 cur_time + ip->client->interval >
1423 ip->client->active->expiry)
1424 ip->client->interval =
1425 ip->client->active->expiry - cur_time + 1;
1427 /* If the lease T2 time has elapsed, or if we're not yet bound,
1428 broadcast the DHCPREQUEST rather than unicasting. */
1429 memset(&destination, 0, sizeof(destination));
1430 if (ip->client->state == S_REQUESTING ||
1431 ip->client->state == S_REBOOTING ||
1432 cur_time > ip->client->active->rebind)
1433 destination.sin_addr.s_addr = INADDR_BROADCAST;
1435 memcpy(&destination.sin_addr.s_addr,
1436 ip->client->destination.iabuf,
1437 sizeof(destination.sin_addr.s_addr));
1438 destination.sin_port = htons(REMOTE_PORT);
1439 destination.sin_family = AF_INET;
1440 destination.sin_len = sizeof(destination);
1442 if (ip->client->state != S_REQUESTING)
1443 memcpy(&from, ip->client->active->address.iabuf,
1446 from.s_addr = INADDR_ANY;
1448 /* Record the number of seconds since we started sending. */
1449 if (ip->client->state == S_REQUESTING)
1450 ip->client->packet.secs = ip->client->secs;
1452 if (interval < 65536)
1453 ip->client->packet.secs = htons(interval);
1455 ip->client->packet.secs = htons(65535);
1458 note("DHCPREQUEST on %s to %s port %d", ip->name,
1459 inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
1461 /* Send out a packet. */
1462 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1463 from, &destination, NULL);
1465 add_timeout(cur_time + ip->client->interval, send_request, ip);
1469 send_decline(void *ipp)
1471 struct interface_info *ip = ipp;
1473 note("DHCPDECLINE on %s to %s port %d", ip->name,
1474 inet_ntoa(sockaddr_broadcast.sin_addr),
1475 ntohs(sockaddr_broadcast.sin_port));
1477 /* Send out a packet. */
1478 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1479 inaddr_any, &sockaddr_broadcast, NULL);
1483 make_discover(struct interface_info *ip, struct client_lease *lease)
1485 unsigned char discover = DHCPDISCOVER;
1486 struct tree_cache *options[256];
1487 struct tree_cache option_elements[256];
1490 memset(option_elements, 0, sizeof(option_elements));
1491 memset(options, 0, sizeof(options));
1492 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1494 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1495 i = DHO_DHCP_MESSAGE_TYPE;
1496 options[i] = &option_elements[i];
1497 options[i]->value = &discover;
1498 options[i]->len = sizeof(discover);
1499 options[i]->buf_size = sizeof(discover);
1500 options[i]->timeout = 0xFFFFFFFF;
1502 /* Request the options we want */
1503 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1504 options[i] = &option_elements[i];
1505 options[i]->value = ip->client->config->requested_options;
1506 options[i]->len = ip->client->config->requested_option_count;
1507 options[i]->buf_size =
1508 ip->client->config->requested_option_count;
1509 options[i]->timeout = 0xFFFFFFFF;
1511 /* If we had an address, try to get it again. */
1513 ip->client->requested_address = lease->address;
1514 i = DHO_DHCP_REQUESTED_ADDRESS;
1515 options[i] = &option_elements[i];
1516 options[i]->value = lease->address.iabuf;
1517 options[i]->len = lease->address.len;
1518 options[i]->buf_size = lease->address.len;
1519 options[i]->timeout = 0xFFFFFFFF;
1521 ip->client->requested_address.len = 0;
1523 /* Send any options requested in the config file. */
1524 for (i = 0; i < 256; i++)
1526 ip->client->config->send_options[i].data) {
1527 options[i] = &option_elements[i];
1529 ip->client->config->send_options[i].data;
1531 ip->client->config->send_options[i].len;
1532 options[i]->buf_size =
1533 ip->client->config->send_options[i].len;
1534 options[i]->timeout = 0xFFFFFFFF;
1537 /* send host name if not set via config file. */
1538 char hostname[_POSIX_HOST_NAME_MAX+1];
1539 if (!options[DHO_HOST_NAME]) {
1540 if (gethostname(hostname, sizeof(hostname)) == 0) {
1542 char* posDot = strchr(hostname, '.');
1544 len = posDot - hostname;
1546 len = strlen(hostname);
1547 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1548 options[DHO_HOST_NAME]->value = hostname;
1549 options[DHO_HOST_NAME]->len = len;
1550 options[DHO_HOST_NAME]->buf_size = len;
1551 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1555 /* set unique client identifier */
1556 char client_ident[sizeof(struct hardware)];
1557 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1558 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1559 ip->hw_address.hlen : sizeof(client_ident)-1;
1560 client_ident[0] = ip->hw_address.htype;
1561 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1562 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1563 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1564 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1565 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1566 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1569 /* Set up the option buffer... */
1570 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1571 options, 0, 0, 0, NULL, 0);
1572 if (ip->client->packet_length < BOOTP_MIN_LEN)
1573 ip->client->packet_length = BOOTP_MIN_LEN;
1575 ip->client->packet.op = BOOTREQUEST;
1576 ip->client->packet.htype = ip->hw_address.htype;
1577 ip->client->packet.hlen = ip->hw_address.hlen;
1578 ip->client->packet.hops = 0;
1579 ip->client->packet.xid = arc4random();
1580 ip->client->packet.secs = 0; /* filled in by send_discover. */
1581 ip->client->packet.flags = 0;
1583 memset(&(ip->client->packet.ciaddr),
1584 0, sizeof(ip->client->packet.ciaddr));
1585 memset(&(ip->client->packet.yiaddr),
1586 0, sizeof(ip->client->packet.yiaddr));
1587 memset(&(ip->client->packet.siaddr),
1588 0, sizeof(ip->client->packet.siaddr));
1589 memset(&(ip->client->packet.giaddr),
1590 0, sizeof(ip->client->packet.giaddr));
1591 memcpy(ip->client->packet.chaddr,
1592 ip->hw_address.haddr, ip->hw_address.hlen);
1597 make_request(struct interface_info *ip, struct client_lease * lease)
1599 unsigned char request = DHCPREQUEST;
1600 struct tree_cache *options[256];
1601 struct tree_cache option_elements[256];
1604 memset(options, 0, sizeof(options));
1605 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1607 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1608 i = DHO_DHCP_MESSAGE_TYPE;
1609 options[i] = &option_elements[i];
1610 options[i]->value = &request;
1611 options[i]->len = sizeof(request);
1612 options[i]->buf_size = sizeof(request);
1613 options[i]->timeout = 0xFFFFFFFF;
1615 /* Request the options we want */
1616 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1617 options[i] = &option_elements[i];
1618 options[i]->value = ip->client->config->requested_options;
1619 options[i]->len = ip->client->config->requested_option_count;
1620 options[i]->buf_size =
1621 ip->client->config->requested_option_count;
1622 options[i]->timeout = 0xFFFFFFFF;
1624 /* If we are requesting an address that hasn't yet been assigned
1625 to us, use the DHCP Requested Address option. */
1626 if (ip->client->state == S_REQUESTING) {
1627 /* Send back the server identifier... */
1628 i = DHO_DHCP_SERVER_IDENTIFIER;
1629 options[i] = &option_elements[i];
1630 options[i]->value = lease->options[i].data;
1631 options[i]->len = lease->options[i].len;
1632 options[i]->buf_size = lease->options[i].len;
1633 options[i]->timeout = 0xFFFFFFFF;
1635 if (ip->client->state == S_REQUESTING ||
1636 ip->client->state == S_REBOOTING) {
1637 ip->client->requested_address = lease->address;
1638 i = DHO_DHCP_REQUESTED_ADDRESS;
1639 options[i] = &option_elements[i];
1640 options[i]->value = lease->address.iabuf;
1641 options[i]->len = lease->address.len;
1642 options[i]->buf_size = lease->address.len;
1643 options[i]->timeout = 0xFFFFFFFF;
1645 ip->client->requested_address.len = 0;
1647 /* Send any options requested in the config file. */
1648 for (i = 0; i < 256; i++)
1650 ip->client->config->send_options[i].data) {
1651 options[i] = &option_elements[i];
1653 ip->client->config->send_options[i].data;
1655 ip->client->config->send_options[i].len;
1656 options[i]->buf_size =
1657 ip->client->config->send_options[i].len;
1658 options[i]->timeout = 0xFFFFFFFF;
1661 /* send host name if not set via config file. */
1662 char hostname[_POSIX_HOST_NAME_MAX+1];
1663 if (!options[DHO_HOST_NAME]) {
1664 if (gethostname(hostname, sizeof(hostname)) == 0) {
1666 char* posDot = strchr(hostname, '.');
1668 len = posDot - hostname;
1670 len = strlen(hostname);
1671 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1672 options[DHO_HOST_NAME]->value = hostname;
1673 options[DHO_HOST_NAME]->len = len;
1674 options[DHO_HOST_NAME]->buf_size = len;
1675 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1679 /* set unique client identifier */
1680 char client_ident[sizeof(struct hardware)];
1681 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1682 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1683 ip->hw_address.hlen : sizeof(client_ident)-1;
1684 client_ident[0] = ip->hw_address.htype;
1685 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1686 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1687 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1688 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1689 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1690 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1693 /* Set up the option buffer... */
1694 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1695 options, 0, 0, 0, NULL, 0);
1696 if (ip->client->packet_length < BOOTP_MIN_LEN)
1697 ip->client->packet_length = BOOTP_MIN_LEN;
1699 ip->client->packet.op = BOOTREQUEST;
1700 ip->client->packet.htype = ip->hw_address.htype;
1701 ip->client->packet.hlen = ip->hw_address.hlen;
1702 ip->client->packet.hops = 0;
1703 ip->client->packet.xid = ip->client->xid;
1704 ip->client->packet.secs = 0; /* Filled in by send_request. */
1706 /* If we own the address we're requesting, put it in ciaddr;
1707 otherwise set ciaddr to zero. */
1708 if (ip->client->state == S_BOUND ||
1709 ip->client->state == S_RENEWING ||
1710 ip->client->state == S_REBINDING) {
1711 memcpy(&ip->client->packet.ciaddr,
1712 lease->address.iabuf, lease->address.len);
1713 ip->client->packet.flags = 0;
1715 memset(&ip->client->packet.ciaddr, 0,
1716 sizeof(ip->client->packet.ciaddr));
1717 ip->client->packet.flags = 0;
1720 memset(&ip->client->packet.yiaddr, 0,
1721 sizeof(ip->client->packet.yiaddr));
1722 memset(&ip->client->packet.siaddr, 0,
1723 sizeof(ip->client->packet.siaddr));
1724 memset(&ip->client->packet.giaddr, 0,
1725 sizeof(ip->client->packet.giaddr));
1726 memcpy(ip->client->packet.chaddr,
1727 ip->hw_address.haddr, ip->hw_address.hlen);
1731 make_decline(struct interface_info *ip, struct client_lease *lease)
1733 struct tree_cache *options[256], message_type_tree;
1734 struct tree_cache requested_address_tree;
1735 struct tree_cache server_id_tree, client_id_tree;
1736 unsigned char decline = DHCPDECLINE;
1739 memset(options, 0, sizeof(options));
1740 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1742 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1743 i = DHO_DHCP_MESSAGE_TYPE;
1744 options[i] = &message_type_tree;
1745 options[i]->value = &decline;
1746 options[i]->len = sizeof(decline);
1747 options[i]->buf_size = sizeof(decline);
1748 options[i]->timeout = 0xFFFFFFFF;
1750 /* Send back the server identifier... */
1751 i = DHO_DHCP_SERVER_IDENTIFIER;
1752 options[i] = &server_id_tree;
1753 options[i]->value = lease->options[i].data;
1754 options[i]->len = lease->options[i].len;
1755 options[i]->buf_size = lease->options[i].len;
1756 options[i]->timeout = 0xFFFFFFFF;
1758 /* Send back the address we're declining. */
1759 i = DHO_DHCP_REQUESTED_ADDRESS;
1760 options[i] = &requested_address_tree;
1761 options[i]->value = lease->address.iabuf;
1762 options[i]->len = lease->address.len;
1763 options[i]->buf_size = lease->address.len;
1764 options[i]->timeout = 0xFFFFFFFF;
1766 /* Send the uid if the user supplied one. */
1767 i = DHO_DHCP_CLIENT_IDENTIFIER;
1768 if (ip->client->config->send_options[i].len) {
1769 options[i] = &client_id_tree;
1770 options[i]->value = ip->client->config->send_options[i].data;
1771 options[i]->len = ip->client->config->send_options[i].len;
1772 options[i]->buf_size = ip->client->config->send_options[i].len;
1773 options[i]->timeout = 0xFFFFFFFF;
1777 /* Set up the option buffer... */
1778 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1779 options, 0, 0, 0, NULL, 0);
1780 if (ip->client->packet_length < BOOTP_MIN_LEN)
1781 ip->client->packet_length = BOOTP_MIN_LEN;
1783 ip->client->packet.op = BOOTREQUEST;
1784 ip->client->packet.htype = ip->hw_address.htype;
1785 ip->client->packet.hlen = ip->hw_address.hlen;
1786 ip->client->packet.hops = 0;
1787 ip->client->packet.xid = ip->client->xid;
1788 ip->client->packet.secs = 0; /* Filled in by send_request. */
1789 ip->client->packet.flags = 0;
1791 /* ciaddr must always be zero. */
1792 memset(&ip->client->packet.ciaddr, 0,
1793 sizeof(ip->client->packet.ciaddr));
1794 memset(&ip->client->packet.yiaddr, 0,
1795 sizeof(ip->client->packet.yiaddr));
1796 memset(&ip->client->packet.siaddr, 0,
1797 sizeof(ip->client->packet.siaddr));
1798 memset(&ip->client->packet.giaddr, 0,
1799 sizeof(ip->client->packet.giaddr));
1800 memcpy(ip->client->packet.chaddr,
1801 ip->hw_address.haddr, ip->hw_address.hlen);
1805 free_client_lease(struct client_lease *lease)
1809 if (lease->server_name)
1810 free(lease->server_name);
1811 if (lease->filename)
1812 free(lease->filename);
1813 for (i = 0; i < 256; i++) {
1814 if (lease->options[i].len)
1815 free(lease->options[i].data);
1823 rewrite_client_leases(void)
1825 struct client_lease *lp;
1828 leaseFile = fopen(path_dhclient_db, "w");
1830 error("can't create %s: %m", path_dhclient_db);
1836 for (lp = ifi->client->leases; lp; lp = lp->next)
1837 write_client_lease(ifi, lp, 1);
1838 if (ifi->client->active)
1839 write_client_lease(ifi, ifi->client->active, 1);
1842 ftruncate(fileno(leaseFile), ftello(leaseFile));
1843 fsync(fileno(leaseFile));
1847 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1850 static int leases_written;
1855 if (leases_written++ > 20) {
1856 rewrite_client_leases();
1861 /* If the lease came from the config file, we don't need to stash
1862 a copy in the lease database. */
1863 if (lease->is_static)
1866 if (!leaseFile) { /* XXX */
1867 leaseFile = fopen(path_dhclient_db, "w");
1869 error("can't create %s: %m", path_dhclient_db);
1872 fprintf(leaseFile, "lease {\n");
1873 if (lease->is_bootp)
1874 fprintf(leaseFile, " bootp;\n");
1875 fprintf(leaseFile, " interface \"%s\";\n", ip->name);
1876 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
1877 if (lease->filename)
1878 fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
1879 if (lease->server_name)
1880 fprintf(leaseFile, " server-name \"%s\";\n",
1881 lease->server_name);
1883 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string);
1884 for (i = 0; i < 256; i++)
1885 if (lease->options[i].len)
1886 fprintf(leaseFile, " option %s %s;\n",
1887 dhcp_options[i].name,
1888 pretty_print_option(i, lease->options[i].data,
1889 lease->options[i].len, 1, 1));
1891 t = gmtime(&lease->renewal);
1892 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1893 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1894 t->tm_hour, t->tm_min, t->tm_sec);
1895 t = gmtime(&lease->rebind);
1896 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1897 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1898 t->tm_hour, t->tm_min, t->tm_sec);
1899 t = gmtime(&lease->expiry);
1900 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1901 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1902 t->tm_hour, t->tm_min, t->tm_sec);
1903 fprintf(leaseFile, "}\n");
1908 script_init(char *reason, struct string_list *medium)
1910 size_t len, mediumlen = 0;
1911 struct imsg_hdr hdr;
1915 if (medium != NULL && medium->string != NULL)
1916 mediumlen = strlen(medium->string);
1918 hdr.code = IMSG_SCRIPT_INIT;
1919 hdr.len = sizeof(struct imsg_hdr) +
1920 sizeof(size_t) + mediumlen +
1921 sizeof(size_t) + strlen(reason);
1923 if ((buf = buf_open(hdr.len)) == NULL)
1924 error("buf_open: %m");
1927 errs += buf_add(buf, &hdr, sizeof(hdr));
1928 errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
1930 errs += buf_add(buf, medium->string, mediumlen);
1931 len = strlen(reason);
1932 errs += buf_add(buf, &len, sizeof(len));
1933 errs += buf_add(buf, reason, len);
1936 error("buf_add: %m");
1938 if (buf_close(privfd, buf) == -1)
1939 error("buf_close: %m");
1943 priv_script_init(char *reason, char *medium)
1945 struct interface_info *ip = ifi;
1948 ip->client->scriptEnvsize = 100;
1949 if (ip->client->scriptEnv == NULL)
1950 ip->client->scriptEnv =
1951 malloc(ip->client->scriptEnvsize * sizeof(char *));
1952 if (ip->client->scriptEnv == NULL)
1953 error("script_init: no memory for environment");
1955 ip->client->scriptEnv[0] = strdup(CLIENT_PATH);
1956 if (ip->client->scriptEnv[0] == NULL)
1957 error("script_init: no memory for environment");
1959 ip->client->scriptEnv[1] = NULL;
1961 script_set_env(ip->client, "", "interface", ip->name);
1964 script_set_env(ip->client, "", "medium", medium);
1966 script_set_env(ip->client, "", "reason", reason);
1971 priv_script_write_params(char *prefix, struct client_lease *lease)
1973 struct interface_info *ip = ifi;
1974 u_int8_t dbuf[1500], *dp = NULL;
1978 script_set_env(ip->client, prefix, "ip_address",
1979 piaddr(lease->address));
1981 if (ip->client->config->default_actions[DHO_SUBNET_MASK] ==
1983 dp = ip->client->config->defaults[DHO_SUBNET_MASK].data;
1984 len = ip->client->config->defaults[DHO_SUBNET_MASK].len;
1986 dp = lease->options[DHO_SUBNET_MASK].data;
1987 len = lease->options[DHO_SUBNET_MASK].len;
1989 if (len && (len < sizeof(lease->address.iabuf))) {
1990 struct iaddr netmask, subnet, broadcast;
1992 memcpy(netmask.iabuf, dp, len);
1994 subnet = subnet_number(lease->address, netmask);
1996 script_set_env(ip->client, prefix, "network_number",
1998 if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
1999 broadcast = broadcast_addr(subnet, netmask);
2001 script_set_env(ip->client, prefix,
2002 "broadcast_address",
2008 if (lease->filename)
2009 script_set_env(ip->client, prefix, "filename", lease->filename);
2010 if (lease->server_name)
2011 script_set_env(ip->client, prefix, "server_name",
2012 lease->server_name);
2013 for (i = 0; i < 256; i++) {
2016 if (ip->client->config->defaults[i].len) {
2017 if (lease->options[i].len) {
2019 ip->client->config->default_actions[i]) {
2020 case ACTION_DEFAULT:
2021 dp = lease->options[i].data;
2022 len = lease->options[i].len;
2024 case ACTION_SUPERSEDE:
2027 config->defaults[i].data;
2029 config->defaults[i].len;
2031 case ACTION_PREPEND:
2033 config->defaults[i].len +
2034 lease->options[i].len;
2035 if (len >= sizeof(dbuf)) {
2036 warning("no space to %s %s",
2038 dhcp_options[i].name);
2044 config->defaults[i].data,
2046 config->defaults[i].len);
2047 memcpy(dp + ip->client->
2048 config->defaults[i].len,
2049 lease->options[i].data,
2050 lease->options[i].len);
2055 * When we append, we assume that we're
2056 * appending to text. Some MS servers
2057 * include a NUL byte at the end of
2058 * the search string provided.
2061 config->defaults[i].len +
2062 lease->options[i].len;
2063 if (len >= sizeof(dbuf)) {
2064 warning("no space to %s %s",
2066 dhcp_options[i].name);
2070 lease->options[i].data,
2071 lease->options[i].len);
2072 for (dp = dbuf + lease->options[i].len;
2073 dp > dbuf; dp--, len--)
2078 config->defaults[i].data,
2080 config->defaults[i].len);
2086 config->defaults[i].data;
2088 config->defaults[i].len;
2090 } else if (lease->options[i].len) {
2091 len = lease->options[i].len;
2092 dp = lease->options[i].data;
2099 if (dhcp_option_ev_name(name, sizeof(name),
2101 script_set_env(ip->client, prefix, name,
2102 pretty_print_option(i, dp, len, 0, 0));
2105 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
2106 script_set_env(ip->client, prefix, "expiry", tbuf);
2110 script_write_params(char *prefix, struct client_lease *lease)
2112 size_t fn_len = 0, sn_len = 0, pr_len = 0;
2113 struct imsg_hdr hdr;
2117 if (lease->filename != NULL)
2118 fn_len = strlen(lease->filename);
2119 if (lease->server_name != NULL)
2120 sn_len = strlen(lease->server_name);
2122 pr_len = strlen(prefix);
2124 hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
2125 hdr.len = sizeof(hdr) + sizeof(struct client_lease) +
2126 sizeof(size_t) + fn_len + sizeof(size_t) + sn_len +
2127 sizeof(size_t) + pr_len;
2129 for (i = 0; i < 256; i++)
2130 hdr.len += sizeof(int) + lease->options[i].len;
2132 scripttime = time(NULL);
2134 if ((buf = buf_open(hdr.len)) == NULL)
2135 error("buf_open: %m");
2138 errs += buf_add(buf, &hdr, sizeof(hdr));
2139 errs += buf_add(buf, lease, sizeof(struct client_lease));
2140 errs += buf_add(buf, &fn_len, sizeof(fn_len));
2141 errs += buf_add(buf, lease->filename, fn_len);
2142 errs += buf_add(buf, &sn_len, sizeof(sn_len));
2143 errs += buf_add(buf, lease->server_name, sn_len);
2144 errs += buf_add(buf, &pr_len, sizeof(pr_len));
2145 errs += buf_add(buf, prefix, pr_len);
2147 for (i = 0; i < 256; i++) {
2148 errs += buf_add(buf, &lease->options[i].len,
2149 sizeof(lease->options[i].len));
2150 errs += buf_add(buf, lease->options[i].data,
2151 lease->options[i].len);
2155 error("buf_add: %m");
2157 if (buf_close(privfd, buf) == -1)
2158 error("buf_close: %m");
2164 struct imsg_hdr hdr;
2168 hdr.code = IMSG_SCRIPT_GO;
2169 hdr.len = sizeof(struct imsg_hdr);
2171 if ((buf = buf_open(hdr.len)) == NULL)
2172 error("buf_open: %m");
2174 if (buf_add(buf, &hdr, sizeof(hdr)))
2175 error("buf_add: %m");
2177 if (buf_close(privfd, buf) == -1)
2178 error("buf_close: %m");
2180 bzero(&hdr, sizeof(hdr));
2181 buf_read(privfd, &hdr, sizeof(hdr));
2182 if (hdr.code != IMSG_SCRIPT_GO_RET)
2183 error("unexpected msg type %u", hdr.code);
2184 if (hdr.len != sizeof(hdr) + sizeof(int))
2185 error("received corrupted message");
2186 buf_read(privfd, &ret, sizeof(ret));
2188 scripttime = time(NULL);
2194 priv_script_go(void)
2196 char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI";
2197 static char client_path[] = CLIENT_PATH;
2198 struct interface_info *ip = ifi;
2199 int pid, wpid, wstatus;
2201 scripttime = time(NULL);
2204 scriptName = ip->client->config->script_name;
2205 envp = ip->client->scriptEnv;
2207 scriptName = top_level_config.script_name;
2209 epp[1] = client_path;
2214 argv[0] = scriptName;
2223 wpid = wait(&wstatus);
2224 } while (wpid != pid && wpid > 0);
2230 execve(scriptName, argv, envp);
2231 error("execve (%s, ...): %m", scriptName);
2235 script_flush_env(ip->client);
2237 return (wstatus & 0xff);
2241 script_set_env(struct client_state *client, const char *prefix,
2242 const char *name, const char *value)
2246 namelen = strlen(name);
2248 for (i = 0; client->scriptEnv[i]; i++)
2249 if (strncmp(client->scriptEnv[i], name, namelen) == 0 &&
2250 client->scriptEnv[i][namelen] == '=')
2253 if (client->scriptEnv[i])
2254 /* Reuse the slot. */
2255 free(client->scriptEnv[i]);
2257 /* New variable. Expand if necessary. */
2258 if (i >= client->scriptEnvsize - 1) {
2259 char **newscriptEnv;
2260 int newscriptEnvsize = client->scriptEnvsize + 50;
2262 newscriptEnv = realloc(client->scriptEnv,
2264 if (newscriptEnv == NULL) {
2265 free(client->scriptEnv);
2266 client->scriptEnv = NULL;
2267 client->scriptEnvsize = 0;
2268 error("script_set_env: no memory for variable");
2270 client->scriptEnv = newscriptEnv;
2271 client->scriptEnvsize = newscriptEnvsize;
2273 /* need to set the NULL pointer at end of array beyond
2275 client->scriptEnv[i + 1] = NULL;
2277 /* Allocate space and format the variable in the appropriate slot. */
2278 client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 +
2280 if (client->scriptEnv[i] == NULL)
2281 error("script_set_env: no memory for variable assignment");
2283 /* No `` or $() command substitution allowed in environment values! */
2284 for (j=0; j < strlen(value); j++)
2288 error("illegal character (%c) in value '%s'", value[j],
2292 snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
2293 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
2297 script_flush_env(struct client_state *client)
2301 for (i = 0; client->scriptEnv[i]; i++) {
2302 free(client->scriptEnv[i]);
2303 client->scriptEnv[i] = NULL;
2305 client->scriptEnvsize = 0;
2309 dhcp_option_ev_name(char *buf, size_t buflen, struct option *option)
2313 for (i = 0; option->name[i]; i++) {
2314 if (i + 1 == buflen)
2316 if (option->name[i] == '-')
2319 buf[i] = option->name[i];
2329 static int state = 0;
2331 if (no_daemon || state)
2336 /* Stop logging to stderr... */
2339 if (daemon(1, 0) == -1)
2342 if (pidfile != NULL)
2343 pidfile_write(pidfile);
2345 /* we are chrooted, daemon(3) fails to open /dev/null */
2347 dup2(nullfd, STDIN_FILENO);
2348 dup2(nullfd, STDOUT_FILENO);
2349 dup2(nullfd, STDERR_FILENO);
2356 check_option(struct client_lease *l, int option)
2361 /* we use this, since this is what gets passed to dhclient-script */
2363 opbuf = pretty_print_option(option, l->options[option].data,
2364 l->options[option].len, 0, 0);
2366 sbuf = option_as_string(option, l->options[option].data,
2367 l->options[option].len);
2370 case DHO_SUBNET_MASK:
2371 case DHO_TIME_SERVERS:
2372 case DHO_NAME_SERVERS:
2374 case DHO_DOMAIN_NAME_SERVERS:
2375 case DHO_LOG_SERVERS:
2376 case DHO_COOKIE_SERVERS:
2377 case DHO_LPR_SERVERS:
2378 case DHO_IMPRESS_SERVERS:
2379 case DHO_RESOURCE_LOCATION_SERVERS:
2380 case DHO_SWAP_SERVER:
2381 case DHO_BROADCAST_ADDRESS:
2382 case DHO_NIS_SERVERS:
2383 case DHO_NTP_SERVERS:
2384 case DHO_NETBIOS_NAME_SERVERS:
2385 case DHO_NETBIOS_DD_SERVER:
2386 case DHO_FONT_SERVERS:
2387 case DHO_DHCP_SERVER_IDENTIFIER:
2388 case DHO_NISPLUS_SERVERS:
2389 case DHO_MOBILE_IP_HOME_AGENT:
2390 case DHO_SMTP_SERVER:
2391 case DHO_POP_SERVER:
2392 case DHO_NNTP_SERVER:
2393 case DHO_WWW_SERVER:
2394 case DHO_FINGER_SERVER:
2395 case DHO_IRC_SERVER:
2396 case DHO_STREETTALK_SERVER:
2397 case DHO_STREETTALK_DA_SERVER:
2398 if (!ipv4addrs(opbuf)) {
2399 warning("Invalid IP address in option: %s", opbuf);
2404 case DHO_NIS_DOMAIN:
2405 case DHO_NISPLUS_DOMAIN:
2406 case DHO_TFTP_SERVER_NAME:
2407 if (!res_hnok(sbuf)) {
2408 warning("Bogus Host Name option %d: %s (%s)", option,
2410 l->options[option].len = 0;
2411 free(l->options[option].data);
2414 case DHO_DOMAIN_NAME:
2415 case DHO_DOMAIN_SEARCH:
2416 if (!res_hnok(sbuf)) {
2417 if (!check_search(sbuf)) {
2418 warning("Bogus domain search list %d: %s (%s)",
2419 option, sbuf, opbuf);
2420 l->options[option].len = 0;
2421 free(l->options[option].data);
2426 case DHO_TIME_OFFSET:
2428 case DHO_MERIT_DUMP:
2430 case DHO_EXTENSIONS_PATH:
2431 case DHO_IP_FORWARDING:
2432 case DHO_NON_LOCAL_SOURCE_ROUTING:
2433 case DHO_POLICY_FILTER:
2434 case DHO_MAX_DGRAM_REASSEMBLY:
2435 case DHO_DEFAULT_IP_TTL:
2436 case DHO_PATH_MTU_AGING_TIMEOUT:
2437 case DHO_PATH_MTU_PLATEAU_TABLE:
2438 case DHO_INTERFACE_MTU:
2439 case DHO_ALL_SUBNETS_LOCAL:
2440 case DHO_PERFORM_MASK_DISCOVERY:
2441 case DHO_MASK_SUPPLIER:
2442 case DHO_ROUTER_DISCOVERY:
2443 case DHO_ROUTER_SOLICITATION_ADDRESS:
2444 case DHO_STATIC_ROUTES:
2445 case DHO_TRAILER_ENCAPSULATION:
2446 case DHO_ARP_CACHE_TIMEOUT:
2447 case DHO_IEEE802_3_ENCAPSULATION:
2448 case DHO_DEFAULT_TCP_TTL:
2449 case DHO_TCP_KEEPALIVE_INTERVAL:
2450 case DHO_TCP_KEEPALIVE_GARBAGE:
2451 case DHO_VENDOR_ENCAPSULATED_OPTIONS:
2452 case DHO_NETBIOS_NODE_TYPE:
2453 case DHO_NETBIOS_SCOPE:
2454 case DHO_X_DISPLAY_MANAGER:
2455 case DHO_DHCP_REQUESTED_ADDRESS:
2456 case DHO_DHCP_LEASE_TIME:
2457 case DHO_DHCP_OPTION_OVERLOAD:
2458 case DHO_DHCP_MESSAGE_TYPE:
2459 case DHO_DHCP_PARAMETER_REQUEST_LIST:
2460 case DHO_DHCP_MESSAGE:
2461 case DHO_DHCP_MAX_MESSAGE_SIZE:
2462 case DHO_DHCP_RENEWAL_TIME:
2463 case DHO_DHCP_REBINDING_TIME:
2464 case DHO_DHCP_CLASS_IDENTIFIER:
2465 case DHO_DHCP_CLIENT_IDENTIFIER:
2466 case DHO_BOOTFILE_NAME:
2467 case DHO_DHCP_USER_CLASS_ID:
2470 case DHO_CLASSLESS_ROUTES:
2471 return (check_classless_option(l->options[option].data,
2472 l->options[option].len));
2474 warning("unknown dhcp option value 0x%x", option);
2475 return (unknown_ok);
2479 /* RFC 3442 The Classless Static Routes option checks */
2481 check_classless_option(unsigned char *data, int len)
2484 unsigned char width;
2485 in_addr_t addr, mask;
2488 warning("Too small length: %d", len);
2496 } else if (width < 9) {
2497 addr = (in_addr_t)(data[i] << 24);
2499 } else if (width < 17) {
2500 addr = (in_addr_t)(data[i] << 24) +
2501 (in_addr_t)(data[i + 1] << 16);
2503 } else if (width < 25) {
2504 addr = (in_addr_t)(data[i] << 24) +
2505 (in_addr_t)(data[i + 1] << 16) +
2506 (in_addr_t)(data[i + 2] << 8);
2508 } else if (width < 33) {
2509 addr = (in_addr_t)(data[i] << 24) +
2510 (in_addr_t)(data[i + 1] << 16) +
2511 (in_addr_t)(data[i + 2] << 8) +
2515 warning("Incorrect subnet width: %d", width);
2518 mask = (in_addr_t)(~0) << (32 - width);
2524 * ... After deriving a subnet number and subnet mask
2525 * from each destination descriptor, the DHCP client
2526 * MUST zero any bits in the subnet number where the
2527 * corresponding bit in the mask is zero...
2529 if ((addr & mask) != addr) {
2531 data[i - 1] = (unsigned char)(
2532 (addr >> (((32 - width)/8)*8)) & 0xFF);
2537 warning("Incorrect data length: %d (must be %d)", len, i);
2544 res_hnok(const char *dn)
2546 int pch = PERIOD, ch = *dn++;
2548 while (ch != '\0') {
2551 if (periodchar(ch)) {
2553 } else if (periodchar(pch)) {
2554 if (!borderchar(ch))
2556 } else if (periodchar(nch) || nch == '\0') {
2557 if (!borderchar(ch))
2560 if (!middlechar(ch))
2569 check_search(const char *srch)
2571 int pch = PERIOD, ch = *srch++;
2574 /* 256 char limit re resolv.conf(5) */
2575 if (strlen(srch) > 256)
2578 while (whitechar(ch))
2581 while (ch != '\0') {
2584 if (periodchar(ch) || whitechar(ch)) {
2586 } else if (periodchar(pch)) {
2587 if (!borderchar(ch))
2589 } else if (periodchar(nch) || nch == '\0') {
2590 if (!borderchar(ch))
2593 if (!middlechar(ch))
2596 if (!whitechar(ch)) {
2599 while (whitechar(nch)) {
2608 /* 6 domain limit re resolv.conf(5) */
2614 /* Does buf consist only of dotted decimal ipv4 addrs?
2615 * return how many if so,
2616 * otherwise, return 0
2619 ipv4addrs(char * buf)
2624 while (inet_aton(buf, &jnk) == 1){
2626 while (periodchar(*buf) || digitchar(*buf))
2638 option_as_string(unsigned int code, unsigned char *data, int len)
2640 static char optbuf[32768]; /* XXX */
2642 int opleft = sizeof(optbuf);
2643 unsigned char *dp = data;
2646 error("option_as_string: bad code %d", code);
2648 for (; dp < data + len; dp++) {
2649 if (!isascii(*dp) || !isprint(*dp)) {
2650 if (dp + 1 != data + len || *dp != 0) {
2651 snprintf(op, opleft, "\\%03o", *dp);
2655 } else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
2656 *dp == '`' || *dp == '\\') {
2670 warning("dhcp option too large");
2675 fork_privchld(int fd, int fd2)
2677 struct pollfd pfd[1];
2682 error("cannot fork");
2689 setproctitle("%s [priv]", ifi->name);
2692 dup2(nullfd, STDIN_FILENO);
2693 dup2(nullfd, STDOUT_FILENO);
2694 dup2(nullfd, STDERR_FILENO);
2700 pfd[0].events = POLLIN;
2701 if ((nfds = poll(pfd, 1, INFTIM)) == -1)
2703 error("poll error");
2705 if (nfds == 0 || !(pfd[0].revents & POLLIN))