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;
99 * ASSERT_STATE() does nothing now; it used to be
100 * assert (state_is == state_shouldbe).
102 #define ASSERT_STATE(state_is, state_shouldbe) {}
104 #define TIME_MAX 2147483647
111 struct interface_info *ifi;
113 int findproto(char *, int);
114 struct sockaddr *get_ifa(char *, int);
115 void routehandler(struct protocol *);
117 int check_option(struct client_lease *l, int option);
118 int check_classless_option(unsigned char *data, int len);
119 int ipv4addrs(char * buf);
120 int res_hnok(const char *dn);
121 int check_search(const char *srch);
122 char *option_as_string(unsigned int code, unsigned char *data, int len);
123 int fork_privchld(int, int);
126 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
127 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
129 static time_t scripttime;
132 findproto(char *cp, int n)
139 for (i = 1; i; i <<= 1) {
141 sa = (struct sockaddr *)cp;
147 if (sa->sa_family == AF_INET)
149 if (sa->sa_family == AF_INET6)
162 get_ifa(char *cp, int n)
169 for (i = 1; i; i <<= 1)
171 sa = (struct sockaddr *)cp;
180 struct iaddr defaddr = { 4 };
186 struct interface_info *ifi = arg;
189 * Clear existing state.
191 if (ifi->client->active != NULL) {
192 script_init("EXPIRE", NULL);
193 script_write_params("old_",
194 ifi->client->active);
195 if (ifi->client->alias)
196 script_write_params("alias_",
200 ifi->client->state = S_INIT;
205 routehandler(struct protocol *p)
207 char msg[2048], *addr;
208 struct rt_msghdr *rtm;
209 struct if_msghdr *ifm;
210 struct ifa_msghdr *ifam;
211 struct if_announcemsghdr *ifan;
212 struct ieee80211_join_event *jev;
213 struct client_lease *l;
214 time_t t = time(NULL);
219 n = read(routefd, &msg, sizeof(msg));
220 rtm = (struct rt_msghdr *)msg;
221 if (n < sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen ||
222 rtm->rtm_version != RTM_VERSION)
225 switch (rtm->rtm_type) {
228 ifam = (struct ifa_msghdr *)rtm;
230 if (ifam->ifam_index != ifi->index)
232 if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
234 if (scripttime == 0 || t < scripttime + 10)
237 sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs);
241 if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf))
242 error("king bula sez: len mismatch");
243 memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len);
244 if (addr_eq(a, defaddr))
247 for (l = ifi->client->active; l != NULL; l = l->next)
248 if (addr_eq(a, l->address))
251 if (l == NULL) /* added/deleted addr is not the one we set */
254 addr = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
255 if (rtm->rtm_type == RTM_NEWADDR) {
257 * XXX: If someone other than us adds our address,
258 * should we assume they are taking over from us,
259 * delete the lease record, and exit without modifying
262 warning("My address (%s) was re-added", addr);
264 warning("My address (%s) was deleted, dhclient exiting",
270 ifm = (struct if_msghdr *)rtm;
271 if (ifm->ifm_index != ifi->index)
273 if ((rtm->rtm_flags & RTF_UP) == 0) {
274 warning("Interface %s is down, dhclient exiting",
280 ifan = (struct if_announcemsghdr *)rtm;
281 if (ifan->ifan_what == IFAN_DEPARTURE &&
282 ifan->ifan_index == ifi->index) {
283 warning("Interface %s is gone, dhclient exiting",
289 ifan = (struct if_announcemsghdr *)rtm;
290 if (ifan->ifan_index != ifi->index)
292 switch (ifan->ifan_what) {
293 case RTM_IEEE80211_ASSOC:
294 case RTM_IEEE80211_REASSOC:
296 * Use assoc/reassoc event to kick state machine
297 * in case we roam. Otherwise fall back to the
298 * normal state machine just like a wired network.
300 jev = (struct ieee80211_join_event *) &ifan[1];
301 if (memcmp(curbssid, jev->iev_addr, 6)) {
305 memcpy(curbssid, jev->iev_addr, 6);
315 script_init("FAIL", NULL);
316 if (ifi->client->alias)
317 script_write_params("alias_", ifi->client->alias);
323 main(int argc, char *argv[])
325 extern char *__progname;
326 int ch, fd, quiet = 0, i = 0;
328 int immediate_daemon = 0;
331 /* Initially, log errors to stderr as well as to syslogd. */
332 openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
333 setlogmask(LOG_UPTO(LOG_DEBUG));
335 while ((ch = getopt(argc, argv, "bc:dl:qu")) != -1)
338 immediate_daemon = 1;
341 path_dhclient_conf = optarg;
347 path_dhclient_db = optarg;
365 if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL)
367 if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
368 error("Interface name too long");
369 if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s",
370 _PATH_DHCLIENT_DB, ifi->name) == -1)
379 memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
380 sockaddr_broadcast.sin_family = AF_INET;
381 sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
382 sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
383 sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast);
384 inaddr_any.s_addr = INADDR_ANY;
388 if (!interface_link_status(ifi->name)) {
389 fprintf(stderr, "%s: no link ...", ifi->name);
392 while (!interface_link_status(ifi->name)) {
393 fprintf(stderr, ".");
396 fprintf(stderr, " giving up\n");
401 fprintf(stderr, " got link\n");
404 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
405 error("cannot open %s: %m", _PATH_DEVNULL);
407 if ((pw = getpwnam("_dhcp")) == NULL) {
408 warning("no such user: _dhcp, falling back to \"nobody\"");
409 if ((pw = getpwnam("nobody")) == NULL)
410 error("no such user: nobody");
413 if (pipe(pipe_fd) == -1)
416 fork_privchld(pipe_fd[0], pipe_fd[1]);
421 if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
422 error("can't open and lock %s: %m", path_dhclient_db);
423 read_client_leases();
424 rewrite_client_leases();
427 priv_script_init("PREINIT", NULL);
428 if (ifi->client->alias)
429 priv_script_write_params("alias_", ifi->client->alias);
432 if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
433 add_protocol("AF_ROUTE", routefd, routehandler, ifi);
435 /* set up the interface */
436 discover_interfaces(ifi);
438 if (chroot(_PATH_VAREMPTY) == -1)
440 if (chdir("/") == -1)
441 error("chdir(\"/\")");
443 if (setgroups(1, &pw->pw_gid) ||
444 setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
445 seteuid(pw->pw_uid) || setuid(pw->pw_uid))
446 error("can't drop privileges: %m");
450 setproctitle("%s", ifi->name);
452 if (immediate_daemon)
455 ifi->client->state = S_INIT;
458 bootp_packet_handler = do_packet;
469 extern char *__progname;
471 fprintf(stderr, "usage: %s [-bdqu] ", __progname);
472 fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
479 * Each routine is called from the dhclient_state_machine() in one of
481 * -> entering INIT state
482 * -> recvpacket_flag == 0: timeout in this state
483 * -> otherwise: received a packet in this state
485 * Return conditions as handled by dhclient_state_machine():
486 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
487 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
488 * Returns 0: finish the nap which was interrupted for no good reason.
490 * Several per-interface variables are used to keep track of the process:
491 * active_lease: the lease that is being used on the interface
492 * (null pointer if not configured yet).
493 * offered_leases: leases corresponding to DHCPOFFER messages that have
494 * been sent to us by DHCP servers.
495 * acked_leases: leases corresponding to DHCPACK messages that have been
496 * sent to us by DHCP servers.
497 * sendpacket: DHCP packet we're trying to send.
498 * destination: IP address to send sendpacket to
499 * In addition, there are several relevant per-lease variables.
500 * T1_expiry, T2_expiry, lease_expiry: lease milestones
501 * In the active lease, these control the process of renewing the lease;
502 * In leases on the acked_leases list, this simply determines when we
503 * can no longer legitimately use the lease.
507 state_reboot(void *ipp)
509 struct interface_info *ip = ipp;
511 /* If we don't remember an active lease, go straight to INIT. */
512 if (!ip->client->active || ip->client->active->is_bootp) {
517 /* We are in the rebooting state. */
518 ip->client->state = S_REBOOTING;
520 /* make_request doesn't initialize xid because it normally comes
521 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
522 so pick an xid now. */
523 ip->client->xid = arc4random();
525 /* Make a DHCPREQUEST packet, and set appropriate per-interface
527 make_request(ip, ip->client->active);
528 ip->client->destination = iaddr_broadcast;
529 ip->client->first_sending = cur_time;
530 ip->client->interval = ip->client->config->initial_interval;
532 /* Zap the medium list... */
533 ip->client->medium = NULL;
535 /* Send out the first DHCPREQUEST packet. */
540 * Called when a lease has completely expired and we've
541 * been unable to renew it.
544 state_init(void *ipp)
546 struct interface_info *ip = ipp;
548 ASSERT_STATE(state, S_INIT);
550 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
552 make_discover(ip, ip->client->active);
553 ip->client->xid = ip->client->packet.xid;
554 ip->client->destination = iaddr_broadcast;
555 ip->client->state = S_SELECTING;
556 ip->client->first_sending = cur_time;
557 ip->client->interval = ip->client->config->initial_interval;
559 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
565 * state_selecting is called when one or more DHCPOFFER packets
566 * have been received and a configurable period of time has passed.
569 state_selecting(void *ipp)
571 struct interface_info *ip = ipp;
572 struct client_lease *lp, *next, *picked;
574 ASSERT_STATE(state, S_SELECTING);
576 /* Cancel state_selecting and send_discover timeouts, since either
577 one could have got us here. */
578 cancel_timeout(state_selecting, ip);
579 cancel_timeout(send_discover, ip);
581 /* We have received one or more DHCPOFFER packets. Currently,
582 the only criterion by which we judge leases is whether or
583 not we get a response when we arp for them. */
585 for (lp = ip->client->offered_leases; lp; lp = next) {
588 /* Check to see if we got an ARPREPLY for the address
589 in this particular lease. */
591 script_init("ARPCHECK", lp->medium);
592 script_write_params("check_", lp);
594 /* If the ARPCHECK code detects another
595 machine using the offered address, it exits
596 nonzero. We need to send a DHCPDECLINE and
599 make_decline(ip, lp);
607 free_client_lease(lp);
610 ip->client->offered_leases = NULL;
612 /* If we just tossed all the leases we were offered, go back
615 ip->client->state = S_INIT;
620 /* If it was a BOOTREPLY, we can just take the address right now. */
621 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
622 ip->client->new = picked;
624 /* Make up some lease expiry times
625 XXX these should be configurable. */
626 ip->client->new->expiry = cur_time + 12000;
627 ip->client->new->renewal += cur_time + 8000;
628 ip->client->new->rebind += cur_time + 10000;
630 ip->client->state = S_REQUESTING;
632 /* Bind to the address we received. */
637 /* Go to the REQUESTING state. */
638 ip->client->destination = iaddr_broadcast;
639 ip->client->state = S_REQUESTING;
640 ip->client->first_sending = cur_time;
641 ip->client->interval = ip->client->config->initial_interval;
643 /* Make a DHCPREQUEST packet from the lease we picked. */
644 make_request(ip, picked);
645 ip->client->xid = ip->client->packet.xid;
647 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
648 free_client_lease(picked);
650 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
654 /* state_requesting is called when we receive a DHCPACK message after
655 having sent out one or more DHCPREQUEST packets. */
658 dhcpack(struct packet *packet)
660 struct interface_info *ip = packet->interface;
661 struct client_lease *lease;
663 /* If we're not receptive to an offer right now, or if the offer
664 has an unrecognizable transaction id, then just drop it. */
665 if (packet->interface->client->xid != packet->raw->xid ||
666 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
667 (memcmp(packet->interface->hw_address.haddr,
668 packet->raw->chaddr, packet->raw->hlen)))
671 if (ip->client->state != S_REBOOTING &&
672 ip->client->state != S_REQUESTING &&
673 ip->client->state != S_RENEWING &&
674 ip->client->state != S_REBINDING)
677 note("DHCPACK from %s", piaddr(packet->client_addr));
679 lease = packet_to_lease(packet);
681 note("packet_to_lease failed.");
685 ip->client->new = lease;
687 /* Stop resending DHCPREQUEST. */
688 cancel_timeout(send_request, ip);
690 /* Figure out the lease time. */
691 if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
692 ip->client->new->expiry = getULong(
693 ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
695 ip->client->new->expiry = default_lease_time;
696 /* A number that looks negative here is really just very large,
697 because the lease expiry offset is unsigned. */
698 if (ip->client->new->expiry < 0)
699 ip->client->new->expiry = TIME_MAX;
700 /* XXX should be fixed by resetting the client state */
701 if (ip->client->new->expiry < 60)
702 ip->client->new->expiry = 60;
704 /* Take the server-provided renewal time if there is one;
705 otherwise figure it out according to the spec. */
706 if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
707 ip->client->new->renewal = getULong(
708 ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
710 ip->client->new->renewal = ip->client->new->expiry / 2;
712 /* Same deal with the rebind time. */
713 if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
714 ip->client->new->rebind = getULong(
715 ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
717 ip->client->new->rebind = ip->client->new->renewal +
718 ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
720 ip->client->new->expiry += cur_time;
721 /* Lease lengths can never be negative. */
722 if (ip->client->new->expiry < cur_time)
723 ip->client->new->expiry = TIME_MAX;
724 ip->client->new->renewal += cur_time;
725 if (ip->client->new->renewal < cur_time)
726 ip->client->new->renewal = TIME_MAX;
727 ip->client->new->rebind += cur_time;
728 if (ip->client->new->rebind < cur_time)
729 ip->client->new->rebind = TIME_MAX;
735 bind_lease(struct interface_info *ip)
737 /* Remember the medium. */
738 ip->client->new->medium = ip->client->medium;
740 /* Write out the new lease. */
741 write_client_lease(ip, ip->client->new, 0);
743 /* Run the client script with the new parameters. */
744 script_init((ip->client->state == S_REQUESTING ? "BOUND" :
745 (ip->client->state == S_RENEWING ? "RENEW" :
746 (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))),
747 ip->client->new->medium);
748 if (ip->client->active && ip->client->state != S_REBOOTING)
749 script_write_params("old_", ip->client->active);
750 script_write_params("new_", ip->client->new);
751 if (ip->client->alias)
752 script_write_params("alias_", ip->client->alias);
755 /* Replace the old active lease with the new one. */
756 if (ip->client->active)
757 free_client_lease(ip->client->active);
758 ip->client->active = ip->client->new;
759 ip->client->new = NULL;
761 /* Set up a timeout to start the renewal process. */
762 add_timeout(ip->client->active->renewal, state_bound, ip);
764 note("bound to %s -- renewal in %d seconds.",
765 piaddr(ip->client->active->address),
766 (int)(ip->client->active->renewal - cur_time));
767 ip->client->state = S_BOUND;
768 reinitialize_interfaces();
773 * state_bound is called when we've successfully bound to a particular
774 * lease, but the renewal time on that lease has expired. We are
775 * expected to unicast a DHCPREQUEST to the server that gave us our
779 state_bound(void *ipp)
781 struct interface_info *ip = ipp;
783 ASSERT_STATE(state, S_BOUND);
785 /* T1 has expired. */
786 make_request(ip, ip->client->active);
787 ip->client->xid = ip->client->packet.xid;
789 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
790 memcpy(ip->client->destination.iabuf, ip->client->active->
791 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
792 ip->client->destination.len = 4;
794 ip->client->destination = iaddr_broadcast;
796 ip->client->first_sending = cur_time;
797 ip->client->interval = ip->client->config->initial_interval;
798 ip->client->state = S_RENEWING;
800 /* Send the first packet immediately. */
805 bootp(struct packet *packet)
807 struct iaddrlist *ap;
809 if (packet->raw->op != BOOTREPLY)
812 /* If there's a reject list, make sure this packet's sender isn't
814 for (ap = packet->interface->client->config->reject_list;
816 if (addr_eq(packet->client_addr, ap->addr)) {
817 note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
825 dhcp(struct packet *packet)
827 struct iaddrlist *ap;
828 void (*handler)(struct packet *);
831 switch (packet->packet_type) {
848 /* If there's a reject list, make sure this packet's sender isn't
850 for (ap = packet->interface->client->config->reject_list;
852 if (addr_eq(packet->client_addr, ap->addr)) {
853 note("%s from %s rejected.", type, piaddr(ap->addr));
861 dhcpoffer(struct packet *packet)
863 struct interface_info *ip = packet->interface;
864 struct client_lease *lease, *lp;
866 int arp_timeout_needed, stop_selecting;
867 char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
868 "DHCPOFFER" : "BOOTREPLY";
870 /* If we're not receptive to an offer right now, or if the offer
871 has an unrecognizable transaction id, then just drop it. */
872 if (ip->client->state != S_SELECTING ||
873 packet->interface->client->xid != packet->raw->xid ||
874 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
875 (memcmp(packet->interface->hw_address.haddr,
876 packet->raw->chaddr, packet->raw->hlen)))
879 note("%s from %s", name, piaddr(packet->client_addr));
882 /* If this lease doesn't supply the minimum required parameters,
884 for (i = 0; ip->client->config->required_options[i]; i++) {
885 if (!packet->options[ip->client->config->
886 required_options[i]].len) {
887 note("%s isn't satisfactory.", name);
892 /* If we've already seen this lease, don't record it again. */
893 for (lease = ip->client->offered_leases;
894 lease; lease = lease->next) {
895 if (lease->address.len == sizeof(packet->raw->yiaddr) &&
896 !memcmp(lease->address.iabuf,
897 &packet->raw->yiaddr, lease->address.len)) {
898 debug("%s already seen.", name);
903 lease = packet_to_lease(packet);
905 note("packet_to_lease failed.");
909 /* If this lease was acquired through a BOOTREPLY, record that
911 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
914 /* Record the medium under which this lease was offered. */
915 lease->medium = ip->client->medium;
917 /* Send out an ARP Request for the offered IP address. */
918 script_init("ARPSEND", lease->medium);
919 script_write_params("check_", lease);
920 /* If the script can't send an ARP request without waiting,
921 we'll be waiting when we do the ARPCHECK, so don't wait now. */
923 arp_timeout_needed = 0;
925 arp_timeout_needed = 2;
927 /* Figure out when we're supposed to stop selecting. */
929 ip->client->first_sending + ip->client->config->select_interval;
931 /* If this is the lease we asked for, put it at the head of the
932 list, and don't mess with the arp request timeout. */
933 if (lease->address.len == ip->client->requested_address.len &&
934 !memcmp(lease->address.iabuf,
935 ip->client->requested_address.iabuf,
936 ip->client->requested_address.len)) {
937 lease->next = ip->client->offered_leases;
938 ip->client->offered_leases = lease;
940 /* If we already have an offer, and arping for this
941 offer would take us past the selection timeout,
942 then don't extend the timeout - just hope for the
944 if (ip->client->offered_leases &&
945 (cur_time + arp_timeout_needed) > stop_selecting)
946 arp_timeout_needed = 0;
948 /* Put the lease at the end of the list. */
950 if (!ip->client->offered_leases)
951 ip->client->offered_leases = lease;
953 for (lp = ip->client->offered_leases; lp->next;
960 /* If we're supposed to stop selecting before we've had time
961 to wait for the ARPREPLY, add some delay to wait for
963 if (stop_selecting - cur_time < arp_timeout_needed)
964 stop_selecting = cur_time + arp_timeout_needed;
966 /* If the selecting interval has expired, go immediately to
967 state_selecting(). Otherwise, time out into
968 state_selecting at the select interval. */
969 if (stop_selecting <= 0)
972 add_timeout(stop_selecting, state_selecting, ip);
973 cancel_timeout(send_discover, ip);
977 /* Allocate a client_lease structure and initialize it from the parameters
978 in the specified packet. */
980 struct client_lease *
981 packet_to_lease(struct packet *packet)
983 struct client_lease *lease;
986 lease = malloc(sizeof(struct client_lease));
989 warning("dhcpoffer: no memory to record lease.");
993 memset(lease, 0, sizeof(*lease));
995 /* Copy the lease options. */
996 for (i = 0; i < 256; i++) {
997 if (packet->options[i].len) {
998 lease->options[i].data =
999 malloc(packet->options[i].len + 1);
1000 if (!lease->options[i].data) {
1001 warning("dhcpoffer: no memory for option %d", i);
1002 free_client_lease(lease);
1005 memcpy(lease->options[i].data,
1006 packet->options[i].data,
1007 packet->options[i].len);
1008 lease->options[i].len =
1009 packet->options[i].len;
1010 lease->options[i].data[lease->options[i].len] =
1013 if (!check_option(lease,i)) {
1014 /* ignore a bogus lease offer */
1015 warning("Invalid lease option - ignoring offer");
1016 free_client_lease(lease);
1022 lease->address.len = sizeof(packet->raw->yiaddr);
1023 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
1025 /* If the server name was filled out, copy it.
1026 Do not attempt to validate the server name as a host name.
1027 RFC 2131 merely states that sname is NUL-terminated (which do
1028 do not assume) and that it is the server's host name. Since
1029 the ISC client and server allow arbitrary characters, we do
1031 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1032 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
1033 packet->raw->sname[0]) {
1034 lease->server_name = malloc(DHCP_SNAME_LEN + 1);
1035 if (!lease->server_name) {
1036 warning("dhcpoffer: no memory for server name.");
1037 free_client_lease(lease);
1040 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
1041 lease->server_name[DHCP_SNAME_LEN]='\0';
1044 /* Ditto for the filename. */
1045 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1046 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
1047 packet->raw->file[0]) {
1048 /* Don't count on the NUL terminator. */
1049 lease->filename = malloc(DHCP_FILE_LEN + 1);
1050 if (!lease->filename) {
1051 warning("dhcpoffer: no memory for filename.");
1052 free_client_lease(lease);
1055 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
1056 lease->filename[DHCP_FILE_LEN]='\0';
1062 dhcpnak(struct packet *packet)
1064 struct interface_info *ip = packet->interface;
1066 /* If we're not receptive to an offer right now, or if the offer
1067 has an unrecognizable transaction id, then just drop it. */
1068 if (packet->interface->client->xid != packet->raw->xid ||
1069 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
1070 (memcmp(packet->interface->hw_address.haddr,
1071 packet->raw->chaddr, packet->raw->hlen)))
1074 if (ip->client->state != S_REBOOTING &&
1075 ip->client->state != S_REQUESTING &&
1076 ip->client->state != S_RENEWING &&
1077 ip->client->state != S_REBINDING)
1080 note("DHCPNAK from %s", piaddr(packet->client_addr));
1082 if (!ip->client->active) {
1083 note("DHCPNAK with no active lease.\n");
1087 free_client_lease(ip->client->active);
1088 ip->client->active = NULL;
1090 /* Stop sending DHCPREQUEST packets... */
1091 cancel_timeout(send_request, ip);
1093 ip->client->state = S_INIT;
1097 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1098 one after the right interval has expired. If we don't get an offer by
1099 the time we reach the panic interval, call the panic function. */
1102 send_discover(void *ipp)
1104 struct interface_info *ip = ipp;
1105 int interval, increase = 1;
1107 /* Figure out how long it's been since we started transmitting. */
1108 interval = cur_time - ip->client->first_sending;
1110 /* If we're past the panic timeout, call the script and tell it
1111 we haven't found anything for this interface yet. */
1112 if (interval > ip->client->config->timeout) {
1117 /* If we're selecting media, try the whole list before doing
1118 the exponential backoff, but if we've already received an
1119 offer, stop looping, because we obviously have it right. */
1120 if (!ip->client->offered_leases &&
1121 ip->client->config->media) {
1124 if (ip->client->medium) {
1125 ip->client->medium = ip->client->medium->next;
1128 if (!ip->client->medium) {
1130 error("No valid media types for %s!", ip->name);
1131 ip->client->medium = ip->client->config->media;
1135 note("Trying medium \"%s\" %d", ip->client->medium->string,
1137 script_init("MEDIUM", ip->client->medium);
1143 * If we're supposed to increase the interval, do so. If it's
1144 * currently zero (i.e., we haven't sent any packets yet), set
1145 * it to one; otherwise, add to it a random number between zero
1146 * and two times itself. On average, this means that it will
1147 * double with every transmission.
1150 if (!ip->client->interval)
1151 ip->client->interval =
1152 ip->client->config->initial_interval;
1154 ip->client->interval += (arc4random() >> 2) %
1155 (2 * ip->client->interval);
1158 /* Don't backoff past cutoff. */
1159 if (ip->client->interval >
1160 ip->client->config->backoff_cutoff)
1161 ip->client->interval =
1162 ((ip->client->config->backoff_cutoff / 2)
1163 + ((arc4random() >> 2) %
1164 ip->client->config->backoff_cutoff));
1165 } else if (!ip->client->interval)
1166 ip->client->interval =
1167 ip->client->config->initial_interval;
1169 /* If the backoff would take us to the panic timeout, just use that
1171 if (cur_time + ip->client->interval >
1172 ip->client->first_sending + ip->client->config->timeout)
1173 ip->client->interval =
1174 (ip->client->first_sending +
1175 ip->client->config->timeout) - cur_time + 1;
1177 /* Record the number of seconds since we started sending. */
1178 if (interval < 65536)
1179 ip->client->packet.secs = htons(interval);
1181 ip->client->packet.secs = htons(65535);
1182 ip->client->secs = ip->client->packet.secs;
1184 note("DHCPDISCOVER on %s to %s port %d interval %d",
1185 ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
1186 ntohs(sockaddr_broadcast.sin_port),
1187 (int)ip->client->interval);
1189 /* Send out a packet. */
1190 (void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
1191 inaddr_any, &sockaddr_broadcast, NULL);
1193 add_timeout(cur_time + ip->client->interval, send_discover, ip);
1197 * state_panic gets called if we haven't received any offers in a preset
1198 * amount of time. When this happens, we try to use existing leases
1199 * that haven't yet expired, and failing that, we call the client script
1200 * and hope it can do something.
1203 state_panic(void *ipp)
1205 struct interface_info *ip = ipp;
1206 struct client_lease *loop = ip->client->active;
1207 struct client_lease *lp;
1209 note("No DHCPOFFERS received.");
1211 /* We may not have an active lease, but we may have some
1212 predefined leases that we can try. */
1213 if (!ip->client->active && ip->client->leases)
1216 /* Run through the list of leases and see if one can be used. */
1217 while (ip->client->active) {
1218 if (ip->client->active->expiry > cur_time) {
1219 note("Trying recorded lease %s",
1220 piaddr(ip->client->active->address));
1221 /* Run the client script with the existing
1223 script_init("TIMEOUT",
1224 ip->client->active->medium);
1225 script_write_params("new_", ip->client->active);
1226 if (ip->client->alias)
1227 script_write_params("alias_",
1230 /* If the old lease is still good and doesn't
1231 yet need renewal, go into BOUND state and
1232 timeout at the renewal time. */
1235 ip->client->active->renewal) {
1236 ip->client->state = S_BOUND;
1237 note("bound: renewal in %d seconds.",
1238 (int)(ip->client->active->renewal -
1241 ip->client->active->renewal,
1244 ip->client->state = S_BOUND;
1245 note("bound: immediate renewal.");
1248 reinitialize_interfaces();
1254 /* If there are no other leases, give up. */
1255 if (!ip->client->leases) {
1256 ip->client->leases = ip->client->active;
1257 ip->client->active = NULL;
1262 /* Otherwise, put the active lease at the end of the
1263 lease list, and try another lease.. */
1264 for (lp = ip->client->leases; lp->next; lp = lp->next)
1266 lp->next = ip->client->active;
1268 lp->next->next = NULL;
1269 ip->client->active = ip->client->leases;
1270 ip->client->leases = ip->client->leases->next;
1272 /* If we already tried this lease, we've exhausted the
1273 set of leases, so we might as well give up for
1275 if (ip->client->active == loop)
1278 loop = ip->client->active;
1281 /* No leases were available, or what was available didn't work, so
1282 tell the shell script that we failed to allocate an address,
1283 and try again later. */
1284 note("No working leases in persistent database - sleeping.\n");
1285 script_init("FAIL", NULL);
1286 if (ip->client->alias)
1287 script_write_params("alias_", ip->client->alias);
1289 ip->client->state = S_INIT;
1290 add_timeout(cur_time + ip->client->config->retry_interval, state_init,
1296 send_request(void *ipp)
1298 struct interface_info *ip = ipp;
1299 struct sockaddr_in destination;
1300 struct in_addr from;
1303 /* Figure out how long it's been since we started transmitting. */
1304 interval = cur_time - ip->client->first_sending;
1306 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1307 past the reboot timeout, go to INIT and see if we can
1308 DISCOVER an address... */
1309 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1310 means either that we're on a network with no DHCP server,
1311 or that our server is down. In the latter case, assuming
1312 that there is a backup DHCP server, DHCPDISCOVER will get
1313 us a new address, but we could also have successfully
1314 reused our old address. In the former case, we're hosed
1315 anyway. This is not a win-prone situation. */
1316 if ((ip->client->state == S_REBOOTING ||
1317 ip->client->state == S_REQUESTING) &&
1318 interval > ip->client->config->reboot_timeout) {
1320 ip->client->state = S_INIT;
1321 cancel_timeout(send_request, ip);
1326 /* If we're in the reboot state, make sure the media is set up
1328 if (ip->client->state == S_REBOOTING &&
1329 !ip->client->medium &&
1330 ip->client->active->medium ) {
1331 script_init("MEDIUM", ip->client->active->medium);
1333 /* If the medium we chose won't fly, go to INIT state. */
1337 /* Record the medium. */
1338 ip->client->medium = ip->client->active->medium;
1341 /* If the lease has expired, relinquish the address and go back
1342 to the INIT state. */
1343 if (ip->client->state != S_REQUESTING &&
1344 cur_time > ip->client->active->expiry) {
1345 /* Run the client script with the new parameters. */
1346 script_init("EXPIRE", NULL);
1347 script_write_params("old_", ip->client->active);
1348 if (ip->client->alias)
1349 script_write_params("alias_", ip->client->alias);
1352 /* Now do a preinit on the interface so that we can
1353 discover a new address. */
1354 script_init("PREINIT", NULL);
1355 if (ip->client->alias)
1356 script_write_params("alias_", ip->client->alias);
1359 ip->client->state = S_INIT;
1364 /* Do the exponential backoff... */
1365 if (!ip->client->interval)
1366 ip->client->interval = ip->client->config->initial_interval;
1368 ip->client->interval += ((arc4random() >> 2) %
1369 (2 * ip->client->interval));
1371 /* Don't backoff past cutoff. */
1372 if (ip->client->interval >
1373 ip->client->config->backoff_cutoff)
1374 ip->client->interval =
1375 ((ip->client->config->backoff_cutoff / 2) +
1376 ((arc4random() >> 2) % ip->client->interval));
1378 /* If the backoff would take us to the expiry time, just set the
1379 timeout to the expiry time. */
1380 if (ip->client->state != S_REQUESTING &&
1381 cur_time + ip->client->interval >
1382 ip->client->active->expiry)
1383 ip->client->interval =
1384 ip->client->active->expiry - cur_time + 1;
1386 /* If the lease T2 time has elapsed, or if we're not yet bound,
1387 broadcast the DHCPREQUEST rather than unicasting. */
1388 memset(&destination, 0, sizeof(destination));
1389 if (ip->client->state == S_REQUESTING ||
1390 ip->client->state == S_REBOOTING ||
1391 cur_time > ip->client->active->rebind)
1392 destination.sin_addr.s_addr = INADDR_BROADCAST;
1394 memcpy(&destination.sin_addr.s_addr,
1395 ip->client->destination.iabuf,
1396 sizeof(destination.sin_addr.s_addr));
1397 destination.sin_port = htons(REMOTE_PORT);
1398 destination.sin_family = AF_INET;
1399 destination.sin_len = sizeof(destination);
1401 if (ip->client->state != S_REQUESTING)
1402 memcpy(&from, ip->client->active->address.iabuf,
1405 from.s_addr = INADDR_ANY;
1407 /* Record the number of seconds since we started sending. */
1408 if (ip->client->state == S_REQUESTING)
1409 ip->client->packet.secs = ip->client->secs;
1411 if (interval < 65536)
1412 ip->client->packet.secs = htons(interval);
1414 ip->client->packet.secs = htons(65535);
1417 note("DHCPREQUEST on %s to %s port %d", ip->name,
1418 inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
1420 /* Send out a packet. */
1421 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1422 from, &destination, NULL);
1424 add_timeout(cur_time + ip->client->interval, send_request, ip);
1428 send_decline(void *ipp)
1430 struct interface_info *ip = ipp;
1432 note("DHCPDECLINE on %s to %s port %d", ip->name,
1433 inet_ntoa(sockaddr_broadcast.sin_addr),
1434 ntohs(sockaddr_broadcast.sin_port));
1436 /* Send out a packet. */
1437 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1438 inaddr_any, &sockaddr_broadcast, NULL);
1442 make_discover(struct interface_info *ip, struct client_lease *lease)
1444 unsigned char discover = DHCPDISCOVER;
1445 struct tree_cache *options[256];
1446 struct tree_cache option_elements[256];
1449 memset(option_elements, 0, sizeof(option_elements));
1450 memset(options, 0, sizeof(options));
1451 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1453 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1454 i = DHO_DHCP_MESSAGE_TYPE;
1455 options[i] = &option_elements[i];
1456 options[i]->value = &discover;
1457 options[i]->len = sizeof(discover);
1458 options[i]->buf_size = sizeof(discover);
1459 options[i]->timeout = 0xFFFFFFFF;
1461 /* Request the options we want */
1462 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1463 options[i] = &option_elements[i];
1464 options[i]->value = ip->client->config->requested_options;
1465 options[i]->len = ip->client->config->requested_option_count;
1466 options[i]->buf_size =
1467 ip->client->config->requested_option_count;
1468 options[i]->timeout = 0xFFFFFFFF;
1470 /* If we had an address, try to get it again. */
1472 ip->client->requested_address = lease->address;
1473 i = DHO_DHCP_REQUESTED_ADDRESS;
1474 options[i] = &option_elements[i];
1475 options[i]->value = lease->address.iabuf;
1476 options[i]->len = lease->address.len;
1477 options[i]->buf_size = lease->address.len;
1478 options[i]->timeout = 0xFFFFFFFF;
1480 ip->client->requested_address.len = 0;
1482 /* Send any options requested in the config file. */
1483 for (i = 0; i < 256; i++)
1485 ip->client->config->send_options[i].data) {
1486 options[i] = &option_elements[i];
1488 ip->client->config->send_options[i].data;
1490 ip->client->config->send_options[i].len;
1491 options[i]->buf_size =
1492 ip->client->config->send_options[i].len;
1493 options[i]->timeout = 0xFFFFFFFF;
1496 /* send host name if not set via config file. */
1497 char hostname[_POSIX_HOST_NAME_MAX+1];
1498 if (!options[DHO_HOST_NAME]) {
1499 if (gethostname(hostname, sizeof(hostname)) == 0) {
1501 char* posDot = strchr(hostname, '.');
1503 len = posDot - hostname;
1505 len = strlen(hostname);
1506 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1507 options[DHO_HOST_NAME]->value = hostname;
1508 options[DHO_HOST_NAME]->len = len;
1509 options[DHO_HOST_NAME]->buf_size = len;
1510 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1514 /* set unique client identifier */
1515 char client_ident[sizeof(struct hardware)];
1516 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1517 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1518 ip->hw_address.hlen : sizeof(client_ident)-1;
1519 client_ident[0] = ip->hw_address.htype;
1520 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1521 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1522 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1523 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1524 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1525 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1528 /* Set up the option buffer... */
1529 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1530 options, 0, 0, 0, NULL, 0);
1531 if (ip->client->packet_length < BOOTP_MIN_LEN)
1532 ip->client->packet_length = BOOTP_MIN_LEN;
1534 ip->client->packet.op = BOOTREQUEST;
1535 ip->client->packet.htype = ip->hw_address.htype;
1536 ip->client->packet.hlen = ip->hw_address.hlen;
1537 ip->client->packet.hops = 0;
1538 ip->client->packet.xid = arc4random();
1539 ip->client->packet.secs = 0; /* filled in by send_discover. */
1540 ip->client->packet.flags = 0;
1542 memset(&(ip->client->packet.ciaddr),
1543 0, sizeof(ip->client->packet.ciaddr));
1544 memset(&(ip->client->packet.yiaddr),
1545 0, sizeof(ip->client->packet.yiaddr));
1546 memset(&(ip->client->packet.siaddr),
1547 0, sizeof(ip->client->packet.siaddr));
1548 memset(&(ip->client->packet.giaddr),
1549 0, sizeof(ip->client->packet.giaddr));
1550 memcpy(ip->client->packet.chaddr,
1551 ip->hw_address.haddr, ip->hw_address.hlen);
1556 make_request(struct interface_info *ip, struct client_lease * lease)
1558 unsigned char request = DHCPREQUEST;
1559 struct tree_cache *options[256];
1560 struct tree_cache option_elements[256];
1563 memset(options, 0, sizeof(options));
1564 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1566 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1567 i = DHO_DHCP_MESSAGE_TYPE;
1568 options[i] = &option_elements[i];
1569 options[i]->value = &request;
1570 options[i]->len = sizeof(request);
1571 options[i]->buf_size = sizeof(request);
1572 options[i]->timeout = 0xFFFFFFFF;
1574 /* Request the options we want */
1575 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1576 options[i] = &option_elements[i];
1577 options[i]->value = ip->client->config->requested_options;
1578 options[i]->len = ip->client->config->requested_option_count;
1579 options[i]->buf_size =
1580 ip->client->config->requested_option_count;
1581 options[i]->timeout = 0xFFFFFFFF;
1583 /* If we are requesting an address that hasn't yet been assigned
1584 to us, use the DHCP Requested Address option. */
1585 if (ip->client->state == S_REQUESTING) {
1586 /* Send back the server identifier... */
1587 i = DHO_DHCP_SERVER_IDENTIFIER;
1588 options[i] = &option_elements[i];
1589 options[i]->value = lease->options[i].data;
1590 options[i]->len = lease->options[i].len;
1591 options[i]->buf_size = lease->options[i].len;
1592 options[i]->timeout = 0xFFFFFFFF;
1594 if (ip->client->state == S_REQUESTING ||
1595 ip->client->state == S_REBOOTING) {
1596 ip->client->requested_address = lease->address;
1597 i = DHO_DHCP_REQUESTED_ADDRESS;
1598 options[i] = &option_elements[i];
1599 options[i]->value = lease->address.iabuf;
1600 options[i]->len = lease->address.len;
1601 options[i]->buf_size = lease->address.len;
1602 options[i]->timeout = 0xFFFFFFFF;
1604 ip->client->requested_address.len = 0;
1606 /* Send any options requested in the config file. */
1607 for (i = 0; i < 256; i++)
1609 ip->client->config->send_options[i].data) {
1610 options[i] = &option_elements[i];
1612 ip->client->config->send_options[i].data;
1614 ip->client->config->send_options[i].len;
1615 options[i]->buf_size =
1616 ip->client->config->send_options[i].len;
1617 options[i]->timeout = 0xFFFFFFFF;
1620 /* send host name if not set via config file. */
1621 char hostname[_POSIX_HOST_NAME_MAX+1];
1622 if (!options[DHO_HOST_NAME]) {
1623 if (gethostname(hostname, sizeof(hostname)) == 0) {
1625 char* posDot = strchr(hostname, '.');
1627 len = posDot - hostname;
1629 len = strlen(hostname);
1630 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1631 options[DHO_HOST_NAME]->value = hostname;
1632 options[DHO_HOST_NAME]->len = len;
1633 options[DHO_HOST_NAME]->buf_size = len;
1634 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1638 /* set unique client identifier */
1639 char client_ident[sizeof(struct hardware)];
1640 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1641 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1642 ip->hw_address.hlen : sizeof(client_ident)-1;
1643 client_ident[0] = ip->hw_address.htype;
1644 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1645 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1646 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1647 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1648 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1649 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1652 /* Set up the option buffer... */
1653 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1654 options, 0, 0, 0, NULL, 0);
1655 if (ip->client->packet_length < BOOTP_MIN_LEN)
1656 ip->client->packet_length = BOOTP_MIN_LEN;
1658 ip->client->packet.op = BOOTREQUEST;
1659 ip->client->packet.htype = ip->hw_address.htype;
1660 ip->client->packet.hlen = ip->hw_address.hlen;
1661 ip->client->packet.hops = 0;
1662 ip->client->packet.xid = ip->client->xid;
1663 ip->client->packet.secs = 0; /* Filled in by send_request. */
1665 /* If we own the address we're requesting, put it in ciaddr;
1666 otherwise set ciaddr to zero. */
1667 if (ip->client->state == S_BOUND ||
1668 ip->client->state == S_RENEWING ||
1669 ip->client->state == S_REBINDING) {
1670 memcpy(&ip->client->packet.ciaddr,
1671 lease->address.iabuf, lease->address.len);
1672 ip->client->packet.flags = 0;
1674 memset(&ip->client->packet.ciaddr, 0,
1675 sizeof(ip->client->packet.ciaddr));
1676 ip->client->packet.flags = 0;
1679 memset(&ip->client->packet.yiaddr, 0,
1680 sizeof(ip->client->packet.yiaddr));
1681 memset(&ip->client->packet.siaddr, 0,
1682 sizeof(ip->client->packet.siaddr));
1683 memset(&ip->client->packet.giaddr, 0,
1684 sizeof(ip->client->packet.giaddr));
1685 memcpy(ip->client->packet.chaddr,
1686 ip->hw_address.haddr, ip->hw_address.hlen);
1690 make_decline(struct interface_info *ip, struct client_lease *lease)
1692 struct tree_cache *options[256], message_type_tree;
1693 struct tree_cache requested_address_tree;
1694 struct tree_cache server_id_tree, client_id_tree;
1695 unsigned char decline = DHCPDECLINE;
1698 memset(options, 0, sizeof(options));
1699 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1701 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1702 i = DHO_DHCP_MESSAGE_TYPE;
1703 options[i] = &message_type_tree;
1704 options[i]->value = &decline;
1705 options[i]->len = sizeof(decline);
1706 options[i]->buf_size = sizeof(decline);
1707 options[i]->timeout = 0xFFFFFFFF;
1709 /* Send back the server identifier... */
1710 i = DHO_DHCP_SERVER_IDENTIFIER;
1711 options[i] = &server_id_tree;
1712 options[i]->value = lease->options[i].data;
1713 options[i]->len = lease->options[i].len;
1714 options[i]->buf_size = lease->options[i].len;
1715 options[i]->timeout = 0xFFFFFFFF;
1717 /* Send back the address we're declining. */
1718 i = DHO_DHCP_REQUESTED_ADDRESS;
1719 options[i] = &requested_address_tree;
1720 options[i]->value = lease->address.iabuf;
1721 options[i]->len = lease->address.len;
1722 options[i]->buf_size = lease->address.len;
1723 options[i]->timeout = 0xFFFFFFFF;
1725 /* Send the uid if the user supplied one. */
1726 i = DHO_DHCP_CLIENT_IDENTIFIER;
1727 if (ip->client->config->send_options[i].len) {
1728 options[i] = &client_id_tree;
1729 options[i]->value = ip->client->config->send_options[i].data;
1730 options[i]->len = ip->client->config->send_options[i].len;
1731 options[i]->buf_size = ip->client->config->send_options[i].len;
1732 options[i]->timeout = 0xFFFFFFFF;
1736 /* Set up the option buffer... */
1737 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1738 options, 0, 0, 0, NULL, 0);
1739 if (ip->client->packet_length < BOOTP_MIN_LEN)
1740 ip->client->packet_length = BOOTP_MIN_LEN;
1742 ip->client->packet.op = BOOTREQUEST;
1743 ip->client->packet.htype = ip->hw_address.htype;
1744 ip->client->packet.hlen = ip->hw_address.hlen;
1745 ip->client->packet.hops = 0;
1746 ip->client->packet.xid = ip->client->xid;
1747 ip->client->packet.secs = 0; /* Filled in by send_request. */
1748 ip->client->packet.flags = 0;
1750 /* ciaddr must always be zero. */
1751 memset(&ip->client->packet.ciaddr, 0,
1752 sizeof(ip->client->packet.ciaddr));
1753 memset(&ip->client->packet.yiaddr, 0,
1754 sizeof(ip->client->packet.yiaddr));
1755 memset(&ip->client->packet.siaddr, 0,
1756 sizeof(ip->client->packet.siaddr));
1757 memset(&ip->client->packet.giaddr, 0,
1758 sizeof(ip->client->packet.giaddr));
1759 memcpy(ip->client->packet.chaddr,
1760 ip->hw_address.haddr, ip->hw_address.hlen);
1764 free_client_lease(struct client_lease *lease)
1768 if (lease->server_name)
1769 free(lease->server_name);
1770 if (lease->filename)
1771 free(lease->filename);
1772 for (i = 0; i < 256; i++) {
1773 if (lease->options[i].len)
1774 free(lease->options[i].data);
1782 rewrite_client_leases(void)
1784 struct client_lease *lp;
1787 leaseFile = fopen(path_dhclient_db, "w");
1789 error("can't create %s: %m", path_dhclient_db);
1795 for (lp = ifi->client->leases; lp; lp = lp->next)
1796 write_client_lease(ifi, lp, 1);
1797 if (ifi->client->active)
1798 write_client_lease(ifi, ifi->client->active, 1);
1801 ftruncate(fileno(leaseFile), ftello(leaseFile));
1802 fsync(fileno(leaseFile));
1806 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1809 static int leases_written;
1814 if (leases_written++ > 20) {
1815 rewrite_client_leases();
1820 /* If the lease came from the config file, we don't need to stash
1821 a copy in the lease database. */
1822 if (lease->is_static)
1825 if (!leaseFile) { /* XXX */
1826 leaseFile = fopen(path_dhclient_db, "w");
1828 error("can't create %s: %m", path_dhclient_db);
1831 fprintf(leaseFile, "lease {\n");
1832 if (lease->is_bootp)
1833 fprintf(leaseFile, " bootp;\n");
1834 fprintf(leaseFile, " interface \"%s\";\n", ip->name);
1835 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
1836 if (lease->filename)
1837 fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
1838 if (lease->server_name)
1839 fprintf(leaseFile, " server-name \"%s\";\n",
1840 lease->server_name);
1842 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string);
1843 for (i = 0; i < 256; i++)
1844 if (lease->options[i].len)
1845 fprintf(leaseFile, " option %s %s;\n",
1846 dhcp_options[i].name,
1847 pretty_print_option(i, lease->options[i].data,
1848 lease->options[i].len, 1, 1));
1850 t = gmtime(&lease->renewal);
1851 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1852 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1853 t->tm_hour, t->tm_min, t->tm_sec);
1854 t = gmtime(&lease->rebind);
1855 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1856 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1857 t->tm_hour, t->tm_min, t->tm_sec);
1858 t = gmtime(&lease->expiry);
1859 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1860 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1861 t->tm_hour, t->tm_min, t->tm_sec);
1862 fprintf(leaseFile, "}\n");
1867 script_init(char *reason, struct string_list *medium)
1869 size_t len, mediumlen = 0;
1870 struct imsg_hdr hdr;
1874 if (medium != NULL && medium->string != NULL)
1875 mediumlen = strlen(medium->string);
1877 hdr.code = IMSG_SCRIPT_INIT;
1878 hdr.len = sizeof(struct imsg_hdr) +
1879 sizeof(size_t) + mediumlen +
1880 sizeof(size_t) + strlen(reason);
1882 if ((buf = buf_open(hdr.len)) == NULL)
1883 error("buf_open: %m");
1886 errs += buf_add(buf, &hdr, sizeof(hdr));
1887 errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
1889 errs += buf_add(buf, medium->string, mediumlen);
1890 len = strlen(reason);
1891 errs += buf_add(buf, &len, sizeof(len));
1892 errs += buf_add(buf, reason, len);
1895 error("buf_add: %m");
1897 if (buf_close(privfd, buf) == -1)
1898 error("buf_close: %m");
1902 priv_script_init(char *reason, char *medium)
1904 struct interface_info *ip = ifi;
1907 ip->client->scriptEnvsize = 100;
1908 if (ip->client->scriptEnv == NULL)
1909 ip->client->scriptEnv =
1910 malloc(ip->client->scriptEnvsize * sizeof(char *));
1911 if (ip->client->scriptEnv == NULL)
1912 error("script_init: no memory for environment");
1914 ip->client->scriptEnv[0] = strdup(CLIENT_PATH);
1915 if (ip->client->scriptEnv[0] == NULL)
1916 error("script_init: no memory for environment");
1918 ip->client->scriptEnv[1] = NULL;
1920 script_set_env(ip->client, "", "interface", ip->name);
1923 script_set_env(ip->client, "", "medium", medium);
1925 script_set_env(ip->client, "", "reason", reason);
1930 priv_script_write_params(char *prefix, struct client_lease *lease)
1932 struct interface_info *ip = ifi;
1933 u_int8_t dbuf[1500], *dp = NULL;
1937 script_set_env(ip->client, prefix, "ip_address",
1938 piaddr(lease->address));
1940 if (ip->client->config->default_actions[DHO_SUBNET_MASK] ==
1942 dp = ip->client->config->defaults[DHO_SUBNET_MASK].data;
1943 len = ip->client->config->defaults[DHO_SUBNET_MASK].len;
1945 dp = lease->options[DHO_SUBNET_MASK].data;
1946 len = lease->options[DHO_SUBNET_MASK].len;
1948 if (len && (len < sizeof(lease->address.iabuf))) {
1949 struct iaddr netmask, subnet, broadcast;
1951 memcpy(netmask.iabuf, dp, len);
1953 subnet = subnet_number(lease->address, netmask);
1955 script_set_env(ip->client, prefix, "network_number",
1957 if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
1958 broadcast = broadcast_addr(subnet, netmask);
1960 script_set_env(ip->client, prefix,
1961 "broadcast_address",
1967 if (lease->filename)
1968 script_set_env(ip->client, prefix, "filename", lease->filename);
1969 if (lease->server_name)
1970 script_set_env(ip->client, prefix, "server_name",
1971 lease->server_name);
1972 for (i = 0; i < 256; i++) {
1975 if (ip->client->config->defaults[i].len) {
1976 if (lease->options[i].len) {
1978 ip->client->config->default_actions[i]) {
1979 case ACTION_DEFAULT:
1980 dp = lease->options[i].data;
1981 len = lease->options[i].len;
1983 case ACTION_SUPERSEDE:
1986 config->defaults[i].data;
1988 config->defaults[i].len;
1990 case ACTION_PREPEND:
1992 config->defaults[i].len +
1993 lease->options[i].len;
1994 if (len >= sizeof(dbuf)) {
1995 warning("no space to %s %s",
1997 dhcp_options[i].name);
2003 config->defaults[i].data,
2005 config->defaults[i].len);
2006 memcpy(dp + ip->client->
2007 config->defaults[i].len,
2008 lease->options[i].data,
2009 lease->options[i].len);
2014 * When we append, we assume that we're
2015 * appending to text. Some MS servers
2016 * include a NUL byte at the end of
2017 * the search string provided.
2020 config->defaults[i].len +
2021 lease->options[i].len;
2022 if (len >= sizeof(dbuf)) {
2023 warning("no space to %s %s",
2025 dhcp_options[i].name);
2029 lease->options[i].data,
2030 lease->options[i].len);
2031 for (dp = dbuf + lease->options[i].len;
2032 dp > dbuf; dp--, len--)
2037 config->defaults[i].data,
2039 config->defaults[i].len);
2045 config->defaults[i].data;
2047 config->defaults[i].len;
2049 } else if (lease->options[i].len) {
2050 len = lease->options[i].len;
2051 dp = lease->options[i].data;
2058 if (dhcp_option_ev_name(name, sizeof(name),
2060 script_set_env(ip->client, prefix, name,
2061 pretty_print_option(i, dp, len, 0, 0));
2064 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
2065 script_set_env(ip->client, prefix, "expiry", tbuf);
2069 script_write_params(char *prefix, struct client_lease *lease)
2071 size_t fn_len = 0, sn_len = 0, pr_len = 0;
2072 struct imsg_hdr hdr;
2076 if (lease->filename != NULL)
2077 fn_len = strlen(lease->filename);
2078 if (lease->server_name != NULL)
2079 sn_len = strlen(lease->server_name);
2081 pr_len = strlen(prefix);
2083 hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
2084 hdr.len = sizeof(hdr) + sizeof(struct client_lease) +
2085 sizeof(size_t) + fn_len + sizeof(size_t) + sn_len +
2086 sizeof(size_t) + pr_len;
2088 for (i = 0; i < 256; i++)
2089 hdr.len += sizeof(int) + lease->options[i].len;
2091 scripttime = time(NULL);
2093 if ((buf = buf_open(hdr.len)) == NULL)
2094 error("buf_open: %m");
2097 errs += buf_add(buf, &hdr, sizeof(hdr));
2098 errs += buf_add(buf, lease, sizeof(struct client_lease));
2099 errs += buf_add(buf, &fn_len, sizeof(fn_len));
2100 errs += buf_add(buf, lease->filename, fn_len);
2101 errs += buf_add(buf, &sn_len, sizeof(sn_len));
2102 errs += buf_add(buf, lease->server_name, sn_len);
2103 errs += buf_add(buf, &pr_len, sizeof(pr_len));
2104 errs += buf_add(buf, prefix, pr_len);
2106 for (i = 0; i < 256; i++) {
2107 errs += buf_add(buf, &lease->options[i].len,
2108 sizeof(lease->options[i].len));
2109 errs += buf_add(buf, lease->options[i].data,
2110 lease->options[i].len);
2114 error("buf_add: %m");
2116 if (buf_close(privfd, buf) == -1)
2117 error("buf_close: %m");
2123 struct imsg_hdr hdr;
2127 hdr.code = IMSG_SCRIPT_GO;
2128 hdr.len = sizeof(struct imsg_hdr);
2130 if ((buf = buf_open(hdr.len)) == NULL)
2131 error("buf_open: %m");
2133 if (buf_add(buf, &hdr, sizeof(hdr)))
2134 error("buf_add: %m");
2136 if (buf_close(privfd, buf) == -1)
2137 error("buf_close: %m");
2139 bzero(&hdr, sizeof(hdr));
2140 buf_read(privfd, &hdr, sizeof(hdr));
2141 if (hdr.code != IMSG_SCRIPT_GO_RET)
2142 error("unexpected msg type %u", hdr.code);
2143 if (hdr.len != sizeof(hdr) + sizeof(int))
2144 error("received corrupted message");
2145 buf_read(privfd, &ret, sizeof(ret));
2147 scripttime = time(NULL);
2153 priv_script_go(void)
2155 char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI";
2156 static char client_path[] = CLIENT_PATH;
2157 struct interface_info *ip = ifi;
2158 int pid, wpid, wstatus;
2160 scripttime = time(NULL);
2163 scriptName = ip->client->config->script_name;
2164 envp = ip->client->scriptEnv;
2166 scriptName = top_level_config.script_name;
2168 epp[1] = client_path;
2173 argv[0] = scriptName;
2182 wpid = wait(&wstatus);
2183 } while (wpid != pid && wpid > 0);
2189 execve(scriptName, argv, envp);
2190 error("execve (%s, ...): %m", scriptName);
2194 script_flush_env(ip->client);
2196 return (wstatus & 0xff);
2200 script_set_env(struct client_state *client, const char *prefix,
2201 const char *name, const char *value)
2205 namelen = strlen(name);
2207 for (i = 0; client->scriptEnv[i]; i++)
2208 if (strncmp(client->scriptEnv[i], name, namelen) == 0 &&
2209 client->scriptEnv[i][namelen] == '=')
2212 if (client->scriptEnv[i])
2213 /* Reuse the slot. */
2214 free(client->scriptEnv[i]);
2216 /* New variable. Expand if necessary. */
2217 if (i >= client->scriptEnvsize - 1) {
2218 char **newscriptEnv;
2219 int newscriptEnvsize = client->scriptEnvsize + 50;
2221 newscriptEnv = realloc(client->scriptEnv,
2223 if (newscriptEnv == NULL) {
2224 free(client->scriptEnv);
2225 client->scriptEnv = NULL;
2226 client->scriptEnvsize = 0;
2227 error("script_set_env: no memory for variable");
2229 client->scriptEnv = newscriptEnv;
2230 client->scriptEnvsize = newscriptEnvsize;
2232 /* need to set the NULL pointer at end of array beyond
2234 client->scriptEnv[i + 1] = NULL;
2236 /* Allocate space and format the variable in the appropriate slot. */
2237 client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 +
2239 if (client->scriptEnv[i] == NULL)
2240 error("script_set_env: no memory for variable assignment");
2242 /* No `` or $() command substitution allowed in environment values! */
2243 for (j=0; j < strlen(value); j++)
2247 error("illegal character (%c) in value '%s'", value[j],
2251 snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
2252 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
2256 script_flush_env(struct client_state *client)
2260 for (i = 0; client->scriptEnv[i]; i++) {
2261 free(client->scriptEnv[i]);
2262 client->scriptEnv[i] = NULL;
2264 client->scriptEnvsize = 0;
2268 dhcp_option_ev_name(char *buf, size_t buflen, struct option *option)
2272 for (i = 0; option->name[i]; i++) {
2273 if (i + 1 == buflen)
2275 if (option->name[i] == '-')
2278 buf[i] = option->name[i];
2288 static int state = 0;
2290 if (no_daemon || state)
2295 /* Stop logging to stderr... */
2298 if (daemon(1, 0) == -1)
2301 /* we are chrooted, daemon(3) fails to open /dev/null */
2303 dup2(nullfd, STDIN_FILENO);
2304 dup2(nullfd, STDOUT_FILENO);
2305 dup2(nullfd, STDERR_FILENO);
2312 check_option(struct client_lease *l, int option)
2317 /* we use this, since this is what gets passed to dhclient-script */
2319 opbuf = pretty_print_option(option, l->options[option].data,
2320 l->options[option].len, 0, 0);
2322 sbuf = option_as_string(option, l->options[option].data,
2323 l->options[option].len);
2326 case DHO_SUBNET_MASK:
2327 case DHO_TIME_SERVERS:
2328 case DHO_NAME_SERVERS:
2330 case DHO_DOMAIN_NAME_SERVERS:
2331 case DHO_LOG_SERVERS:
2332 case DHO_COOKIE_SERVERS:
2333 case DHO_LPR_SERVERS:
2334 case DHO_IMPRESS_SERVERS:
2335 case DHO_RESOURCE_LOCATION_SERVERS:
2336 case DHO_SWAP_SERVER:
2337 case DHO_BROADCAST_ADDRESS:
2338 case DHO_NIS_SERVERS:
2339 case DHO_NTP_SERVERS:
2340 case DHO_NETBIOS_NAME_SERVERS:
2341 case DHO_NETBIOS_DD_SERVER:
2342 case DHO_FONT_SERVERS:
2343 case DHO_DHCP_SERVER_IDENTIFIER:
2344 case DHO_NISPLUS_SERVERS:
2345 case DHO_MOBILE_IP_HOME_AGENT:
2346 case DHO_SMTP_SERVER:
2347 case DHO_POP_SERVER:
2348 case DHO_NNTP_SERVER:
2349 case DHO_WWW_SERVER:
2350 case DHO_FINGER_SERVER:
2351 case DHO_IRC_SERVER:
2352 case DHO_STREETTALK_SERVER:
2353 case DHO_STREETTALK_DA_SERVER:
2354 if (!ipv4addrs(opbuf)) {
2355 warning("Invalid IP address in option: %s", opbuf);
2360 case DHO_NIS_DOMAIN:
2361 case DHO_NISPLUS_DOMAIN:
2362 case DHO_TFTP_SERVER_NAME:
2363 if (!res_hnok(sbuf)) {
2364 warning("Bogus Host Name option %d: %s (%s)", option,
2366 l->options[option].len = 0;
2367 free(l->options[option].data);
2370 case DHO_DOMAIN_NAME:
2371 if (!res_hnok(sbuf)) {
2372 if (!check_search(sbuf)) {
2373 warning("Bogus domain search list %d: %s (%s)",
2374 option, sbuf, opbuf);
2375 l->options[option].len = 0;
2376 free(l->options[option].data);
2381 case DHO_TIME_OFFSET:
2383 case DHO_MERIT_DUMP:
2385 case DHO_EXTENSIONS_PATH:
2386 case DHO_IP_FORWARDING:
2387 case DHO_NON_LOCAL_SOURCE_ROUTING:
2388 case DHO_POLICY_FILTER:
2389 case DHO_MAX_DGRAM_REASSEMBLY:
2390 case DHO_DEFAULT_IP_TTL:
2391 case DHO_PATH_MTU_AGING_TIMEOUT:
2392 case DHO_PATH_MTU_PLATEAU_TABLE:
2393 case DHO_INTERFACE_MTU:
2394 case DHO_ALL_SUBNETS_LOCAL:
2395 case DHO_PERFORM_MASK_DISCOVERY:
2396 case DHO_MASK_SUPPLIER:
2397 case DHO_ROUTER_DISCOVERY:
2398 case DHO_ROUTER_SOLICITATION_ADDRESS:
2399 case DHO_STATIC_ROUTES:
2400 case DHO_TRAILER_ENCAPSULATION:
2401 case DHO_ARP_CACHE_TIMEOUT:
2402 case DHO_IEEE802_3_ENCAPSULATION:
2403 case DHO_DEFAULT_TCP_TTL:
2404 case DHO_TCP_KEEPALIVE_INTERVAL:
2405 case DHO_TCP_KEEPALIVE_GARBAGE:
2406 case DHO_VENDOR_ENCAPSULATED_OPTIONS:
2407 case DHO_NETBIOS_NODE_TYPE:
2408 case DHO_NETBIOS_SCOPE:
2409 case DHO_X_DISPLAY_MANAGER:
2410 case DHO_DHCP_REQUESTED_ADDRESS:
2411 case DHO_DHCP_LEASE_TIME:
2412 case DHO_DHCP_OPTION_OVERLOAD:
2413 case DHO_DHCP_MESSAGE_TYPE:
2414 case DHO_DHCP_PARAMETER_REQUEST_LIST:
2415 case DHO_DHCP_MESSAGE:
2416 case DHO_DHCP_MAX_MESSAGE_SIZE:
2417 case DHO_DHCP_RENEWAL_TIME:
2418 case DHO_DHCP_REBINDING_TIME:
2419 case DHO_DHCP_CLASS_IDENTIFIER:
2420 case DHO_DHCP_CLIENT_IDENTIFIER:
2421 case DHO_BOOTFILE_NAME:
2422 case DHO_DHCP_USER_CLASS_ID:
2425 case DHO_CLASSLESS_ROUTES:
2426 return (check_classless_option(l->options[option].data,
2427 l->options[option].len));
2429 warning("unknown dhcp option value 0x%x", option);
2430 return (unknown_ok);
2434 /* RFC 3442 The Classless Static Routes option checks */
2436 check_classless_option(unsigned char *data, int len)
2439 unsigned char width;
2440 in_addr_t addr, mask;
2443 warning("Too small length: %d", len);
2451 } else if (width < 9) {
2452 addr = (in_addr_t)(data[i] << 24);
2454 } else if (width < 17) {
2455 addr = (in_addr_t)(data[i] << 24) +
2456 (in_addr_t)(data[i + 1] << 16);
2458 } else if (width < 25) {
2459 addr = (in_addr_t)(data[i] << 24) +
2460 (in_addr_t)(data[i + 1] << 16) +
2461 (in_addr_t)(data[i + 2] << 8);
2463 } else if (width < 33) {
2464 addr = (in_addr_t)(data[i] << 24) +
2465 (in_addr_t)(data[i + 1] << 16) +
2466 (in_addr_t)(data[i + 2] << 8) +
2470 warning("Incorrect subnet width: %d", width);
2473 mask = (in_addr_t)(~0) << (32 - width);
2479 * ... After deriving a subnet number and subnet mask
2480 * from each destination descriptor, the DHCP client
2481 * MUST zero any bits in the subnet number where the
2482 * corresponding bit in the mask is zero...
2484 if ((addr & mask) != addr) {
2486 data[i - 1] = (unsigned char)(
2487 (addr >> (((32 - width)/8)*8)) & 0xFF);
2492 warning("Incorrect data length: %d (must be %d)", len, i);
2499 res_hnok(const char *dn)
2501 int pch = PERIOD, ch = *dn++;
2503 while (ch != '\0') {
2506 if (periodchar(ch)) {
2508 } else if (periodchar(pch)) {
2509 if (!borderchar(ch))
2511 } else if (periodchar(nch) || nch == '\0') {
2512 if (!borderchar(ch))
2515 if (!middlechar(ch))
2524 check_search(const char *srch)
2526 int pch = PERIOD, ch = *srch++;
2529 /* 256 char limit re resolv.conf(5) */
2530 if (strlen(srch) > 256)
2533 while (whitechar(ch))
2536 while (ch != '\0') {
2539 if (periodchar(ch) || whitechar(ch)) {
2541 } else if (periodchar(pch)) {
2542 if (!borderchar(ch))
2544 } else if (periodchar(nch) || nch == '\0') {
2545 if (!borderchar(ch))
2548 if (!middlechar(ch))
2551 if (!whitechar(ch)) {
2554 while (whitechar(nch)) {
2563 /* 6 domain limit re resolv.conf(5) */
2569 /* Does buf consist only of dotted decimal ipv4 addrs?
2570 * return how many if so,
2571 * otherwise, return 0
2574 ipv4addrs(char * buf)
2579 while (inet_aton(buf, &jnk) == 1){
2581 while (periodchar(*buf) || digitchar(*buf))
2593 option_as_string(unsigned int code, unsigned char *data, int len)
2595 static char optbuf[32768]; /* XXX */
2597 int opleft = sizeof(optbuf);
2598 unsigned char *dp = data;
2601 error("option_as_string: bad code %d", code);
2603 for (; dp < data + len; dp++) {
2604 if (!isascii(*dp) || !isprint(*dp)) {
2605 if (dp + 1 != data + len || *dp != 0) {
2606 snprintf(op, opleft, "\\%03o", *dp);
2610 } else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
2611 *dp == '`' || *dp == '\\') {
2625 warning("dhcp option too large");
2630 fork_privchld(int fd, int fd2)
2632 struct pollfd pfd[1];
2637 error("cannot fork");
2644 setproctitle("%s [priv]", ifi->name);
2647 dup2(nullfd, STDIN_FILENO);
2648 dup2(nullfd, STDOUT_FILENO);
2649 dup2(nullfd, STDERR_FILENO);
2655 pfd[0].events = POLLIN;
2656 if ((nfds = poll(pfd, 1, INFTIM)) == -1)
2658 error("poll error");
2660 if (nfds == 0 || !(pfd[0].revents & POLLIN))