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);
222 n = read(routefd, &msg, sizeof(msg));
223 rtm = (struct rt_msghdr *)msg;
224 if (n < sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen ||
225 rtm->rtm_version != RTM_VERSION)
228 switch (rtm->rtm_type) {
231 ifam = (struct ifa_msghdr *)rtm;
233 if (ifam->ifam_index != ifi->index)
235 if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
237 if (scripttime == 0 || t < scripttime + 10)
240 sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs);
244 if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf))
245 error("king bula sez: len mismatch");
246 memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len);
247 if (addr_eq(a, defaddr))
250 for (l = ifi->client->active; l != NULL; l = l->next)
251 if (addr_eq(a, l->address))
254 if (l == NULL) /* added/deleted addr is not the one we set */
257 addr = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
258 if (rtm->rtm_type == RTM_NEWADDR) {
260 * XXX: If someone other than us adds our address,
261 * should we assume they are taking over from us,
262 * delete the lease record, and exit without modifying
265 warning("My address (%s) was re-added", addr);
267 warning("My address (%s) was deleted, dhclient exiting",
273 ifm = (struct if_msghdr *)rtm;
274 if (ifm->ifm_index != ifi->index)
276 if ((rtm->rtm_flags & RTF_UP) == 0) {
277 warning("Interface %s is down, dhclient exiting",
281 if (!interface_link_status(ifi->name)) {
282 warning("Interface %s is down, dhclient exiting",
288 ifan = (struct if_announcemsghdr *)rtm;
289 if (ifan->ifan_what == IFAN_DEPARTURE &&
290 ifan->ifan_index == ifi->index) {
291 warning("Interface %s is gone, dhclient exiting",
297 ifan = (struct if_announcemsghdr *)rtm;
298 if (ifan->ifan_index != ifi->index)
300 switch (ifan->ifan_what) {
301 case RTM_IEEE80211_ASSOC:
302 case RTM_IEEE80211_REASSOC:
304 * Use assoc/reassoc event to kick state machine
305 * in case we roam. Otherwise fall back to the
306 * normal state machine just like a wired network.
308 jev = (struct ieee80211_join_event *) &ifan[1];
309 if (memcmp(curbssid, jev->iev_addr, 6)) {
313 memcpy(curbssid, jev->iev_addr, 6);
323 script_init("FAIL", NULL);
324 if (ifi->client->active)
325 script_write_params("old_", ifi->client->active);
326 if (ifi->client->alias)
327 script_write_params("alias_", ifi->client->alias);
330 pidfile_remove(pidfile);
335 main(int argc, char *argv[])
337 extern char *__progname;
338 int ch, fd, quiet = 0, i = 0;
340 int immediate_daemon = 0;
344 /* Initially, log errors to stderr as well as to syslogd. */
345 openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
346 setlogmask(LOG_UPTO(LOG_DEBUG));
348 while ((ch = getopt(argc, argv, "bc:dl:p:qu")) != -1)
351 immediate_daemon = 1;
354 path_dhclient_conf = optarg;
360 path_dhclient_db = optarg;
363 path_dhclient_pidfile = optarg;
381 if (path_dhclient_pidfile == NULL) {
382 asprintf(&path_dhclient_pidfile,
383 "%sdhclient.%s.pid", _PATH_VARRUN, *argv);
384 if (path_dhclient_pidfile == NULL)
387 pidfile = pidfile_open(path_dhclient_pidfile, 0600, &otherpid);
388 if (pidfile == NULL) {
390 error("dhclient already running, pid: %d.", otherpid);
392 error("dhclient already running.");
393 warning("Cannot open or create pidfile: %m");
396 if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL)
398 if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
399 error("Interface name too long");
400 if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s",
401 _PATH_DHCLIENT_DB, ifi->name) == -1)
410 memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
411 sockaddr_broadcast.sin_family = AF_INET;
412 sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
413 sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
414 sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast);
415 inaddr_any.s_addr = INADDR_ANY;
419 /* The next bit is potentially very time-consuming, so write out
420 the pidfile right away. We will write it out again with the
421 correct pid after daemonizing. */
423 pidfile_write(pidfile);
425 if (!interface_link_status(ifi->name)) {
426 fprintf(stderr, "%s: no link ...", ifi->name);
429 while (!interface_link_status(ifi->name)) {
430 fprintf(stderr, ".");
433 fprintf(stderr, " giving up\n");
438 fprintf(stderr, " got link\n");
441 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
442 error("cannot open %s: %m", _PATH_DEVNULL);
444 if ((pw = getpwnam("_dhcp")) == NULL) {
445 warning("no such user: _dhcp, falling back to \"nobody\"");
446 if ((pw = getpwnam("nobody")) == NULL)
447 error("no such user: nobody");
450 if (pipe(pipe_fd) == -1)
453 fork_privchld(pipe_fd[0], pipe_fd[1]);
458 if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
459 error("can't open and lock %s: %m", path_dhclient_db);
460 read_client_leases();
461 rewrite_client_leases();
464 priv_script_init("PREINIT", NULL);
465 if (ifi->client->alias)
466 priv_script_write_params("alias_", ifi->client->alias);
469 if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
470 add_protocol("AF_ROUTE", routefd, routehandler, ifi);
472 /* set up the interface */
473 discover_interfaces(ifi);
475 if (chroot(_PATH_VAREMPTY) == -1)
477 if (chdir("/") == -1)
478 error("chdir(\"/\")");
480 if (setgroups(1, &pw->pw_gid) ||
481 setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
482 seteuid(pw->pw_uid) || setuid(pw->pw_uid))
483 error("can't drop privileges: %m");
487 setproctitle("%s", ifi->name);
489 if (immediate_daemon)
492 ifi->client->state = S_INIT;
495 bootp_packet_handler = do_packet;
506 extern char *__progname;
508 fprintf(stderr, "usage: %s [-bdqu] ", __progname);
509 fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
516 * Each routine is called from the dhclient_state_machine() in one of
518 * -> entering INIT state
519 * -> recvpacket_flag == 0: timeout in this state
520 * -> otherwise: received a packet in this state
522 * Return conditions as handled by dhclient_state_machine():
523 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
524 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
525 * Returns 0: finish the nap which was interrupted for no good reason.
527 * Several per-interface variables are used to keep track of the process:
528 * active_lease: the lease that is being used on the interface
529 * (null pointer if not configured yet).
530 * offered_leases: leases corresponding to DHCPOFFER messages that have
531 * been sent to us by DHCP servers.
532 * acked_leases: leases corresponding to DHCPACK messages that have been
533 * sent to us by DHCP servers.
534 * sendpacket: DHCP packet we're trying to send.
535 * destination: IP address to send sendpacket to
536 * In addition, there are several relevant per-lease variables.
537 * T1_expiry, T2_expiry, lease_expiry: lease milestones
538 * In the active lease, these control the process of renewing the lease;
539 * In leases on the acked_leases list, this simply determines when we
540 * can no longer legitimately use the lease.
544 state_reboot(void *ipp)
546 struct interface_info *ip = ipp;
548 /* If we don't remember an active lease, go straight to INIT. */
549 if (!ip->client->active || ip->client->active->is_bootp) {
554 /* We are in the rebooting state. */
555 ip->client->state = S_REBOOTING;
557 /* make_request doesn't initialize xid because it normally comes
558 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
559 so pick an xid now. */
560 ip->client->xid = arc4random();
562 /* Make a DHCPREQUEST packet, and set appropriate per-interface
564 make_request(ip, ip->client->active);
565 ip->client->destination = iaddr_broadcast;
566 ip->client->first_sending = cur_time;
567 ip->client->interval = ip->client->config->initial_interval;
569 /* Zap the medium list... */
570 ip->client->medium = NULL;
572 /* Send out the first DHCPREQUEST packet. */
577 * Called when a lease has completely expired and we've
578 * been unable to renew it.
581 state_init(void *ipp)
583 struct interface_info *ip = ipp;
585 ASSERT_STATE(state, S_INIT);
587 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
589 make_discover(ip, ip->client->active);
590 ip->client->xid = ip->client->packet.xid;
591 ip->client->destination = iaddr_broadcast;
592 ip->client->state = S_SELECTING;
593 ip->client->first_sending = cur_time;
594 ip->client->interval = ip->client->config->initial_interval;
596 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
602 * state_selecting is called when one or more DHCPOFFER packets
603 * have been received and a configurable period of time has passed.
606 state_selecting(void *ipp)
608 struct interface_info *ip = ipp;
609 struct client_lease *lp, *next, *picked;
611 ASSERT_STATE(state, S_SELECTING);
613 /* Cancel state_selecting and send_discover timeouts, since either
614 one could have got us here. */
615 cancel_timeout(state_selecting, ip);
616 cancel_timeout(send_discover, ip);
618 /* We have received one or more DHCPOFFER packets. Currently,
619 the only criterion by which we judge leases is whether or
620 not we get a response when we arp for them. */
622 for (lp = ip->client->offered_leases; lp; lp = next) {
625 /* Check to see if we got an ARPREPLY for the address
626 in this particular lease. */
628 script_init("ARPCHECK", lp->medium);
629 script_write_params("check_", lp);
631 /* If the ARPCHECK code detects another
632 machine using the offered address, it exits
633 nonzero. We need to send a DHCPDECLINE and
636 make_decline(ip, lp);
644 free_client_lease(lp);
647 ip->client->offered_leases = NULL;
649 /* If we just tossed all the leases we were offered, go back
652 ip->client->state = S_INIT;
657 /* If it was a BOOTREPLY, we can just take the address right now. */
658 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
659 ip->client->new = picked;
661 /* Make up some lease expiry times
662 XXX these should be configurable. */
663 ip->client->new->expiry = cur_time + 12000;
664 ip->client->new->renewal += cur_time + 8000;
665 ip->client->new->rebind += cur_time + 10000;
667 ip->client->state = S_REQUESTING;
669 /* Bind to the address we received. */
674 /* Go to the REQUESTING state. */
675 ip->client->destination = iaddr_broadcast;
676 ip->client->state = S_REQUESTING;
677 ip->client->first_sending = cur_time;
678 ip->client->interval = ip->client->config->initial_interval;
680 /* Make a DHCPREQUEST packet from the lease we picked. */
681 make_request(ip, picked);
682 ip->client->xid = ip->client->packet.xid;
684 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
685 free_client_lease(picked);
687 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
691 /* state_requesting is called when we receive a DHCPACK message after
692 having sent out one or more DHCPREQUEST packets. */
695 dhcpack(struct packet *packet)
697 struct interface_info *ip = packet->interface;
698 struct client_lease *lease;
700 /* If we're not receptive to an offer right now, or if the offer
701 has an unrecognizable transaction id, then just drop it. */
702 if (packet->interface->client->xid != packet->raw->xid ||
703 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
704 (memcmp(packet->interface->hw_address.haddr,
705 packet->raw->chaddr, packet->raw->hlen)))
708 if (ip->client->state != S_REBOOTING &&
709 ip->client->state != S_REQUESTING &&
710 ip->client->state != S_RENEWING &&
711 ip->client->state != S_REBINDING)
714 note("DHCPACK from %s", piaddr(packet->client_addr));
716 lease = packet_to_lease(packet);
718 note("packet_to_lease failed.");
722 ip->client->new = lease;
724 /* Stop resending DHCPREQUEST. */
725 cancel_timeout(send_request, ip);
727 /* Figure out the lease time. */
728 if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
729 ip->client->new->expiry = getULong(
730 ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
732 ip->client->new->expiry = default_lease_time;
733 /* A number that looks negative here is really just very large,
734 because the lease expiry offset is unsigned. */
735 if (ip->client->new->expiry < 0)
736 ip->client->new->expiry = TIME_MAX;
737 /* XXX should be fixed by resetting the client state */
738 if (ip->client->new->expiry < 60)
739 ip->client->new->expiry = 60;
741 /* Take the server-provided renewal time if there is one;
742 otherwise figure it out according to the spec. */
743 if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
744 ip->client->new->renewal = getULong(
745 ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
747 ip->client->new->renewal = ip->client->new->expiry / 2;
749 /* Same deal with the rebind time. */
750 if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
751 ip->client->new->rebind = getULong(
752 ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
754 ip->client->new->rebind = ip->client->new->renewal +
755 ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
757 ip->client->new->expiry += cur_time;
758 /* Lease lengths can never be negative. */
759 if (ip->client->new->expiry < cur_time)
760 ip->client->new->expiry = TIME_MAX;
761 ip->client->new->renewal += cur_time;
762 if (ip->client->new->renewal < cur_time)
763 ip->client->new->renewal = TIME_MAX;
764 ip->client->new->rebind += cur_time;
765 if (ip->client->new->rebind < cur_time)
766 ip->client->new->rebind = TIME_MAX;
772 bind_lease(struct interface_info *ip)
774 /* Remember the medium. */
775 ip->client->new->medium = ip->client->medium;
777 /* Write out the new lease. */
778 write_client_lease(ip, ip->client->new, 0);
780 /* Run the client script with the new parameters. */
781 script_init((ip->client->state == S_REQUESTING ? "BOUND" :
782 (ip->client->state == S_RENEWING ? "RENEW" :
783 (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))),
784 ip->client->new->medium);
785 if (ip->client->active && ip->client->state != S_REBOOTING)
786 script_write_params("old_", ip->client->active);
787 script_write_params("new_", ip->client->new);
788 if (ip->client->alias)
789 script_write_params("alias_", ip->client->alias);
792 /* Replace the old active lease with the new one. */
793 if (ip->client->active)
794 free_client_lease(ip->client->active);
795 ip->client->active = ip->client->new;
796 ip->client->new = NULL;
798 /* Set up a timeout to start the renewal process. */
799 add_timeout(ip->client->active->renewal, state_bound, ip);
801 note("bound to %s -- renewal in %d seconds.",
802 piaddr(ip->client->active->address),
803 (int)(ip->client->active->renewal - cur_time));
804 ip->client->state = S_BOUND;
805 reinitialize_interfaces();
810 * state_bound is called when we've successfully bound to a particular
811 * lease, but the renewal time on that lease has expired. We are
812 * expected to unicast a DHCPREQUEST to the server that gave us our
816 state_bound(void *ipp)
818 struct interface_info *ip = ipp;
820 ASSERT_STATE(state, S_BOUND);
822 /* T1 has expired. */
823 make_request(ip, ip->client->active);
824 ip->client->xid = ip->client->packet.xid;
826 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
827 memcpy(ip->client->destination.iabuf, ip->client->active->
828 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
829 ip->client->destination.len = 4;
831 ip->client->destination = iaddr_broadcast;
833 ip->client->first_sending = cur_time;
834 ip->client->interval = ip->client->config->initial_interval;
835 ip->client->state = S_RENEWING;
837 /* Send the first packet immediately. */
842 bootp(struct packet *packet)
844 struct iaddrlist *ap;
846 if (packet->raw->op != BOOTREPLY)
849 /* If there's a reject list, make sure this packet's sender isn't
851 for (ap = packet->interface->client->config->reject_list;
853 if (addr_eq(packet->client_addr, ap->addr)) {
854 note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
862 dhcp(struct packet *packet)
864 struct iaddrlist *ap;
865 void (*handler)(struct packet *);
868 switch (packet->packet_type) {
885 /* If there's a reject list, make sure this packet's sender isn't
887 for (ap = packet->interface->client->config->reject_list;
889 if (addr_eq(packet->client_addr, ap->addr)) {
890 note("%s from %s rejected.", type, piaddr(ap->addr));
898 dhcpoffer(struct packet *packet)
900 struct interface_info *ip = packet->interface;
901 struct client_lease *lease, *lp;
903 int arp_timeout_needed, stop_selecting;
904 char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
905 "DHCPOFFER" : "BOOTREPLY";
907 /* If we're not receptive to an offer right now, or if the offer
908 has an unrecognizable transaction id, then just drop it. */
909 if (ip->client->state != S_SELECTING ||
910 packet->interface->client->xid != packet->raw->xid ||
911 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
912 (memcmp(packet->interface->hw_address.haddr,
913 packet->raw->chaddr, packet->raw->hlen)))
916 note("%s from %s", name, piaddr(packet->client_addr));
919 /* If this lease doesn't supply the minimum required parameters,
921 for (i = 0; ip->client->config->required_options[i]; i++) {
922 if (!packet->options[ip->client->config->
923 required_options[i]].len) {
924 note("%s isn't satisfactory.", name);
929 /* If we've already seen this lease, don't record it again. */
930 for (lease = ip->client->offered_leases;
931 lease; lease = lease->next) {
932 if (lease->address.len == sizeof(packet->raw->yiaddr) &&
933 !memcmp(lease->address.iabuf,
934 &packet->raw->yiaddr, lease->address.len)) {
935 debug("%s already seen.", name);
940 lease = packet_to_lease(packet);
942 note("packet_to_lease failed.");
946 /* If this lease was acquired through a BOOTREPLY, record that
948 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
951 /* Record the medium under which this lease was offered. */
952 lease->medium = ip->client->medium;
954 /* Send out an ARP Request for the offered IP address. */
955 script_init("ARPSEND", lease->medium);
956 script_write_params("check_", lease);
957 /* If the script can't send an ARP request without waiting,
958 we'll be waiting when we do the ARPCHECK, so don't wait now. */
960 arp_timeout_needed = 0;
962 arp_timeout_needed = 2;
964 /* Figure out when we're supposed to stop selecting. */
966 ip->client->first_sending + ip->client->config->select_interval;
968 /* If this is the lease we asked for, put it at the head of the
969 list, and don't mess with the arp request timeout. */
970 if (lease->address.len == ip->client->requested_address.len &&
971 !memcmp(lease->address.iabuf,
972 ip->client->requested_address.iabuf,
973 ip->client->requested_address.len)) {
974 lease->next = ip->client->offered_leases;
975 ip->client->offered_leases = lease;
977 /* If we already have an offer, and arping for this
978 offer would take us past the selection timeout,
979 then don't extend the timeout - just hope for the
981 if (ip->client->offered_leases &&
982 (cur_time + arp_timeout_needed) > stop_selecting)
983 arp_timeout_needed = 0;
985 /* Put the lease at the end of the list. */
987 if (!ip->client->offered_leases)
988 ip->client->offered_leases = lease;
990 for (lp = ip->client->offered_leases; lp->next;
997 /* If we're supposed to stop selecting before we've had time
998 to wait for the ARPREPLY, add some delay to wait for
1000 if (stop_selecting - cur_time < arp_timeout_needed)
1001 stop_selecting = cur_time + arp_timeout_needed;
1003 /* If the selecting interval has expired, go immediately to
1004 state_selecting(). Otherwise, time out into
1005 state_selecting at the select interval. */
1006 if (stop_selecting <= 0)
1007 state_selecting(ip);
1009 add_timeout(stop_selecting, state_selecting, ip);
1010 cancel_timeout(send_discover, ip);
1014 /* Allocate a client_lease structure and initialize it from the parameters
1015 in the specified packet. */
1017 struct client_lease *
1018 packet_to_lease(struct packet *packet)
1020 struct client_lease *lease;
1023 lease = malloc(sizeof(struct client_lease));
1026 warning("dhcpoffer: no memory to record lease.");
1030 memset(lease, 0, sizeof(*lease));
1032 /* Copy the lease options. */
1033 for (i = 0; i < 256; i++) {
1034 if (packet->options[i].len) {
1035 lease->options[i].data =
1036 malloc(packet->options[i].len + 1);
1037 if (!lease->options[i].data) {
1038 warning("dhcpoffer: no memory for option %d", i);
1039 free_client_lease(lease);
1042 memcpy(lease->options[i].data,
1043 packet->options[i].data,
1044 packet->options[i].len);
1045 lease->options[i].len =
1046 packet->options[i].len;
1047 lease->options[i].data[lease->options[i].len] =
1050 if (!check_option(lease,i)) {
1051 /* ignore a bogus lease offer */
1052 warning("Invalid lease option - ignoring offer");
1053 free_client_lease(lease);
1059 lease->address.len = sizeof(packet->raw->yiaddr);
1060 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
1062 /* If the server name was filled out, copy it.
1063 Do not attempt to validate the server name as a host name.
1064 RFC 2131 merely states that sname is NUL-terminated (which do
1065 do not assume) and that it is the server's host name. Since
1066 the ISC client and server allow arbitrary characters, we do
1068 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1069 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
1070 packet->raw->sname[0]) {
1071 lease->server_name = malloc(DHCP_SNAME_LEN + 1);
1072 if (!lease->server_name) {
1073 warning("dhcpoffer: no memory for server name.");
1074 free_client_lease(lease);
1077 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
1078 lease->server_name[DHCP_SNAME_LEN]='\0';
1081 /* Ditto for the filename. */
1082 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1083 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
1084 packet->raw->file[0]) {
1085 /* Don't count on the NUL terminator. */
1086 lease->filename = malloc(DHCP_FILE_LEN + 1);
1087 if (!lease->filename) {
1088 warning("dhcpoffer: no memory for filename.");
1089 free_client_lease(lease);
1092 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
1093 lease->filename[DHCP_FILE_LEN]='\0';
1099 dhcpnak(struct packet *packet)
1101 struct interface_info *ip = packet->interface;
1103 /* If we're not receptive to an offer right now, or if the offer
1104 has an unrecognizable transaction id, then just drop it. */
1105 if (packet->interface->client->xid != packet->raw->xid ||
1106 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
1107 (memcmp(packet->interface->hw_address.haddr,
1108 packet->raw->chaddr, packet->raw->hlen)))
1111 if (ip->client->state != S_REBOOTING &&
1112 ip->client->state != S_REQUESTING &&
1113 ip->client->state != S_RENEWING &&
1114 ip->client->state != S_REBINDING)
1117 note("DHCPNAK from %s", piaddr(packet->client_addr));
1119 if (!ip->client->active) {
1120 note("DHCPNAK with no active lease.\n");
1124 free_client_lease(ip->client->active);
1125 ip->client->active = NULL;
1127 /* Stop sending DHCPREQUEST packets... */
1128 cancel_timeout(send_request, ip);
1130 ip->client->state = S_INIT;
1134 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1135 one after the right interval has expired. If we don't get an offer by
1136 the time we reach the panic interval, call the panic function. */
1139 send_discover(void *ipp)
1141 struct interface_info *ip = ipp;
1142 int interval, increase = 1;
1144 /* Figure out how long it's been since we started transmitting. */
1145 interval = cur_time - ip->client->first_sending;
1147 /* If we're past the panic timeout, call the script and tell it
1148 we haven't found anything for this interface yet. */
1149 if (interval > ip->client->config->timeout) {
1154 /* If we're selecting media, try the whole list before doing
1155 the exponential backoff, but if we've already received an
1156 offer, stop looping, because we obviously have it right. */
1157 if (!ip->client->offered_leases &&
1158 ip->client->config->media) {
1161 if (ip->client->medium) {
1162 ip->client->medium = ip->client->medium->next;
1165 if (!ip->client->medium) {
1167 error("No valid media types for %s!", ip->name);
1168 ip->client->medium = ip->client->config->media;
1172 note("Trying medium \"%s\" %d", ip->client->medium->string,
1174 script_init("MEDIUM", ip->client->medium);
1180 * If we're supposed to increase the interval, do so. If it's
1181 * currently zero (i.e., we haven't sent any packets yet), set
1182 * it to one; otherwise, add to it a random number between zero
1183 * and two times itself. On average, this means that it will
1184 * double with every transmission.
1187 if (!ip->client->interval)
1188 ip->client->interval =
1189 ip->client->config->initial_interval;
1191 ip->client->interval += (arc4random() >> 2) %
1192 (2 * ip->client->interval);
1195 /* Don't backoff past cutoff. */
1196 if (ip->client->interval >
1197 ip->client->config->backoff_cutoff)
1198 ip->client->interval =
1199 ((ip->client->config->backoff_cutoff / 2)
1200 + ((arc4random() >> 2) %
1201 ip->client->config->backoff_cutoff));
1202 } else if (!ip->client->interval)
1203 ip->client->interval =
1204 ip->client->config->initial_interval;
1206 /* If the backoff would take us to the panic timeout, just use that
1208 if (cur_time + ip->client->interval >
1209 ip->client->first_sending + ip->client->config->timeout)
1210 ip->client->interval =
1211 (ip->client->first_sending +
1212 ip->client->config->timeout) - cur_time + 1;
1214 /* Record the number of seconds since we started sending. */
1215 if (interval < 65536)
1216 ip->client->packet.secs = htons(interval);
1218 ip->client->packet.secs = htons(65535);
1219 ip->client->secs = ip->client->packet.secs;
1221 note("DHCPDISCOVER on %s to %s port %d interval %d",
1222 ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
1223 ntohs(sockaddr_broadcast.sin_port),
1224 (int)ip->client->interval);
1226 /* Send out a packet. */
1227 (void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
1228 inaddr_any, &sockaddr_broadcast, NULL);
1230 add_timeout(cur_time + ip->client->interval, send_discover, ip);
1234 * state_panic gets called if we haven't received any offers in a preset
1235 * amount of time. When this happens, we try to use existing leases
1236 * that haven't yet expired, and failing that, we call the client script
1237 * and hope it can do something.
1240 state_panic(void *ipp)
1242 struct interface_info *ip = ipp;
1243 struct client_lease *loop = ip->client->active;
1244 struct client_lease *lp;
1246 note("No DHCPOFFERS received.");
1248 /* We may not have an active lease, but we may have some
1249 predefined leases that we can try. */
1250 if (!ip->client->active && ip->client->leases)
1253 /* Run through the list of leases and see if one can be used. */
1254 while (ip->client->active) {
1255 if (ip->client->active->expiry > cur_time) {
1256 note("Trying recorded lease %s",
1257 piaddr(ip->client->active->address));
1258 /* Run the client script with the existing
1260 script_init("TIMEOUT",
1261 ip->client->active->medium);
1262 script_write_params("new_", ip->client->active);
1263 if (ip->client->alias)
1264 script_write_params("alias_",
1267 /* If the old lease is still good and doesn't
1268 yet need renewal, go into BOUND state and
1269 timeout at the renewal time. */
1272 ip->client->active->renewal) {
1273 ip->client->state = S_BOUND;
1274 note("bound: renewal in %d seconds.",
1275 (int)(ip->client->active->renewal -
1278 ip->client->active->renewal,
1281 ip->client->state = S_BOUND;
1282 note("bound: immediate renewal.");
1285 reinitialize_interfaces();
1291 /* If there are no other leases, give up. */
1292 if (!ip->client->leases) {
1293 ip->client->leases = ip->client->active;
1294 ip->client->active = NULL;
1299 /* Otherwise, put the active lease at the end of the
1300 lease list, and try another lease.. */
1301 for (lp = ip->client->leases; lp->next; lp = lp->next)
1303 lp->next = ip->client->active;
1305 lp->next->next = NULL;
1306 ip->client->active = ip->client->leases;
1307 ip->client->leases = ip->client->leases->next;
1309 /* If we already tried this lease, we've exhausted the
1310 set of leases, so we might as well give up for
1312 if (ip->client->active == loop)
1315 loop = ip->client->active;
1318 /* No leases were available, or what was available didn't work, so
1319 tell the shell script that we failed to allocate an address,
1320 and try again later. */
1321 note("No working leases in persistent database - sleeping.\n");
1322 script_init("FAIL", NULL);
1323 if (ip->client->alias)
1324 script_write_params("alias_", ip->client->alias);
1326 ip->client->state = S_INIT;
1327 add_timeout(cur_time + ip->client->config->retry_interval, state_init,
1333 send_request(void *ipp)
1335 struct interface_info *ip = ipp;
1336 struct sockaddr_in destination;
1337 struct in_addr from;
1340 /* Figure out how long it's been since we started transmitting. */
1341 interval = cur_time - ip->client->first_sending;
1343 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1344 past the reboot timeout, go to INIT and see if we can
1345 DISCOVER an address... */
1346 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1347 means either that we're on a network with no DHCP server,
1348 or that our server is down. In the latter case, assuming
1349 that there is a backup DHCP server, DHCPDISCOVER will get
1350 us a new address, but we could also have successfully
1351 reused our old address. In the former case, we're hosed
1352 anyway. This is not a win-prone situation. */
1353 if ((ip->client->state == S_REBOOTING ||
1354 ip->client->state == S_REQUESTING) &&
1355 interval > ip->client->config->reboot_timeout) {
1357 ip->client->state = S_INIT;
1358 cancel_timeout(send_request, ip);
1363 /* If we're in the reboot state, make sure the media is set up
1365 if (ip->client->state == S_REBOOTING &&
1366 !ip->client->medium &&
1367 ip->client->active->medium ) {
1368 script_init("MEDIUM", ip->client->active->medium);
1370 /* If the medium we chose won't fly, go to INIT state. */
1374 /* Record the medium. */
1375 ip->client->medium = ip->client->active->medium;
1378 /* If the lease has expired, relinquish the address and go back
1379 to the INIT state. */
1380 if (ip->client->state != S_REQUESTING &&
1381 cur_time > ip->client->active->expiry) {
1382 /* Run the client script with the new parameters. */
1383 script_init("EXPIRE", NULL);
1384 script_write_params("old_", ip->client->active);
1385 if (ip->client->alias)
1386 script_write_params("alias_", ip->client->alias);
1389 /* Now do a preinit on the interface so that we can
1390 discover a new address. */
1391 script_init("PREINIT", NULL);
1392 if (ip->client->alias)
1393 script_write_params("alias_", ip->client->alias);
1396 ip->client->state = S_INIT;
1401 /* Do the exponential backoff... */
1402 if (!ip->client->interval)
1403 ip->client->interval = ip->client->config->initial_interval;
1405 ip->client->interval += ((arc4random() >> 2) %
1406 (2 * ip->client->interval));
1408 /* Don't backoff past cutoff. */
1409 if (ip->client->interval >
1410 ip->client->config->backoff_cutoff)
1411 ip->client->interval =
1412 ((ip->client->config->backoff_cutoff / 2) +
1413 ((arc4random() >> 2) % ip->client->interval));
1415 /* If the backoff would take us to the expiry time, just set the
1416 timeout to the expiry time. */
1417 if (ip->client->state != S_REQUESTING &&
1418 cur_time + ip->client->interval >
1419 ip->client->active->expiry)
1420 ip->client->interval =
1421 ip->client->active->expiry - cur_time + 1;
1423 /* If the lease T2 time has elapsed, or if we're not yet bound,
1424 broadcast the DHCPREQUEST rather than unicasting. */
1425 memset(&destination, 0, sizeof(destination));
1426 if (ip->client->state == S_REQUESTING ||
1427 ip->client->state == S_REBOOTING ||
1428 cur_time > ip->client->active->rebind)
1429 destination.sin_addr.s_addr = INADDR_BROADCAST;
1431 memcpy(&destination.sin_addr.s_addr,
1432 ip->client->destination.iabuf,
1433 sizeof(destination.sin_addr.s_addr));
1434 destination.sin_port = htons(REMOTE_PORT);
1435 destination.sin_family = AF_INET;
1436 destination.sin_len = sizeof(destination);
1438 if (ip->client->state != S_REQUESTING)
1439 memcpy(&from, ip->client->active->address.iabuf,
1442 from.s_addr = INADDR_ANY;
1444 /* Record the number of seconds since we started sending. */
1445 if (ip->client->state == S_REQUESTING)
1446 ip->client->packet.secs = ip->client->secs;
1448 if (interval < 65536)
1449 ip->client->packet.secs = htons(interval);
1451 ip->client->packet.secs = htons(65535);
1454 note("DHCPREQUEST on %s to %s port %d", ip->name,
1455 inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
1457 /* Send out a packet. */
1458 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1459 from, &destination, NULL);
1461 add_timeout(cur_time + ip->client->interval, send_request, ip);
1465 send_decline(void *ipp)
1467 struct interface_info *ip = ipp;
1469 note("DHCPDECLINE on %s to %s port %d", ip->name,
1470 inet_ntoa(sockaddr_broadcast.sin_addr),
1471 ntohs(sockaddr_broadcast.sin_port));
1473 /* Send out a packet. */
1474 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1475 inaddr_any, &sockaddr_broadcast, NULL);
1479 make_discover(struct interface_info *ip, struct client_lease *lease)
1481 unsigned char discover = DHCPDISCOVER;
1482 struct tree_cache *options[256];
1483 struct tree_cache option_elements[256];
1486 memset(option_elements, 0, sizeof(option_elements));
1487 memset(options, 0, sizeof(options));
1488 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1490 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1491 i = DHO_DHCP_MESSAGE_TYPE;
1492 options[i] = &option_elements[i];
1493 options[i]->value = &discover;
1494 options[i]->len = sizeof(discover);
1495 options[i]->buf_size = sizeof(discover);
1496 options[i]->timeout = 0xFFFFFFFF;
1498 /* Request the options we want */
1499 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1500 options[i] = &option_elements[i];
1501 options[i]->value = ip->client->config->requested_options;
1502 options[i]->len = ip->client->config->requested_option_count;
1503 options[i]->buf_size =
1504 ip->client->config->requested_option_count;
1505 options[i]->timeout = 0xFFFFFFFF;
1507 /* If we had an address, try to get it again. */
1509 ip->client->requested_address = lease->address;
1510 i = DHO_DHCP_REQUESTED_ADDRESS;
1511 options[i] = &option_elements[i];
1512 options[i]->value = lease->address.iabuf;
1513 options[i]->len = lease->address.len;
1514 options[i]->buf_size = lease->address.len;
1515 options[i]->timeout = 0xFFFFFFFF;
1517 ip->client->requested_address.len = 0;
1519 /* Send any options requested in the config file. */
1520 for (i = 0; i < 256; i++)
1522 ip->client->config->send_options[i].data) {
1523 options[i] = &option_elements[i];
1525 ip->client->config->send_options[i].data;
1527 ip->client->config->send_options[i].len;
1528 options[i]->buf_size =
1529 ip->client->config->send_options[i].len;
1530 options[i]->timeout = 0xFFFFFFFF;
1533 /* send host name if not set via config file. */
1534 char hostname[_POSIX_HOST_NAME_MAX+1];
1535 if (!options[DHO_HOST_NAME]) {
1536 if (gethostname(hostname, sizeof(hostname)) == 0) {
1538 char* posDot = strchr(hostname, '.');
1540 len = posDot - hostname;
1542 len = strlen(hostname);
1543 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1544 options[DHO_HOST_NAME]->value = hostname;
1545 options[DHO_HOST_NAME]->len = len;
1546 options[DHO_HOST_NAME]->buf_size = len;
1547 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1551 /* set unique client identifier */
1552 char client_ident[sizeof(struct hardware)];
1553 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1554 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1555 ip->hw_address.hlen : sizeof(client_ident)-1;
1556 client_ident[0] = ip->hw_address.htype;
1557 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1558 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1559 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1560 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1561 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1562 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1565 /* Set up the option buffer... */
1566 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1567 options, 0, 0, 0, NULL, 0);
1568 if (ip->client->packet_length < BOOTP_MIN_LEN)
1569 ip->client->packet_length = BOOTP_MIN_LEN;
1571 ip->client->packet.op = BOOTREQUEST;
1572 ip->client->packet.htype = ip->hw_address.htype;
1573 ip->client->packet.hlen = ip->hw_address.hlen;
1574 ip->client->packet.hops = 0;
1575 ip->client->packet.xid = arc4random();
1576 ip->client->packet.secs = 0; /* filled in by send_discover. */
1577 ip->client->packet.flags = 0;
1579 memset(&(ip->client->packet.ciaddr),
1580 0, sizeof(ip->client->packet.ciaddr));
1581 memset(&(ip->client->packet.yiaddr),
1582 0, sizeof(ip->client->packet.yiaddr));
1583 memset(&(ip->client->packet.siaddr),
1584 0, sizeof(ip->client->packet.siaddr));
1585 memset(&(ip->client->packet.giaddr),
1586 0, sizeof(ip->client->packet.giaddr));
1587 memcpy(ip->client->packet.chaddr,
1588 ip->hw_address.haddr, ip->hw_address.hlen);
1593 make_request(struct interface_info *ip, struct client_lease * lease)
1595 unsigned char request = DHCPREQUEST;
1596 struct tree_cache *options[256];
1597 struct tree_cache option_elements[256];
1600 memset(options, 0, sizeof(options));
1601 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1603 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1604 i = DHO_DHCP_MESSAGE_TYPE;
1605 options[i] = &option_elements[i];
1606 options[i]->value = &request;
1607 options[i]->len = sizeof(request);
1608 options[i]->buf_size = sizeof(request);
1609 options[i]->timeout = 0xFFFFFFFF;
1611 /* Request the options we want */
1612 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1613 options[i] = &option_elements[i];
1614 options[i]->value = ip->client->config->requested_options;
1615 options[i]->len = ip->client->config->requested_option_count;
1616 options[i]->buf_size =
1617 ip->client->config->requested_option_count;
1618 options[i]->timeout = 0xFFFFFFFF;
1620 /* If we are requesting an address that hasn't yet been assigned
1621 to us, use the DHCP Requested Address option. */
1622 if (ip->client->state == S_REQUESTING) {
1623 /* Send back the server identifier... */
1624 i = DHO_DHCP_SERVER_IDENTIFIER;
1625 options[i] = &option_elements[i];
1626 options[i]->value = lease->options[i].data;
1627 options[i]->len = lease->options[i].len;
1628 options[i]->buf_size = lease->options[i].len;
1629 options[i]->timeout = 0xFFFFFFFF;
1631 if (ip->client->state == S_REQUESTING ||
1632 ip->client->state == S_REBOOTING) {
1633 ip->client->requested_address = lease->address;
1634 i = DHO_DHCP_REQUESTED_ADDRESS;
1635 options[i] = &option_elements[i];
1636 options[i]->value = lease->address.iabuf;
1637 options[i]->len = lease->address.len;
1638 options[i]->buf_size = lease->address.len;
1639 options[i]->timeout = 0xFFFFFFFF;
1641 ip->client->requested_address.len = 0;
1643 /* Send any options requested in the config file. */
1644 for (i = 0; i < 256; i++)
1646 ip->client->config->send_options[i].data) {
1647 options[i] = &option_elements[i];
1649 ip->client->config->send_options[i].data;
1651 ip->client->config->send_options[i].len;
1652 options[i]->buf_size =
1653 ip->client->config->send_options[i].len;
1654 options[i]->timeout = 0xFFFFFFFF;
1657 /* send host name if not set via config file. */
1658 char hostname[_POSIX_HOST_NAME_MAX+1];
1659 if (!options[DHO_HOST_NAME]) {
1660 if (gethostname(hostname, sizeof(hostname)) == 0) {
1662 char* posDot = strchr(hostname, '.');
1664 len = posDot - hostname;
1666 len = strlen(hostname);
1667 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1668 options[DHO_HOST_NAME]->value = hostname;
1669 options[DHO_HOST_NAME]->len = len;
1670 options[DHO_HOST_NAME]->buf_size = len;
1671 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1675 /* set unique client identifier */
1676 char client_ident[sizeof(struct hardware)];
1677 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1678 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1679 ip->hw_address.hlen : sizeof(client_ident)-1;
1680 client_ident[0] = ip->hw_address.htype;
1681 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1682 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1683 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1684 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1685 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1686 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1689 /* Set up the option buffer... */
1690 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1691 options, 0, 0, 0, NULL, 0);
1692 if (ip->client->packet_length < BOOTP_MIN_LEN)
1693 ip->client->packet_length = BOOTP_MIN_LEN;
1695 ip->client->packet.op = BOOTREQUEST;
1696 ip->client->packet.htype = ip->hw_address.htype;
1697 ip->client->packet.hlen = ip->hw_address.hlen;
1698 ip->client->packet.hops = 0;
1699 ip->client->packet.xid = ip->client->xid;
1700 ip->client->packet.secs = 0; /* Filled in by send_request. */
1702 /* If we own the address we're requesting, put it in ciaddr;
1703 otherwise set ciaddr to zero. */
1704 if (ip->client->state == S_BOUND ||
1705 ip->client->state == S_RENEWING ||
1706 ip->client->state == S_REBINDING) {
1707 memcpy(&ip->client->packet.ciaddr,
1708 lease->address.iabuf, lease->address.len);
1709 ip->client->packet.flags = 0;
1711 memset(&ip->client->packet.ciaddr, 0,
1712 sizeof(ip->client->packet.ciaddr));
1713 ip->client->packet.flags = 0;
1716 memset(&ip->client->packet.yiaddr, 0,
1717 sizeof(ip->client->packet.yiaddr));
1718 memset(&ip->client->packet.siaddr, 0,
1719 sizeof(ip->client->packet.siaddr));
1720 memset(&ip->client->packet.giaddr, 0,
1721 sizeof(ip->client->packet.giaddr));
1722 memcpy(ip->client->packet.chaddr,
1723 ip->hw_address.haddr, ip->hw_address.hlen);
1727 make_decline(struct interface_info *ip, struct client_lease *lease)
1729 struct tree_cache *options[256], message_type_tree;
1730 struct tree_cache requested_address_tree;
1731 struct tree_cache server_id_tree, client_id_tree;
1732 unsigned char decline = DHCPDECLINE;
1735 memset(options, 0, sizeof(options));
1736 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1738 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1739 i = DHO_DHCP_MESSAGE_TYPE;
1740 options[i] = &message_type_tree;
1741 options[i]->value = &decline;
1742 options[i]->len = sizeof(decline);
1743 options[i]->buf_size = sizeof(decline);
1744 options[i]->timeout = 0xFFFFFFFF;
1746 /* Send back the server identifier... */
1747 i = DHO_DHCP_SERVER_IDENTIFIER;
1748 options[i] = &server_id_tree;
1749 options[i]->value = lease->options[i].data;
1750 options[i]->len = lease->options[i].len;
1751 options[i]->buf_size = lease->options[i].len;
1752 options[i]->timeout = 0xFFFFFFFF;
1754 /* Send back the address we're declining. */
1755 i = DHO_DHCP_REQUESTED_ADDRESS;
1756 options[i] = &requested_address_tree;
1757 options[i]->value = lease->address.iabuf;
1758 options[i]->len = lease->address.len;
1759 options[i]->buf_size = lease->address.len;
1760 options[i]->timeout = 0xFFFFFFFF;
1762 /* Send the uid if the user supplied one. */
1763 i = DHO_DHCP_CLIENT_IDENTIFIER;
1764 if (ip->client->config->send_options[i].len) {
1765 options[i] = &client_id_tree;
1766 options[i]->value = ip->client->config->send_options[i].data;
1767 options[i]->len = ip->client->config->send_options[i].len;
1768 options[i]->buf_size = ip->client->config->send_options[i].len;
1769 options[i]->timeout = 0xFFFFFFFF;
1773 /* Set up the option buffer... */
1774 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1775 options, 0, 0, 0, NULL, 0);
1776 if (ip->client->packet_length < BOOTP_MIN_LEN)
1777 ip->client->packet_length = BOOTP_MIN_LEN;
1779 ip->client->packet.op = BOOTREQUEST;
1780 ip->client->packet.htype = ip->hw_address.htype;
1781 ip->client->packet.hlen = ip->hw_address.hlen;
1782 ip->client->packet.hops = 0;
1783 ip->client->packet.xid = ip->client->xid;
1784 ip->client->packet.secs = 0; /* Filled in by send_request. */
1785 ip->client->packet.flags = 0;
1787 /* ciaddr must always be zero. */
1788 memset(&ip->client->packet.ciaddr, 0,
1789 sizeof(ip->client->packet.ciaddr));
1790 memset(&ip->client->packet.yiaddr, 0,
1791 sizeof(ip->client->packet.yiaddr));
1792 memset(&ip->client->packet.siaddr, 0,
1793 sizeof(ip->client->packet.siaddr));
1794 memset(&ip->client->packet.giaddr, 0,
1795 sizeof(ip->client->packet.giaddr));
1796 memcpy(ip->client->packet.chaddr,
1797 ip->hw_address.haddr, ip->hw_address.hlen);
1801 free_client_lease(struct client_lease *lease)
1805 if (lease->server_name)
1806 free(lease->server_name);
1807 if (lease->filename)
1808 free(lease->filename);
1809 for (i = 0; i < 256; i++) {
1810 if (lease->options[i].len)
1811 free(lease->options[i].data);
1819 rewrite_client_leases(void)
1821 struct client_lease *lp;
1824 leaseFile = fopen(path_dhclient_db, "w");
1826 error("can't create %s: %m", path_dhclient_db);
1832 for (lp = ifi->client->leases; lp; lp = lp->next)
1833 write_client_lease(ifi, lp, 1);
1834 if (ifi->client->active)
1835 write_client_lease(ifi, ifi->client->active, 1);
1838 ftruncate(fileno(leaseFile), ftello(leaseFile));
1839 fsync(fileno(leaseFile));
1843 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1846 static int leases_written;
1851 if (leases_written++ > 20) {
1852 rewrite_client_leases();
1857 /* If the lease came from the config file, we don't need to stash
1858 a copy in the lease database. */
1859 if (lease->is_static)
1862 if (!leaseFile) { /* XXX */
1863 leaseFile = fopen(path_dhclient_db, "w");
1865 error("can't create %s: %m", path_dhclient_db);
1868 fprintf(leaseFile, "lease {\n");
1869 if (lease->is_bootp)
1870 fprintf(leaseFile, " bootp;\n");
1871 fprintf(leaseFile, " interface \"%s\";\n", ip->name);
1872 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
1873 if (lease->filename)
1874 fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
1875 if (lease->server_name)
1876 fprintf(leaseFile, " server-name \"%s\";\n",
1877 lease->server_name);
1879 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string);
1880 for (i = 0; i < 256; i++)
1881 if (lease->options[i].len)
1882 fprintf(leaseFile, " option %s %s;\n",
1883 dhcp_options[i].name,
1884 pretty_print_option(i, lease->options[i].data,
1885 lease->options[i].len, 1, 1));
1887 t = gmtime(&lease->renewal);
1888 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1889 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1890 t->tm_hour, t->tm_min, t->tm_sec);
1891 t = gmtime(&lease->rebind);
1892 fprintf(leaseFile, " rebind %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->expiry);
1896 fprintf(leaseFile, " expire %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 fprintf(leaseFile, "}\n");
1904 script_init(char *reason, struct string_list *medium)
1906 size_t len, mediumlen = 0;
1907 struct imsg_hdr hdr;
1911 if (medium != NULL && medium->string != NULL)
1912 mediumlen = strlen(medium->string);
1914 hdr.code = IMSG_SCRIPT_INIT;
1915 hdr.len = sizeof(struct imsg_hdr) +
1916 sizeof(size_t) + mediumlen +
1917 sizeof(size_t) + strlen(reason);
1919 if ((buf = buf_open(hdr.len)) == NULL)
1920 error("buf_open: %m");
1923 errs += buf_add(buf, &hdr, sizeof(hdr));
1924 errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
1926 errs += buf_add(buf, medium->string, mediumlen);
1927 len = strlen(reason);
1928 errs += buf_add(buf, &len, sizeof(len));
1929 errs += buf_add(buf, reason, len);
1932 error("buf_add: %m");
1934 if (buf_close(privfd, buf) == -1)
1935 error("buf_close: %m");
1939 priv_script_init(char *reason, char *medium)
1941 struct interface_info *ip = ifi;
1944 ip->client->scriptEnvsize = 100;
1945 if (ip->client->scriptEnv == NULL)
1946 ip->client->scriptEnv =
1947 malloc(ip->client->scriptEnvsize * sizeof(char *));
1948 if (ip->client->scriptEnv == NULL)
1949 error("script_init: no memory for environment");
1951 ip->client->scriptEnv[0] = strdup(CLIENT_PATH);
1952 if (ip->client->scriptEnv[0] == NULL)
1953 error("script_init: no memory for environment");
1955 ip->client->scriptEnv[1] = NULL;
1957 script_set_env(ip->client, "", "interface", ip->name);
1960 script_set_env(ip->client, "", "medium", medium);
1962 script_set_env(ip->client, "", "reason", reason);
1967 priv_script_write_params(char *prefix, struct client_lease *lease)
1969 struct interface_info *ip = ifi;
1970 u_int8_t dbuf[1500], *dp = NULL;
1974 script_set_env(ip->client, prefix, "ip_address",
1975 piaddr(lease->address));
1977 if (ip->client->config->default_actions[DHO_SUBNET_MASK] ==
1979 dp = ip->client->config->defaults[DHO_SUBNET_MASK].data;
1980 len = ip->client->config->defaults[DHO_SUBNET_MASK].len;
1982 dp = lease->options[DHO_SUBNET_MASK].data;
1983 len = lease->options[DHO_SUBNET_MASK].len;
1985 if (len && (len < sizeof(lease->address.iabuf))) {
1986 struct iaddr netmask, subnet, broadcast;
1988 memcpy(netmask.iabuf, dp, len);
1990 subnet = subnet_number(lease->address, netmask);
1992 script_set_env(ip->client, prefix, "network_number",
1994 if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
1995 broadcast = broadcast_addr(subnet, netmask);
1997 script_set_env(ip->client, prefix,
1998 "broadcast_address",
2004 if (lease->filename)
2005 script_set_env(ip->client, prefix, "filename", lease->filename);
2006 if (lease->server_name)
2007 script_set_env(ip->client, prefix, "server_name",
2008 lease->server_name);
2009 for (i = 0; i < 256; i++) {
2012 if (ip->client->config->defaults[i].len) {
2013 if (lease->options[i].len) {
2015 ip->client->config->default_actions[i]) {
2016 case ACTION_DEFAULT:
2017 dp = lease->options[i].data;
2018 len = lease->options[i].len;
2020 case ACTION_SUPERSEDE:
2023 config->defaults[i].data;
2025 config->defaults[i].len;
2027 case ACTION_PREPEND:
2029 config->defaults[i].len +
2030 lease->options[i].len;
2031 if (len >= sizeof(dbuf)) {
2032 warning("no space to %s %s",
2034 dhcp_options[i].name);
2040 config->defaults[i].data,
2042 config->defaults[i].len);
2043 memcpy(dp + ip->client->
2044 config->defaults[i].len,
2045 lease->options[i].data,
2046 lease->options[i].len);
2051 * When we append, we assume that we're
2052 * appending to text. Some MS servers
2053 * include a NUL byte at the end of
2054 * the search string provided.
2057 config->defaults[i].len +
2058 lease->options[i].len;
2059 if (len >= sizeof(dbuf)) {
2060 warning("no space to %s %s",
2062 dhcp_options[i].name);
2066 lease->options[i].data,
2067 lease->options[i].len);
2068 for (dp = dbuf + lease->options[i].len;
2069 dp > dbuf; dp--, len--)
2074 config->defaults[i].data,
2076 config->defaults[i].len);
2082 config->defaults[i].data;
2084 config->defaults[i].len;
2086 } else if (lease->options[i].len) {
2087 len = lease->options[i].len;
2088 dp = lease->options[i].data;
2095 if (dhcp_option_ev_name(name, sizeof(name),
2097 script_set_env(ip->client, prefix, name,
2098 pretty_print_option(i, dp, len, 0, 0));
2101 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
2102 script_set_env(ip->client, prefix, "expiry", tbuf);
2106 script_write_params(char *prefix, struct client_lease *lease)
2108 size_t fn_len = 0, sn_len = 0, pr_len = 0;
2109 struct imsg_hdr hdr;
2113 if (lease->filename != NULL)
2114 fn_len = strlen(lease->filename);
2115 if (lease->server_name != NULL)
2116 sn_len = strlen(lease->server_name);
2118 pr_len = strlen(prefix);
2120 hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
2121 hdr.len = sizeof(hdr) + sizeof(struct client_lease) +
2122 sizeof(size_t) + fn_len + sizeof(size_t) + sn_len +
2123 sizeof(size_t) + pr_len;
2125 for (i = 0; i < 256; i++)
2126 hdr.len += sizeof(int) + lease->options[i].len;
2128 scripttime = time(NULL);
2130 if ((buf = buf_open(hdr.len)) == NULL)
2131 error("buf_open: %m");
2134 errs += buf_add(buf, &hdr, sizeof(hdr));
2135 errs += buf_add(buf, lease, sizeof(struct client_lease));
2136 errs += buf_add(buf, &fn_len, sizeof(fn_len));
2137 errs += buf_add(buf, lease->filename, fn_len);
2138 errs += buf_add(buf, &sn_len, sizeof(sn_len));
2139 errs += buf_add(buf, lease->server_name, sn_len);
2140 errs += buf_add(buf, &pr_len, sizeof(pr_len));
2141 errs += buf_add(buf, prefix, pr_len);
2143 for (i = 0; i < 256; i++) {
2144 errs += buf_add(buf, &lease->options[i].len,
2145 sizeof(lease->options[i].len));
2146 errs += buf_add(buf, lease->options[i].data,
2147 lease->options[i].len);
2151 error("buf_add: %m");
2153 if (buf_close(privfd, buf) == -1)
2154 error("buf_close: %m");
2160 struct imsg_hdr hdr;
2164 hdr.code = IMSG_SCRIPT_GO;
2165 hdr.len = sizeof(struct imsg_hdr);
2167 if ((buf = buf_open(hdr.len)) == NULL)
2168 error("buf_open: %m");
2170 if (buf_add(buf, &hdr, sizeof(hdr)))
2171 error("buf_add: %m");
2173 if (buf_close(privfd, buf) == -1)
2174 error("buf_close: %m");
2176 bzero(&hdr, sizeof(hdr));
2177 buf_read(privfd, &hdr, sizeof(hdr));
2178 if (hdr.code != IMSG_SCRIPT_GO_RET)
2179 error("unexpected msg type %u", hdr.code);
2180 if (hdr.len != sizeof(hdr) + sizeof(int))
2181 error("received corrupted message");
2182 buf_read(privfd, &ret, sizeof(ret));
2184 scripttime = time(NULL);
2190 priv_script_go(void)
2192 char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI";
2193 static char client_path[] = CLIENT_PATH;
2194 struct interface_info *ip = ifi;
2195 int pid, wpid, wstatus;
2197 scripttime = time(NULL);
2200 scriptName = ip->client->config->script_name;
2201 envp = ip->client->scriptEnv;
2203 scriptName = top_level_config.script_name;
2205 epp[1] = client_path;
2210 argv[0] = scriptName;
2219 wpid = wait(&wstatus);
2220 } while (wpid != pid && wpid > 0);
2226 execve(scriptName, argv, envp);
2227 error("execve (%s, ...): %m", scriptName);
2231 script_flush_env(ip->client);
2233 return (wstatus & 0xff);
2237 script_set_env(struct client_state *client, const char *prefix,
2238 const char *name, const char *value)
2242 namelen = strlen(name);
2244 for (i = 0; client->scriptEnv[i]; i++)
2245 if (strncmp(client->scriptEnv[i], name, namelen) == 0 &&
2246 client->scriptEnv[i][namelen] == '=')
2249 if (client->scriptEnv[i])
2250 /* Reuse the slot. */
2251 free(client->scriptEnv[i]);
2253 /* New variable. Expand if necessary. */
2254 if (i >= client->scriptEnvsize - 1) {
2255 char **newscriptEnv;
2256 int newscriptEnvsize = client->scriptEnvsize + 50;
2258 newscriptEnv = realloc(client->scriptEnv,
2260 if (newscriptEnv == NULL) {
2261 free(client->scriptEnv);
2262 client->scriptEnv = NULL;
2263 client->scriptEnvsize = 0;
2264 error("script_set_env: no memory for variable");
2266 client->scriptEnv = newscriptEnv;
2267 client->scriptEnvsize = newscriptEnvsize;
2269 /* need to set the NULL pointer at end of array beyond
2271 client->scriptEnv[i + 1] = NULL;
2273 /* Allocate space and format the variable in the appropriate slot. */
2274 client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 +
2276 if (client->scriptEnv[i] == NULL)
2277 error("script_set_env: no memory for variable assignment");
2279 /* No `` or $() command substitution allowed in environment values! */
2280 for (j=0; j < strlen(value); j++)
2284 error("illegal character (%c) in value '%s'", value[j],
2288 snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
2289 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
2293 script_flush_env(struct client_state *client)
2297 for (i = 0; client->scriptEnv[i]; i++) {
2298 free(client->scriptEnv[i]);
2299 client->scriptEnv[i] = NULL;
2301 client->scriptEnvsize = 0;
2305 dhcp_option_ev_name(char *buf, size_t buflen, struct option *option)
2309 for (i = 0; option->name[i]; i++) {
2310 if (i + 1 == buflen)
2312 if (option->name[i] == '-')
2315 buf[i] = option->name[i];
2325 static int state = 0;
2327 if (no_daemon || state)
2332 /* Stop logging to stderr... */
2335 if (daemon(1, 0) == -1)
2338 if (pidfile != NULL)
2339 pidfile_write(pidfile);
2341 /* we are chrooted, daemon(3) fails to open /dev/null */
2343 dup2(nullfd, STDIN_FILENO);
2344 dup2(nullfd, STDOUT_FILENO);
2345 dup2(nullfd, STDERR_FILENO);
2352 check_option(struct client_lease *l, int option)
2357 /* we use this, since this is what gets passed to dhclient-script */
2359 opbuf = pretty_print_option(option, l->options[option].data,
2360 l->options[option].len, 0, 0);
2362 sbuf = option_as_string(option, l->options[option].data,
2363 l->options[option].len);
2366 case DHO_SUBNET_MASK:
2367 case DHO_TIME_SERVERS:
2368 case DHO_NAME_SERVERS:
2370 case DHO_DOMAIN_NAME_SERVERS:
2371 case DHO_LOG_SERVERS:
2372 case DHO_COOKIE_SERVERS:
2373 case DHO_LPR_SERVERS:
2374 case DHO_IMPRESS_SERVERS:
2375 case DHO_RESOURCE_LOCATION_SERVERS:
2376 case DHO_SWAP_SERVER:
2377 case DHO_BROADCAST_ADDRESS:
2378 case DHO_NIS_SERVERS:
2379 case DHO_NTP_SERVERS:
2380 case DHO_NETBIOS_NAME_SERVERS:
2381 case DHO_NETBIOS_DD_SERVER:
2382 case DHO_FONT_SERVERS:
2383 case DHO_DHCP_SERVER_IDENTIFIER:
2384 case DHO_NISPLUS_SERVERS:
2385 case DHO_MOBILE_IP_HOME_AGENT:
2386 case DHO_SMTP_SERVER:
2387 case DHO_POP_SERVER:
2388 case DHO_NNTP_SERVER:
2389 case DHO_WWW_SERVER:
2390 case DHO_FINGER_SERVER:
2391 case DHO_IRC_SERVER:
2392 case DHO_STREETTALK_SERVER:
2393 case DHO_STREETTALK_DA_SERVER:
2394 if (!ipv4addrs(opbuf)) {
2395 warning("Invalid IP address in option: %s", opbuf);
2400 case DHO_NIS_DOMAIN:
2401 case DHO_NISPLUS_DOMAIN:
2402 case DHO_TFTP_SERVER_NAME:
2403 if (!res_hnok(sbuf)) {
2404 warning("Bogus Host Name option %d: %s (%s)", option,
2406 l->options[option].len = 0;
2407 free(l->options[option].data);
2410 case DHO_DOMAIN_NAME:
2411 case DHO_DOMAIN_SEARCH:
2412 if (!res_hnok(sbuf)) {
2413 if (!check_search(sbuf)) {
2414 warning("Bogus domain search list %d: %s (%s)",
2415 option, sbuf, opbuf);
2416 l->options[option].len = 0;
2417 free(l->options[option].data);
2422 case DHO_TIME_OFFSET:
2424 case DHO_MERIT_DUMP:
2426 case DHO_EXTENSIONS_PATH:
2427 case DHO_IP_FORWARDING:
2428 case DHO_NON_LOCAL_SOURCE_ROUTING:
2429 case DHO_POLICY_FILTER:
2430 case DHO_MAX_DGRAM_REASSEMBLY:
2431 case DHO_DEFAULT_IP_TTL:
2432 case DHO_PATH_MTU_AGING_TIMEOUT:
2433 case DHO_PATH_MTU_PLATEAU_TABLE:
2434 case DHO_INTERFACE_MTU:
2435 case DHO_ALL_SUBNETS_LOCAL:
2436 case DHO_PERFORM_MASK_DISCOVERY:
2437 case DHO_MASK_SUPPLIER:
2438 case DHO_ROUTER_DISCOVERY:
2439 case DHO_ROUTER_SOLICITATION_ADDRESS:
2440 case DHO_STATIC_ROUTES:
2441 case DHO_TRAILER_ENCAPSULATION:
2442 case DHO_ARP_CACHE_TIMEOUT:
2443 case DHO_IEEE802_3_ENCAPSULATION:
2444 case DHO_DEFAULT_TCP_TTL:
2445 case DHO_TCP_KEEPALIVE_INTERVAL:
2446 case DHO_TCP_KEEPALIVE_GARBAGE:
2447 case DHO_VENDOR_ENCAPSULATED_OPTIONS:
2448 case DHO_NETBIOS_NODE_TYPE:
2449 case DHO_NETBIOS_SCOPE:
2450 case DHO_X_DISPLAY_MANAGER:
2451 case DHO_DHCP_REQUESTED_ADDRESS:
2452 case DHO_DHCP_LEASE_TIME:
2453 case DHO_DHCP_OPTION_OVERLOAD:
2454 case DHO_DHCP_MESSAGE_TYPE:
2455 case DHO_DHCP_PARAMETER_REQUEST_LIST:
2456 case DHO_DHCP_MESSAGE:
2457 case DHO_DHCP_MAX_MESSAGE_SIZE:
2458 case DHO_DHCP_RENEWAL_TIME:
2459 case DHO_DHCP_REBINDING_TIME:
2460 case DHO_DHCP_CLASS_IDENTIFIER:
2461 case DHO_DHCP_CLIENT_IDENTIFIER:
2462 case DHO_BOOTFILE_NAME:
2463 case DHO_DHCP_USER_CLASS_ID:
2466 case DHO_CLASSLESS_ROUTES:
2467 return (check_classless_option(l->options[option].data,
2468 l->options[option].len));
2470 warning("unknown dhcp option value 0x%x", option);
2471 return (unknown_ok);
2475 /* RFC 3442 The Classless Static Routes option checks */
2477 check_classless_option(unsigned char *data, int len)
2480 unsigned char width;
2481 in_addr_t addr, mask;
2484 warning("Too small length: %d", len);
2492 } else if (width < 9) {
2493 addr = (in_addr_t)(data[i] << 24);
2495 } else if (width < 17) {
2496 addr = (in_addr_t)(data[i] << 24) +
2497 (in_addr_t)(data[i + 1] << 16);
2499 } else if (width < 25) {
2500 addr = (in_addr_t)(data[i] << 24) +
2501 (in_addr_t)(data[i + 1] << 16) +
2502 (in_addr_t)(data[i + 2] << 8);
2504 } else if (width < 33) {
2505 addr = (in_addr_t)(data[i] << 24) +
2506 (in_addr_t)(data[i + 1] << 16) +
2507 (in_addr_t)(data[i + 2] << 8) +
2511 warning("Incorrect subnet width: %d", width);
2514 mask = (in_addr_t)(~0) << (32 - width);
2520 * ... After deriving a subnet number and subnet mask
2521 * from each destination descriptor, the DHCP client
2522 * MUST zero any bits in the subnet number where the
2523 * corresponding bit in the mask is zero...
2525 if ((addr & mask) != addr) {
2527 data[i - 1] = (unsigned char)(
2528 (addr >> (((32 - width)/8)*8)) & 0xFF);
2533 warning("Incorrect data length: %d (must be %d)", len, i);
2540 res_hnok(const char *dn)
2542 int pch = PERIOD, ch = *dn++;
2544 while (ch != '\0') {
2547 if (periodchar(ch)) {
2549 } else if (periodchar(pch)) {
2550 if (!borderchar(ch))
2552 } else if (periodchar(nch) || nch == '\0') {
2553 if (!borderchar(ch))
2556 if (!middlechar(ch))
2565 check_search(const char *srch)
2567 int pch = PERIOD, ch = *srch++;
2570 /* 256 char limit re resolv.conf(5) */
2571 if (strlen(srch) > 256)
2574 while (whitechar(ch))
2577 while (ch != '\0') {
2580 if (periodchar(ch) || whitechar(ch)) {
2582 } else if (periodchar(pch)) {
2583 if (!borderchar(ch))
2585 } else if (periodchar(nch) || nch == '\0') {
2586 if (!borderchar(ch))
2589 if (!middlechar(ch))
2592 if (!whitechar(ch)) {
2595 while (whitechar(nch)) {
2604 /* 6 domain limit re resolv.conf(5) */
2610 /* Does buf consist only of dotted decimal ipv4 addrs?
2611 * return how many if so,
2612 * otherwise, return 0
2615 ipv4addrs(char * buf)
2620 while (inet_aton(buf, &jnk) == 1){
2622 while (periodchar(*buf) || digitchar(*buf))
2634 option_as_string(unsigned int code, unsigned char *data, int len)
2636 static char optbuf[32768]; /* XXX */
2638 int opleft = sizeof(optbuf);
2639 unsigned char *dp = data;
2642 error("option_as_string: bad code %d", code);
2644 for (; dp < data + len; dp++) {
2645 if (!isascii(*dp) || !isprint(*dp)) {
2646 if (dp + 1 != data + len || *dp != 0) {
2647 snprintf(op, opleft, "\\%03o", *dp);
2651 } else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
2652 *dp == '`' || *dp == '\\') {
2666 warning("dhcp option too large");
2671 fork_privchld(int fd, int fd2)
2673 struct pollfd pfd[1];
2678 error("cannot fork");
2685 setproctitle("%s [priv]", ifi->name);
2688 dup2(nullfd, STDIN_FILENO);
2689 dup2(nullfd, STDOUT_FILENO);
2690 dup2(nullfd, STDERR_FILENO);
2696 pfd[0].events = POLLIN;
2697 if ((nfds = poll(pfd, 1, INFTIM)) == -1)
2699 error("poll error");
2701 if (nfds == 0 || !(pfd[0].revents & POLLIN))