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))
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)
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 * XXX: If someone other than us adds our address,
229 * we should assume they are taking over from us,
230 * delete the lease record, and exit without modifying
235 ifam = (struct ifa_msghdr *)rtm;
237 if (ifam->ifam_index != ifi->index)
239 if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
241 if (scripttime == 0 || t < scripttime + 10)
244 sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs);
248 if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf))
249 error("king bula sez: len mismatch");
250 memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len);
251 if (addr_eq(a, defaddr))
254 for (l = ifi->client->active; l != NULL; l = l->next)
255 if (addr_eq(a, l->address))
258 if (l == NULL) /* deleted addr is not the one we set */
262 ifm = (struct if_msghdr *)rtm;
263 if (ifm->ifm_index != ifi->index)
265 if ((rtm->rtm_flags & RTF_UP) == 0)
269 ifan = (struct if_announcemsghdr *)rtm;
270 if (ifan->ifan_what == IFAN_DEPARTURE &&
271 ifan->ifan_index == ifi->index)
275 ifan = (struct if_announcemsghdr *)rtm;
276 if (ifan->ifan_index != ifi->index)
278 switch (ifan->ifan_what) {
279 case RTM_IEEE80211_ASSOC:
280 case RTM_IEEE80211_REASSOC:
282 * Use assoc/reassoc event to kick state machine
283 * in case we roam. Otherwise fall back to the
284 * normal state machine just like a wired network.
286 jev = (struct ieee80211_join_event *) &ifan[1];
287 if (memcmp(curbssid, jev->iev_addr, 6)) {
291 memcpy(curbssid, jev->iev_addr, 6);
301 script_init("FAIL", NULL);
302 if (ifi->client->alias)
303 script_write_params("alias_", ifi->client->alias);
309 main(int argc, char *argv[])
311 extern char *__progname;
312 int ch, fd, quiet = 0, i = 0;
314 int immediate_daemon = 0;
317 /* Initially, log errors to stderr as well as to syslogd. */
318 openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
319 setlogmask(LOG_UPTO(LOG_DEBUG));
321 while ((ch = getopt(argc, argv, "bc:dl:qu")) != -1)
324 immediate_daemon = 1;
327 path_dhclient_conf = optarg;
333 path_dhclient_db = optarg;
351 if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL)
353 if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
354 error("Interface name too long");
355 if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s",
356 _PATH_DHCLIENT_DB, ifi->name) == -1)
365 memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
366 sockaddr_broadcast.sin_family = AF_INET;
367 sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
368 sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
369 sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast);
370 inaddr_any.s_addr = INADDR_ANY;
374 if (!interface_link_status(ifi->name)) {
375 fprintf(stderr, "%s: no link ...", ifi->name);
378 while (!interface_link_status(ifi->name)) {
379 fprintf(stderr, ".");
382 fprintf(stderr, " giving up\n");
387 fprintf(stderr, " got link\n");
390 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
391 error("cannot open %s: %m", _PATH_DEVNULL);
393 if ((pw = getpwnam("_dhcp")) == NULL) {
394 warning("no such user: _dhcp, falling back to \"nobody\"");
395 if ((pw = getpwnam("nobody")) == NULL)
396 error("no such user: nobody");
399 if (pipe(pipe_fd) == -1)
402 fork_privchld(pipe_fd[0], pipe_fd[1]);
407 if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
408 error("can't open and lock %s: %m", path_dhclient_db);
409 read_client_leases();
410 rewrite_client_leases();
413 priv_script_init("PREINIT", NULL);
414 if (ifi->client->alias)
415 priv_script_write_params("alias_", ifi->client->alias);
418 if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
419 add_protocol("AF_ROUTE", routefd, routehandler, ifi);
421 /* set up the interface */
422 discover_interfaces(ifi);
424 if (chroot(_PATH_VAREMPTY) == -1)
426 if (chdir("/") == -1)
427 error("chdir(\"/\")");
429 if (setgroups(1, &pw->pw_gid) ||
430 setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
431 seteuid(pw->pw_uid) || setuid(pw->pw_uid))
432 error("can't drop privileges: %m");
436 setproctitle("%s", ifi->name);
438 if (immediate_daemon)
441 ifi->client->state = S_INIT;
444 bootp_packet_handler = do_packet;
455 extern char *__progname;
457 fprintf(stderr, "usage: %s [-bdqu] ", __progname);
458 fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
465 * Each routine is called from the dhclient_state_machine() in one of
467 * -> entering INIT state
468 * -> recvpacket_flag == 0: timeout in this state
469 * -> otherwise: received a packet in this state
471 * Return conditions as handled by dhclient_state_machine():
472 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
473 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
474 * Returns 0: finish the nap which was interrupted for no good reason.
476 * Several per-interface variables are used to keep track of the process:
477 * active_lease: the lease that is being used on the interface
478 * (null pointer if not configured yet).
479 * offered_leases: leases corresponding to DHCPOFFER messages that have
480 * been sent to us by DHCP servers.
481 * acked_leases: leases corresponding to DHCPACK messages that have been
482 * sent to us by DHCP servers.
483 * sendpacket: DHCP packet we're trying to send.
484 * destination: IP address to send sendpacket to
485 * In addition, there are several relevant per-lease variables.
486 * T1_expiry, T2_expiry, lease_expiry: lease milestones
487 * In the active lease, these control the process of renewing the lease;
488 * In leases on the acked_leases list, this simply determines when we
489 * can no longer legitimately use the lease.
493 state_reboot(void *ipp)
495 struct interface_info *ip = ipp;
497 /* If we don't remember an active lease, go straight to INIT. */
498 if (!ip->client->active || ip->client->active->is_bootp) {
503 /* We are in the rebooting state. */
504 ip->client->state = S_REBOOTING;
506 /* make_request doesn't initialize xid because it normally comes
507 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
508 so pick an xid now. */
509 ip->client->xid = arc4random();
511 /* Make a DHCPREQUEST packet, and set appropriate per-interface
513 make_request(ip, ip->client->active);
514 ip->client->destination = iaddr_broadcast;
515 ip->client->first_sending = cur_time;
516 ip->client->interval = ip->client->config->initial_interval;
518 /* Zap the medium list... */
519 ip->client->medium = NULL;
521 /* Send out the first DHCPREQUEST packet. */
526 * Called when a lease has completely expired and we've
527 * been unable to renew it.
530 state_init(void *ipp)
532 struct interface_info *ip = ipp;
534 ASSERT_STATE(state, S_INIT);
536 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
538 make_discover(ip, ip->client->active);
539 ip->client->xid = ip->client->packet.xid;
540 ip->client->destination = iaddr_broadcast;
541 ip->client->state = S_SELECTING;
542 ip->client->first_sending = cur_time;
543 ip->client->interval = ip->client->config->initial_interval;
545 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
551 * state_selecting is called when one or more DHCPOFFER packets
552 * have been received and a configurable period of time has passed.
555 state_selecting(void *ipp)
557 struct interface_info *ip = ipp;
558 struct client_lease *lp, *next, *picked;
560 ASSERT_STATE(state, S_SELECTING);
562 /* Cancel state_selecting and send_discover timeouts, since either
563 one could have got us here. */
564 cancel_timeout(state_selecting, ip);
565 cancel_timeout(send_discover, ip);
567 /* We have received one or more DHCPOFFER packets. Currently,
568 the only criterion by which we judge leases is whether or
569 not we get a response when we arp for them. */
571 for (lp = ip->client->offered_leases; lp; lp = next) {
574 /* Check to see if we got an ARPREPLY for the address
575 in this particular lease. */
577 script_init("ARPCHECK", lp->medium);
578 script_write_params("check_", lp);
580 /* If the ARPCHECK code detects another
581 machine using the offered address, it exits
582 nonzero. We need to send a DHCPDECLINE and
585 make_decline(ip, lp);
593 free_client_lease(lp);
596 ip->client->offered_leases = NULL;
598 /* If we just tossed all the leases we were offered, go back
601 ip->client->state = S_INIT;
606 /* If it was a BOOTREPLY, we can just take the address right now. */
607 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
608 ip->client->new = picked;
610 /* Make up some lease expiry times
611 XXX these should be configurable. */
612 ip->client->new->expiry = cur_time + 12000;
613 ip->client->new->renewal += cur_time + 8000;
614 ip->client->new->rebind += cur_time + 10000;
616 ip->client->state = S_REQUESTING;
618 /* Bind to the address we received. */
623 /* Go to the REQUESTING state. */
624 ip->client->destination = iaddr_broadcast;
625 ip->client->state = S_REQUESTING;
626 ip->client->first_sending = cur_time;
627 ip->client->interval = ip->client->config->initial_interval;
629 /* Make a DHCPREQUEST packet from the lease we picked. */
630 make_request(ip, picked);
631 ip->client->xid = ip->client->packet.xid;
633 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
634 free_client_lease(picked);
636 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
640 /* state_requesting is called when we receive a DHCPACK message after
641 having sent out one or more DHCPREQUEST packets. */
644 dhcpack(struct packet *packet)
646 struct interface_info *ip = packet->interface;
647 struct client_lease *lease;
649 /* If we're not receptive to an offer right now, or if the offer
650 has an unrecognizable transaction id, then just drop it. */
651 if (packet->interface->client->xid != packet->raw->xid ||
652 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
653 (memcmp(packet->interface->hw_address.haddr,
654 packet->raw->chaddr, packet->raw->hlen)))
657 if (ip->client->state != S_REBOOTING &&
658 ip->client->state != S_REQUESTING &&
659 ip->client->state != S_RENEWING &&
660 ip->client->state != S_REBINDING)
663 note("DHCPACK from %s", piaddr(packet->client_addr));
665 lease = packet_to_lease(packet);
667 note("packet_to_lease failed.");
671 ip->client->new = lease;
673 /* Stop resending DHCPREQUEST. */
674 cancel_timeout(send_request, ip);
676 /* Figure out the lease time. */
677 if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
678 ip->client->new->expiry = getULong(
679 ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
681 ip->client->new->expiry = default_lease_time;
682 /* A number that looks negative here is really just very large,
683 because the lease expiry offset is unsigned. */
684 if (ip->client->new->expiry < 0)
685 ip->client->new->expiry = TIME_MAX;
686 /* XXX should be fixed by resetting the client state */
687 if (ip->client->new->expiry < 60)
688 ip->client->new->expiry = 60;
690 /* Take the server-provided renewal time if there is one;
691 otherwise figure it out according to the spec. */
692 if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
693 ip->client->new->renewal = getULong(
694 ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
696 ip->client->new->renewal = ip->client->new->expiry / 2;
698 /* Same deal with the rebind time. */
699 if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
700 ip->client->new->rebind = getULong(
701 ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
703 ip->client->new->rebind = ip->client->new->renewal +
704 ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
706 ip->client->new->expiry += cur_time;
707 /* Lease lengths can never be negative. */
708 if (ip->client->new->expiry < cur_time)
709 ip->client->new->expiry = TIME_MAX;
710 ip->client->new->renewal += cur_time;
711 if (ip->client->new->renewal < cur_time)
712 ip->client->new->renewal = TIME_MAX;
713 ip->client->new->rebind += cur_time;
714 if (ip->client->new->rebind < cur_time)
715 ip->client->new->rebind = TIME_MAX;
721 bind_lease(struct interface_info *ip)
723 /* Remember the medium. */
724 ip->client->new->medium = ip->client->medium;
726 /* Write out the new lease. */
727 write_client_lease(ip, ip->client->new, 0);
729 /* Run the client script with the new parameters. */
730 script_init((ip->client->state == S_REQUESTING ? "BOUND" :
731 (ip->client->state == S_RENEWING ? "RENEW" :
732 (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))),
733 ip->client->new->medium);
734 if (ip->client->active && ip->client->state != S_REBOOTING)
735 script_write_params("old_", ip->client->active);
736 script_write_params("new_", ip->client->new);
737 if (ip->client->alias)
738 script_write_params("alias_", ip->client->alias);
741 /* Replace the old active lease with the new one. */
742 if (ip->client->active)
743 free_client_lease(ip->client->active);
744 ip->client->active = ip->client->new;
745 ip->client->new = NULL;
747 /* Set up a timeout to start the renewal process. */
748 add_timeout(ip->client->active->renewal, state_bound, ip);
750 note("bound to %s -- renewal in %d seconds.",
751 piaddr(ip->client->active->address),
752 (int)(ip->client->active->renewal - cur_time));
753 ip->client->state = S_BOUND;
754 reinitialize_interfaces();
759 * state_bound is called when we've successfully bound to a particular
760 * lease, but the renewal time on that lease has expired. We are
761 * expected to unicast a DHCPREQUEST to the server that gave us our
765 state_bound(void *ipp)
767 struct interface_info *ip = ipp;
769 ASSERT_STATE(state, S_BOUND);
771 /* T1 has expired. */
772 make_request(ip, ip->client->active);
773 ip->client->xid = ip->client->packet.xid;
775 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
776 memcpy(ip->client->destination.iabuf, ip->client->active->
777 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
778 ip->client->destination.len = 4;
780 ip->client->destination = iaddr_broadcast;
782 ip->client->first_sending = cur_time;
783 ip->client->interval = ip->client->config->initial_interval;
784 ip->client->state = S_RENEWING;
786 /* Send the first packet immediately. */
791 bootp(struct packet *packet)
793 struct iaddrlist *ap;
795 if (packet->raw->op != BOOTREPLY)
798 /* If there's a reject list, make sure this packet's sender isn't
800 for (ap = packet->interface->client->config->reject_list;
802 if (addr_eq(packet->client_addr, ap->addr)) {
803 note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
811 dhcp(struct packet *packet)
813 struct iaddrlist *ap;
814 void (*handler)(struct packet *);
817 switch (packet->packet_type) {
834 /* If there's a reject list, make sure this packet's sender isn't
836 for (ap = packet->interface->client->config->reject_list;
838 if (addr_eq(packet->client_addr, ap->addr)) {
839 note("%s from %s rejected.", type, piaddr(ap->addr));
847 dhcpoffer(struct packet *packet)
849 struct interface_info *ip = packet->interface;
850 struct client_lease *lease, *lp;
852 int arp_timeout_needed, stop_selecting;
853 char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
854 "DHCPOFFER" : "BOOTREPLY";
856 /* If we're not receptive to an offer right now, or if the offer
857 has an unrecognizable transaction id, then just drop it. */
858 if (ip->client->state != S_SELECTING ||
859 packet->interface->client->xid != packet->raw->xid ||
860 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
861 (memcmp(packet->interface->hw_address.haddr,
862 packet->raw->chaddr, packet->raw->hlen)))
865 note("%s from %s", name, piaddr(packet->client_addr));
868 /* If this lease doesn't supply the minimum required parameters,
870 for (i = 0; ip->client->config->required_options[i]; i++) {
871 if (!packet->options[ip->client->config->
872 required_options[i]].len) {
873 note("%s isn't satisfactory.", name);
878 /* If we've already seen this lease, don't record it again. */
879 for (lease = ip->client->offered_leases;
880 lease; lease = lease->next) {
881 if (lease->address.len == sizeof(packet->raw->yiaddr) &&
882 !memcmp(lease->address.iabuf,
883 &packet->raw->yiaddr, lease->address.len)) {
884 debug("%s already seen.", name);
889 lease = packet_to_lease(packet);
891 note("packet_to_lease failed.");
895 /* If this lease was acquired through a BOOTREPLY, record that
897 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
900 /* Record the medium under which this lease was offered. */
901 lease->medium = ip->client->medium;
903 /* Send out an ARP Request for the offered IP address. */
904 script_init("ARPSEND", lease->medium);
905 script_write_params("check_", lease);
906 /* If the script can't send an ARP request without waiting,
907 we'll be waiting when we do the ARPCHECK, so don't wait now. */
909 arp_timeout_needed = 0;
911 arp_timeout_needed = 2;
913 /* Figure out when we're supposed to stop selecting. */
915 ip->client->first_sending + ip->client->config->select_interval;
917 /* If this is the lease we asked for, put it at the head of the
918 list, and don't mess with the arp request timeout. */
919 if (lease->address.len == ip->client->requested_address.len &&
920 !memcmp(lease->address.iabuf,
921 ip->client->requested_address.iabuf,
922 ip->client->requested_address.len)) {
923 lease->next = ip->client->offered_leases;
924 ip->client->offered_leases = lease;
926 /* If we already have an offer, and arping for this
927 offer would take us past the selection timeout,
928 then don't extend the timeout - just hope for the
930 if (ip->client->offered_leases &&
931 (cur_time + arp_timeout_needed) > stop_selecting)
932 arp_timeout_needed = 0;
934 /* Put the lease at the end of the list. */
936 if (!ip->client->offered_leases)
937 ip->client->offered_leases = lease;
939 for (lp = ip->client->offered_leases; lp->next;
946 /* If we're supposed to stop selecting before we've had time
947 to wait for the ARPREPLY, add some delay to wait for
949 if (stop_selecting - cur_time < arp_timeout_needed)
950 stop_selecting = cur_time + arp_timeout_needed;
952 /* If the selecting interval has expired, go immediately to
953 state_selecting(). Otherwise, time out into
954 state_selecting at the select interval. */
955 if (stop_selecting <= 0)
958 add_timeout(stop_selecting, state_selecting, ip);
959 cancel_timeout(send_discover, ip);
963 /* Allocate a client_lease structure and initialize it from the parameters
964 in the specified packet. */
966 struct client_lease *
967 packet_to_lease(struct packet *packet)
969 struct client_lease *lease;
972 lease = malloc(sizeof(struct client_lease));
975 warning("dhcpoffer: no memory to record lease.");
979 memset(lease, 0, sizeof(*lease));
981 /* Copy the lease options. */
982 for (i = 0; i < 256; i++) {
983 if (packet->options[i].len) {
984 lease->options[i].data =
985 malloc(packet->options[i].len + 1);
986 if (!lease->options[i].data) {
987 warning("dhcpoffer: no memory for option %d", i);
988 free_client_lease(lease);
991 memcpy(lease->options[i].data,
992 packet->options[i].data,
993 packet->options[i].len);
994 lease->options[i].len =
995 packet->options[i].len;
996 lease->options[i].data[lease->options[i].len] =
999 if (!check_option(lease,i)) {
1000 /* ignore a bogus lease offer */
1001 warning("Invalid lease option - ignoring offer");
1002 free_client_lease(lease);
1008 lease->address.len = sizeof(packet->raw->yiaddr);
1009 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
1011 /* If the server name was filled out, copy it.
1012 Do not attempt to validate the server name as a host name.
1013 RFC 2131 merely states that sname is NUL-terminated (which do
1014 do not assume) and that it is the server's host name. Since
1015 the ISC client and server allow arbitrary characters, we do
1017 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1018 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
1019 packet->raw->sname[0]) {
1020 lease->server_name = malloc(DHCP_SNAME_LEN + 1);
1021 if (!lease->server_name) {
1022 warning("dhcpoffer: no memory for server name.");
1023 free_client_lease(lease);
1026 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
1027 lease->server_name[DHCP_SNAME_LEN]='\0';
1030 /* Ditto for the filename. */
1031 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1032 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
1033 packet->raw->file[0]) {
1034 /* Don't count on the NUL terminator. */
1035 lease->filename = malloc(DHCP_FILE_LEN + 1);
1036 if (!lease->filename) {
1037 warning("dhcpoffer: no memory for filename.");
1038 free_client_lease(lease);
1041 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
1042 lease->filename[DHCP_FILE_LEN]='\0';
1048 dhcpnak(struct packet *packet)
1050 struct interface_info *ip = packet->interface;
1052 /* If we're not receptive to an offer right now, or if the offer
1053 has an unrecognizable transaction id, then just drop it. */
1054 if (packet->interface->client->xid != packet->raw->xid ||
1055 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
1056 (memcmp(packet->interface->hw_address.haddr,
1057 packet->raw->chaddr, packet->raw->hlen)))
1060 if (ip->client->state != S_REBOOTING &&
1061 ip->client->state != S_REQUESTING &&
1062 ip->client->state != S_RENEWING &&
1063 ip->client->state != S_REBINDING)
1066 note("DHCPNAK from %s", piaddr(packet->client_addr));
1068 if (!ip->client->active) {
1069 note("DHCPNAK with no active lease.\n");
1073 free_client_lease(ip->client->active);
1074 ip->client->active = NULL;
1076 /* Stop sending DHCPREQUEST packets... */
1077 cancel_timeout(send_request, ip);
1079 ip->client->state = S_INIT;
1083 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1084 one after the right interval has expired. If we don't get an offer by
1085 the time we reach the panic interval, call the panic function. */
1088 send_discover(void *ipp)
1090 struct interface_info *ip = ipp;
1091 int interval, increase = 1;
1093 /* Figure out how long it's been since we started transmitting. */
1094 interval = cur_time - ip->client->first_sending;
1096 /* If we're past the panic timeout, call the script and tell it
1097 we haven't found anything for this interface yet. */
1098 if (interval > ip->client->config->timeout) {
1103 /* If we're selecting media, try the whole list before doing
1104 the exponential backoff, but if we've already received an
1105 offer, stop looping, because we obviously have it right. */
1106 if (!ip->client->offered_leases &&
1107 ip->client->config->media) {
1110 if (ip->client->medium) {
1111 ip->client->medium = ip->client->medium->next;
1114 if (!ip->client->medium) {
1116 error("No valid media types for %s!", ip->name);
1117 ip->client->medium = ip->client->config->media;
1121 note("Trying medium \"%s\" %d", ip->client->medium->string,
1123 script_init("MEDIUM", ip->client->medium);
1129 * If we're supposed to increase the interval, do so. If it's
1130 * currently zero (i.e., we haven't sent any packets yet), set
1131 * it to one; otherwise, add to it a random number between zero
1132 * and two times itself. On average, this means that it will
1133 * double with every transmission.
1136 if (!ip->client->interval)
1137 ip->client->interval =
1138 ip->client->config->initial_interval;
1140 ip->client->interval += (arc4random() >> 2) %
1141 (2 * ip->client->interval);
1144 /* Don't backoff past cutoff. */
1145 if (ip->client->interval >
1146 ip->client->config->backoff_cutoff)
1147 ip->client->interval =
1148 ((ip->client->config->backoff_cutoff / 2)
1149 + ((arc4random() >> 2) %
1150 ip->client->config->backoff_cutoff));
1151 } else if (!ip->client->interval)
1152 ip->client->interval =
1153 ip->client->config->initial_interval;
1155 /* If the backoff would take us to the panic timeout, just use that
1157 if (cur_time + ip->client->interval >
1158 ip->client->first_sending + ip->client->config->timeout)
1159 ip->client->interval =
1160 (ip->client->first_sending +
1161 ip->client->config->timeout) - cur_time + 1;
1163 /* Record the number of seconds since we started sending. */
1164 if (interval < 65536)
1165 ip->client->packet.secs = htons(interval);
1167 ip->client->packet.secs = htons(65535);
1168 ip->client->secs = ip->client->packet.secs;
1170 note("DHCPDISCOVER on %s to %s port %d interval %d",
1171 ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
1172 ntohs(sockaddr_broadcast.sin_port),
1173 (int)ip->client->interval);
1175 /* Send out a packet. */
1176 (void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
1177 inaddr_any, &sockaddr_broadcast, NULL);
1179 add_timeout(cur_time + ip->client->interval, send_discover, ip);
1183 * state_panic gets called if we haven't received any offers in a preset
1184 * amount of time. When this happens, we try to use existing leases
1185 * that haven't yet expired, and failing that, we call the client script
1186 * and hope it can do something.
1189 state_panic(void *ipp)
1191 struct interface_info *ip = ipp;
1192 struct client_lease *loop = ip->client->active;
1193 struct client_lease *lp;
1195 note("No DHCPOFFERS received.");
1197 /* We may not have an active lease, but we may have some
1198 predefined leases that we can try. */
1199 if (!ip->client->active && ip->client->leases)
1202 /* Run through the list of leases and see if one can be used. */
1203 while (ip->client->active) {
1204 if (ip->client->active->expiry > cur_time) {
1205 note("Trying recorded lease %s",
1206 piaddr(ip->client->active->address));
1207 /* Run the client script with the existing
1209 script_init("TIMEOUT",
1210 ip->client->active->medium);
1211 script_write_params("new_", ip->client->active);
1212 if (ip->client->alias)
1213 script_write_params("alias_",
1216 /* If the old lease is still good and doesn't
1217 yet need renewal, go into BOUND state and
1218 timeout at the renewal time. */
1221 ip->client->active->renewal) {
1222 ip->client->state = S_BOUND;
1223 note("bound: renewal in %d seconds.",
1224 (int)(ip->client->active->renewal -
1227 ip->client->active->renewal,
1230 ip->client->state = S_BOUND;
1231 note("bound: immediate renewal.");
1234 reinitialize_interfaces();
1240 /* If there are no other leases, give up. */
1241 if (!ip->client->leases) {
1242 ip->client->leases = ip->client->active;
1243 ip->client->active = NULL;
1248 /* Otherwise, put the active lease at the end of the
1249 lease list, and try another lease.. */
1250 for (lp = ip->client->leases; lp->next; lp = lp->next)
1252 lp->next = ip->client->active;
1254 lp->next->next = NULL;
1255 ip->client->active = ip->client->leases;
1256 ip->client->leases = ip->client->leases->next;
1258 /* If we already tried this lease, we've exhausted the
1259 set of leases, so we might as well give up for
1261 if (ip->client->active == loop)
1264 loop = ip->client->active;
1267 /* No leases were available, or what was available didn't work, so
1268 tell the shell script that we failed to allocate an address,
1269 and try again later. */
1270 note("No working leases in persistent database - sleeping.\n");
1271 script_init("FAIL", NULL);
1272 if (ip->client->alias)
1273 script_write_params("alias_", ip->client->alias);
1275 ip->client->state = S_INIT;
1276 add_timeout(cur_time + ip->client->config->retry_interval, state_init,
1282 send_request(void *ipp)
1284 struct interface_info *ip = ipp;
1285 struct sockaddr_in destination;
1286 struct in_addr from;
1289 /* Figure out how long it's been since we started transmitting. */
1290 interval = cur_time - ip->client->first_sending;
1292 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1293 past the reboot timeout, go to INIT and see if we can
1294 DISCOVER an address... */
1295 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1296 means either that we're on a network with no DHCP server,
1297 or that our server is down. In the latter case, assuming
1298 that there is a backup DHCP server, DHCPDISCOVER will get
1299 us a new address, but we could also have successfully
1300 reused our old address. In the former case, we're hosed
1301 anyway. This is not a win-prone situation. */
1302 if ((ip->client->state == S_REBOOTING ||
1303 ip->client->state == S_REQUESTING) &&
1304 interval > ip->client->config->reboot_timeout) {
1306 ip->client->state = S_INIT;
1307 cancel_timeout(send_request, ip);
1312 /* If we're in the reboot state, make sure the media is set up
1314 if (ip->client->state == S_REBOOTING &&
1315 !ip->client->medium &&
1316 ip->client->active->medium ) {
1317 script_init("MEDIUM", ip->client->active->medium);
1319 /* If the medium we chose won't fly, go to INIT state. */
1323 /* Record the medium. */
1324 ip->client->medium = ip->client->active->medium;
1327 /* If the lease has expired, relinquish the address and go back
1328 to the INIT state. */
1329 if (ip->client->state != S_REQUESTING &&
1330 cur_time > ip->client->active->expiry) {
1331 /* Run the client script with the new parameters. */
1332 script_init("EXPIRE", NULL);
1333 script_write_params("old_", ip->client->active);
1334 if (ip->client->alias)
1335 script_write_params("alias_", ip->client->alias);
1338 /* Now do a preinit on the interface so that we can
1339 discover a new address. */
1340 script_init("PREINIT", NULL);
1341 if (ip->client->alias)
1342 script_write_params("alias_", ip->client->alias);
1345 ip->client->state = S_INIT;
1350 /* Do the exponential backoff... */
1351 if (!ip->client->interval)
1352 ip->client->interval = ip->client->config->initial_interval;
1354 ip->client->interval += ((arc4random() >> 2) %
1355 (2 * ip->client->interval));
1357 /* Don't backoff past cutoff. */
1358 if (ip->client->interval >
1359 ip->client->config->backoff_cutoff)
1360 ip->client->interval =
1361 ((ip->client->config->backoff_cutoff / 2) +
1362 ((arc4random() >> 2) % ip->client->interval));
1364 /* If the backoff would take us to the expiry time, just set the
1365 timeout to the expiry time. */
1366 if (ip->client->state != S_REQUESTING &&
1367 cur_time + ip->client->interval >
1368 ip->client->active->expiry)
1369 ip->client->interval =
1370 ip->client->active->expiry - cur_time + 1;
1372 /* If the lease T2 time has elapsed, or if we're not yet bound,
1373 broadcast the DHCPREQUEST rather than unicasting. */
1374 memset(&destination, 0, sizeof(destination));
1375 if (ip->client->state == S_REQUESTING ||
1376 ip->client->state == S_REBOOTING ||
1377 cur_time > ip->client->active->rebind)
1378 destination.sin_addr.s_addr = INADDR_BROADCAST;
1380 memcpy(&destination.sin_addr.s_addr,
1381 ip->client->destination.iabuf,
1382 sizeof(destination.sin_addr.s_addr));
1383 destination.sin_port = htons(REMOTE_PORT);
1384 destination.sin_family = AF_INET;
1385 destination.sin_len = sizeof(destination);
1387 if (ip->client->state != S_REQUESTING)
1388 memcpy(&from, ip->client->active->address.iabuf,
1391 from.s_addr = INADDR_ANY;
1393 /* Record the number of seconds since we started sending. */
1394 if (ip->client->state == S_REQUESTING)
1395 ip->client->packet.secs = ip->client->secs;
1397 if (interval < 65536)
1398 ip->client->packet.secs = htons(interval);
1400 ip->client->packet.secs = htons(65535);
1403 note("DHCPREQUEST on %s to %s port %d", ip->name,
1404 inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
1406 /* Send out a packet. */
1407 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1408 from, &destination, NULL);
1410 add_timeout(cur_time + ip->client->interval, send_request, ip);
1414 send_decline(void *ipp)
1416 struct interface_info *ip = ipp;
1418 note("DHCPDECLINE on %s to %s port %d", ip->name,
1419 inet_ntoa(sockaddr_broadcast.sin_addr),
1420 ntohs(sockaddr_broadcast.sin_port));
1422 /* Send out a packet. */
1423 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1424 inaddr_any, &sockaddr_broadcast, NULL);
1428 make_discover(struct interface_info *ip, struct client_lease *lease)
1430 unsigned char discover = DHCPDISCOVER;
1431 struct tree_cache *options[256];
1432 struct tree_cache option_elements[256];
1435 memset(option_elements, 0, sizeof(option_elements));
1436 memset(options, 0, sizeof(options));
1437 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1439 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1440 i = DHO_DHCP_MESSAGE_TYPE;
1441 options[i] = &option_elements[i];
1442 options[i]->value = &discover;
1443 options[i]->len = sizeof(discover);
1444 options[i]->buf_size = sizeof(discover);
1445 options[i]->timeout = 0xFFFFFFFF;
1447 /* Request the options we want */
1448 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1449 options[i] = &option_elements[i];
1450 options[i]->value = ip->client->config->requested_options;
1451 options[i]->len = ip->client->config->requested_option_count;
1452 options[i]->buf_size =
1453 ip->client->config->requested_option_count;
1454 options[i]->timeout = 0xFFFFFFFF;
1456 /* If we had an address, try to get it again. */
1458 ip->client->requested_address = lease->address;
1459 i = DHO_DHCP_REQUESTED_ADDRESS;
1460 options[i] = &option_elements[i];
1461 options[i]->value = lease->address.iabuf;
1462 options[i]->len = lease->address.len;
1463 options[i]->buf_size = lease->address.len;
1464 options[i]->timeout = 0xFFFFFFFF;
1466 ip->client->requested_address.len = 0;
1468 /* Send any options requested in the config file. */
1469 for (i = 0; i < 256; i++)
1471 ip->client->config->send_options[i].data) {
1472 options[i] = &option_elements[i];
1474 ip->client->config->send_options[i].data;
1476 ip->client->config->send_options[i].len;
1477 options[i]->buf_size =
1478 ip->client->config->send_options[i].len;
1479 options[i]->timeout = 0xFFFFFFFF;
1482 /* send host name if not set via config file. */
1483 char hostname[_POSIX_HOST_NAME_MAX+1];
1484 if (!options[DHO_HOST_NAME]) {
1485 if (gethostname(hostname, sizeof(hostname)) == 0) {
1487 char* posDot = strchr(hostname, '.');
1489 len = posDot - hostname;
1491 len = strlen(hostname);
1492 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1493 options[DHO_HOST_NAME]->value = hostname;
1494 options[DHO_HOST_NAME]->len = len;
1495 options[DHO_HOST_NAME]->buf_size = len;
1496 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1500 /* set unique client identifier */
1501 char client_ident[sizeof(struct hardware)];
1502 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1503 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1504 ip->hw_address.hlen : sizeof(client_ident)-1;
1505 client_ident[0] = ip->hw_address.htype;
1506 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1507 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1508 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1509 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1510 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1511 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1514 /* Set up the option buffer... */
1515 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1516 options, 0, 0, 0, NULL, 0);
1517 if (ip->client->packet_length < BOOTP_MIN_LEN)
1518 ip->client->packet_length = BOOTP_MIN_LEN;
1520 ip->client->packet.op = BOOTREQUEST;
1521 ip->client->packet.htype = ip->hw_address.htype;
1522 ip->client->packet.hlen = ip->hw_address.hlen;
1523 ip->client->packet.hops = 0;
1524 ip->client->packet.xid = arc4random();
1525 ip->client->packet.secs = 0; /* filled in by send_discover. */
1526 ip->client->packet.flags = 0;
1528 memset(&(ip->client->packet.ciaddr),
1529 0, sizeof(ip->client->packet.ciaddr));
1530 memset(&(ip->client->packet.yiaddr),
1531 0, sizeof(ip->client->packet.yiaddr));
1532 memset(&(ip->client->packet.siaddr),
1533 0, sizeof(ip->client->packet.siaddr));
1534 memset(&(ip->client->packet.giaddr),
1535 0, sizeof(ip->client->packet.giaddr));
1536 memcpy(ip->client->packet.chaddr,
1537 ip->hw_address.haddr, ip->hw_address.hlen);
1542 make_request(struct interface_info *ip, struct client_lease * lease)
1544 unsigned char request = DHCPREQUEST;
1545 struct tree_cache *options[256];
1546 struct tree_cache option_elements[256];
1549 memset(options, 0, sizeof(options));
1550 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1552 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1553 i = DHO_DHCP_MESSAGE_TYPE;
1554 options[i] = &option_elements[i];
1555 options[i]->value = &request;
1556 options[i]->len = sizeof(request);
1557 options[i]->buf_size = sizeof(request);
1558 options[i]->timeout = 0xFFFFFFFF;
1560 /* Request the options we want */
1561 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1562 options[i] = &option_elements[i];
1563 options[i]->value = ip->client->config->requested_options;
1564 options[i]->len = ip->client->config->requested_option_count;
1565 options[i]->buf_size =
1566 ip->client->config->requested_option_count;
1567 options[i]->timeout = 0xFFFFFFFF;
1569 /* If we are requesting an address that hasn't yet been assigned
1570 to us, use the DHCP Requested Address option. */
1571 if (ip->client->state == S_REQUESTING) {
1572 /* Send back the server identifier... */
1573 i = DHO_DHCP_SERVER_IDENTIFIER;
1574 options[i] = &option_elements[i];
1575 options[i]->value = lease->options[i].data;
1576 options[i]->len = lease->options[i].len;
1577 options[i]->buf_size = lease->options[i].len;
1578 options[i]->timeout = 0xFFFFFFFF;
1580 if (ip->client->state == S_REQUESTING ||
1581 ip->client->state == S_REBOOTING) {
1582 ip->client->requested_address = lease->address;
1583 i = DHO_DHCP_REQUESTED_ADDRESS;
1584 options[i] = &option_elements[i];
1585 options[i]->value = lease->address.iabuf;
1586 options[i]->len = lease->address.len;
1587 options[i]->buf_size = lease->address.len;
1588 options[i]->timeout = 0xFFFFFFFF;
1590 ip->client->requested_address.len = 0;
1592 /* Send any options requested in the config file. */
1593 for (i = 0; i < 256; i++)
1595 ip->client->config->send_options[i].data) {
1596 options[i] = &option_elements[i];
1598 ip->client->config->send_options[i].data;
1600 ip->client->config->send_options[i].len;
1601 options[i]->buf_size =
1602 ip->client->config->send_options[i].len;
1603 options[i]->timeout = 0xFFFFFFFF;
1606 /* send host name if not set via config file. */
1607 char hostname[_POSIX_HOST_NAME_MAX+1];
1608 if (!options[DHO_HOST_NAME]) {
1609 if (gethostname(hostname, sizeof(hostname)) == 0) {
1611 char* posDot = strchr(hostname, '.');
1613 len = posDot - hostname;
1615 len = strlen(hostname);
1616 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1617 options[DHO_HOST_NAME]->value = hostname;
1618 options[DHO_HOST_NAME]->len = len;
1619 options[DHO_HOST_NAME]->buf_size = len;
1620 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1624 /* set unique client identifier */
1625 char client_ident[sizeof(struct hardware)];
1626 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1627 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1628 ip->hw_address.hlen : sizeof(client_ident)-1;
1629 client_ident[0] = ip->hw_address.htype;
1630 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1631 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1632 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1633 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1634 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1635 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1638 /* Set up the option buffer... */
1639 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1640 options, 0, 0, 0, NULL, 0);
1641 if (ip->client->packet_length < BOOTP_MIN_LEN)
1642 ip->client->packet_length = BOOTP_MIN_LEN;
1644 ip->client->packet.op = BOOTREQUEST;
1645 ip->client->packet.htype = ip->hw_address.htype;
1646 ip->client->packet.hlen = ip->hw_address.hlen;
1647 ip->client->packet.hops = 0;
1648 ip->client->packet.xid = ip->client->xid;
1649 ip->client->packet.secs = 0; /* Filled in by send_request. */
1651 /* If we own the address we're requesting, put it in ciaddr;
1652 otherwise set ciaddr to zero. */
1653 if (ip->client->state == S_BOUND ||
1654 ip->client->state == S_RENEWING ||
1655 ip->client->state == S_REBINDING) {
1656 memcpy(&ip->client->packet.ciaddr,
1657 lease->address.iabuf, lease->address.len);
1658 ip->client->packet.flags = 0;
1660 memset(&ip->client->packet.ciaddr, 0,
1661 sizeof(ip->client->packet.ciaddr));
1662 ip->client->packet.flags = 0;
1665 memset(&ip->client->packet.yiaddr, 0,
1666 sizeof(ip->client->packet.yiaddr));
1667 memset(&ip->client->packet.siaddr, 0,
1668 sizeof(ip->client->packet.siaddr));
1669 memset(&ip->client->packet.giaddr, 0,
1670 sizeof(ip->client->packet.giaddr));
1671 memcpy(ip->client->packet.chaddr,
1672 ip->hw_address.haddr, ip->hw_address.hlen);
1676 make_decline(struct interface_info *ip, struct client_lease *lease)
1678 struct tree_cache *options[256], message_type_tree;
1679 struct tree_cache requested_address_tree;
1680 struct tree_cache server_id_tree, client_id_tree;
1681 unsigned char decline = DHCPDECLINE;
1684 memset(options, 0, sizeof(options));
1685 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1687 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1688 i = DHO_DHCP_MESSAGE_TYPE;
1689 options[i] = &message_type_tree;
1690 options[i]->value = &decline;
1691 options[i]->len = sizeof(decline);
1692 options[i]->buf_size = sizeof(decline);
1693 options[i]->timeout = 0xFFFFFFFF;
1695 /* Send back the server identifier... */
1696 i = DHO_DHCP_SERVER_IDENTIFIER;
1697 options[i] = &server_id_tree;
1698 options[i]->value = lease->options[i].data;
1699 options[i]->len = lease->options[i].len;
1700 options[i]->buf_size = lease->options[i].len;
1701 options[i]->timeout = 0xFFFFFFFF;
1703 /* Send back the address we're declining. */
1704 i = DHO_DHCP_REQUESTED_ADDRESS;
1705 options[i] = &requested_address_tree;
1706 options[i]->value = lease->address.iabuf;
1707 options[i]->len = lease->address.len;
1708 options[i]->buf_size = lease->address.len;
1709 options[i]->timeout = 0xFFFFFFFF;
1711 /* Send the uid if the user supplied one. */
1712 i = DHO_DHCP_CLIENT_IDENTIFIER;
1713 if (ip->client->config->send_options[i].len) {
1714 options[i] = &client_id_tree;
1715 options[i]->value = ip->client->config->send_options[i].data;
1716 options[i]->len = ip->client->config->send_options[i].len;
1717 options[i]->buf_size = ip->client->config->send_options[i].len;
1718 options[i]->timeout = 0xFFFFFFFF;
1722 /* Set up the option buffer... */
1723 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1724 options, 0, 0, 0, NULL, 0);
1725 if (ip->client->packet_length < BOOTP_MIN_LEN)
1726 ip->client->packet_length = BOOTP_MIN_LEN;
1728 ip->client->packet.op = BOOTREQUEST;
1729 ip->client->packet.htype = ip->hw_address.htype;
1730 ip->client->packet.hlen = ip->hw_address.hlen;
1731 ip->client->packet.hops = 0;
1732 ip->client->packet.xid = ip->client->xid;
1733 ip->client->packet.secs = 0; /* Filled in by send_request. */
1734 ip->client->packet.flags = 0;
1736 /* ciaddr must always be zero. */
1737 memset(&ip->client->packet.ciaddr, 0,
1738 sizeof(ip->client->packet.ciaddr));
1739 memset(&ip->client->packet.yiaddr, 0,
1740 sizeof(ip->client->packet.yiaddr));
1741 memset(&ip->client->packet.siaddr, 0,
1742 sizeof(ip->client->packet.siaddr));
1743 memset(&ip->client->packet.giaddr, 0,
1744 sizeof(ip->client->packet.giaddr));
1745 memcpy(ip->client->packet.chaddr,
1746 ip->hw_address.haddr, ip->hw_address.hlen);
1750 free_client_lease(struct client_lease *lease)
1754 if (lease->server_name)
1755 free(lease->server_name);
1756 if (lease->filename)
1757 free(lease->filename);
1758 for (i = 0; i < 256; i++) {
1759 if (lease->options[i].len)
1760 free(lease->options[i].data);
1768 rewrite_client_leases(void)
1770 struct client_lease *lp;
1773 leaseFile = fopen(path_dhclient_db, "w");
1775 error("can't create %s: %m", path_dhclient_db);
1781 for (lp = ifi->client->leases; lp; lp = lp->next)
1782 write_client_lease(ifi, lp, 1);
1783 if (ifi->client->active)
1784 write_client_lease(ifi, ifi->client->active, 1);
1787 ftruncate(fileno(leaseFile), ftello(leaseFile));
1788 fsync(fileno(leaseFile));
1792 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1795 static int leases_written;
1800 if (leases_written++ > 20) {
1801 rewrite_client_leases();
1806 /* If the lease came from the config file, we don't need to stash
1807 a copy in the lease database. */
1808 if (lease->is_static)
1811 if (!leaseFile) { /* XXX */
1812 leaseFile = fopen(path_dhclient_db, "w");
1814 error("can't create %s: %m", path_dhclient_db);
1817 fprintf(leaseFile, "lease {\n");
1818 if (lease->is_bootp)
1819 fprintf(leaseFile, " bootp;\n");
1820 fprintf(leaseFile, " interface \"%s\";\n", ip->name);
1821 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
1822 if (lease->filename)
1823 fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
1824 if (lease->server_name)
1825 fprintf(leaseFile, " server-name \"%s\";\n",
1826 lease->server_name);
1828 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string);
1829 for (i = 0; i < 256; i++)
1830 if (lease->options[i].len)
1831 fprintf(leaseFile, " option %s %s;\n",
1832 dhcp_options[i].name,
1833 pretty_print_option(i, lease->options[i].data,
1834 lease->options[i].len, 1, 1));
1836 t = gmtime(&lease->renewal);
1837 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1838 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1839 t->tm_hour, t->tm_min, t->tm_sec);
1840 t = gmtime(&lease->rebind);
1841 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1842 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1843 t->tm_hour, t->tm_min, t->tm_sec);
1844 t = gmtime(&lease->expiry);
1845 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1846 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1847 t->tm_hour, t->tm_min, t->tm_sec);
1848 fprintf(leaseFile, "}\n");
1853 script_init(char *reason, struct string_list *medium)
1855 size_t len, mediumlen = 0;
1856 struct imsg_hdr hdr;
1860 if (medium != NULL && medium->string != NULL)
1861 mediumlen = strlen(medium->string);
1863 hdr.code = IMSG_SCRIPT_INIT;
1864 hdr.len = sizeof(struct imsg_hdr) +
1865 sizeof(size_t) + mediumlen +
1866 sizeof(size_t) + strlen(reason);
1868 if ((buf = buf_open(hdr.len)) == NULL)
1869 error("buf_open: %m");
1872 errs += buf_add(buf, &hdr, sizeof(hdr));
1873 errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
1875 errs += buf_add(buf, medium->string, mediumlen);
1876 len = strlen(reason);
1877 errs += buf_add(buf, &len, sizeof(len));
1878 errs += buf_add(buf, reason, len);
1881 error("buf_add: %m");
1883 if (buf_close(privfd, buf) == -1)
1884 error("buf_close: %m");
1888 priv_script_init(char *reason, char *medium)
1890 struct interface_info *ip = ifi;
1893 ip->client->scriptEnvsize = 100;
1894 if (ip->client->scriptEnv == NULL)
1895 ip->client->scriptEnv =
1896 malloc(ip->client->scriptEnvsize * sizeof(char *));
1897 if (ip->client->scriptEnv == NULL)
1898 error("script_init: no memory for environment");
1900 ip->client->scriptEnv[0] = strdup(CLIENT_PATH);
1901 if (ip->client->scriptEnv[0] == NULL)
1902 error("script_init: no memory for environment");
1904 ip->client->scriptEnv[1] = NULL;
1906 script_set_env(ip->client, "", "interface", ip->name);
1909 script_set_env(ip->client, "", "medium", medium);
1911 script_set_env(ip->client, "", "reason", reason);
1916 priv_script_write_params(char *prefix, struct client_lease *lease)
1918 struct interface_info *ip = ifi;
1919 u_int8_t dbuf[1500], *dp = NULL;
1923 script_set_env(ip->client, prefix, "ip_address",
1924 piaddr(lease->address));
1926 if (ip->client->config->default_actions[DHO_SUBNET_MASK] ==
1928 dp = ip->client->config->defaults[DHO_SUBNET_MASK].data;
1929 len = ip->client->config->defaults[DHO_SUBNET_MASK].len;
1931 dp = lease->options[DHO_SUBNET_MASK].data;
1932 len = lease->options[DHO_SUBNET_MASK].len;
1934 if (len && (len < sizeof(lease->address.iabuf))) {
1935 struct iaddr netmask, subnet, broadcast;
1937 memcpy(netmask.iabuf, dp, len);
1939 subnet = subnet_number(lease->address, netmask);
1941 script_set_env(ip->client, prefix, "network_number",
1943 if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
1944 broadcast = broadcast_addr(subnet, netmask);
1946 script_set_env(ip->client, prefix,
1947 "broadcast_address",
1953 if (lease->filename)
1954 script_set_env(ip->client, prefix, "filename", lease->filename);
1955 if (lease->server_name)
1956 script_set_env(ip->client, prefix, "server_name",
1957 lease->server_name);
1958 for (i = 0; i < 256; i++) {
1961 if (ip->client->config->defaults[i].len) {
1962 if (lease->options[i].len) {
1964 ip->client->config->default_actions[i]) {
1965 case ACTION_DEFAULT:
1966 dp = lease->options[i].data;
1967 len = lease->options[i].len;
1969 case ACTION_SUPERSEDE:
1972 config->defaults[i].data;
1974 config->defaults[i].len;
1976 case ACTION_PREPEND:
1978 config->defaults[i].len +
1979 lease->options[i].len;
1980 if (len >= sizeof(dbuf)) {
1981 warning("no space to %s %s",
1983 dhcp_options[i].name);
1989 config->defaults[i].data,
1991 config->defaults[i].len);
1992 memcpy(dp + ip->client->
1993 config->defaults[i].len,
1994 lease->options[i].data,
1995 lease->options[i].len);
2000 * When we append, we assume that we're
2001 * appending to text. Some MS servers
2002 * include a NUL byte at the end of
2003 * the search string provided.
2006 config->defaults[i].len +
2007 lease->options[i].len;
2008 if (len >= sizeof(dbuf)) {
2009 warning("no space to %s %s",
2011 dhcp_options[i].name);
2015 lease->options[i].data,
2016 lease->options[i].len);
2017 for (dp = dbuf + lease->options[i].len;
2018 dp > dbuf; dp--, len--)
2023 config->defaults[i].data,
2025 config->defaults[i].len);
2031 config->defaults[i].data;
2033 config->defaults[i].len;
2035 } else if (lease->options[i].len) {
2036 len = lease->options[i].len;
2037 dp = lease->options[i].data;
2044 if (dhcp_option_ev_name(name, sizeof(name),
2046 script_set_env(ip->client, prefix, name,
2047 pretty_print_option(i, dp, len, 0, 0));
2050 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
2051 script_set_env(ip->client, prefix, "expiry", tbuf);
2055 script_write_params(char *prefix, struct client_lease *lease)
2057 size_t fn_len = 0, sn_len = 0, pr_len = 0;
2058 struct imsg_hdr hdr;
2062 if (lease->filename != NULL)
2063 fn_len = strlen(lease->filename);
2064 if (lease->server_name != NULL)
2065 sn_len = strlen(lease->server_name);
2067 pr_len = strlen(prefix);
2069 hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
2070 hdr.len = sizeof(hdr) + sizeof(struct client_lease) +
2071 sizeof(size_t) + fn_len + sizeof(size_t) + sn_len +
2072 sizeof(size_t) + pr_len;
2074 for (i = 0; i < 256; i++)
2075 hdr.len += sizeof(int) + lease->options[i].len;
2077 scripttime = time(NULL);
2079 if ((buf = buf_open(hdr.len)) == NULL)
2080 error("buf_open: %m");
2083 errs += buf_add(buf, &hdr, sizeof(hdr));
2084 errs += buf_add(buf, lease, sizeof(struct client_lease));
2085 errs += buf_add(buf, &fn_len, sizeof(fn_len));
2086 errs += buf_add(buf, lease->filename, fn_len);
2087 errs += buf_add(buf, &sn_len, sizeof(sn_len));
2088 errs += buf_add(buf, lease->server_name, sn_len);
2089 errs += buf_add(buf, &pr_len, sizeof(pr_len));
2090 errs += buf_add(buf, prefix, pr_len);
2092 for (i = 0; i < 256; i++) {
2093 errs += buf_add(buf, &lease->options[i].len,
2094 sizeof(lease->options[i].len));
2095 errs += buf_add(buf, lease->options[i].data,
2096 lease->options[i].len);
2100 error("buf_add: %m");
2102 if (buf_close(privfd, buf) == -1)
2103 error("buf_close: %m");
2109 struct imsg_hdr hdr;
2113 scripttime = time(NULL);
2115 hdr.code = IMSG_SCRIPT_GO;
2116 hdr.len = sizeof(struct imsg_hdr);
2118 if ((buf = buf_open(hdr.len)) == NULL)
2119 error("buf_open: %m");
2121 if (buf_add(buf, &hdr, sizeof(hdr)))
2122 error("buf_add: %m");
2124 if (buf_close(privfd, buf) == -1)
2125 error("buf_close: %m");
2127 bzero(&hdr, sizeof(hdr));
2128 buf_read(privfd, &hdr, sizeof(hdr));
2129 if (hdr.code != IMSG_SCRIPT_GO_RET)
2130 error("unexpected msg type %u", hdr.code);
2131 if (hdr.len != sizeof(hdr) + sizeof(int))
2132 error("received corrupted message");
2133 buf_read(privfd, &ret, sizeof(ret));
2139 priv_script_go(void)
2141 char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI";
2142 static char client_path[] = CLIENT_PATH;
2143 struct interface_info *ip = ifi;
2144 int pid, wpid, wstatus;
2146 scripttime = time(NULL);
2149 scriptName = ip->client->config->script_name;
2150 envp = ip->client->scriptEnv;
2152 scriptName = top_level_config.script_name;
2154 epp[1] = client_path;
2159 argv[0] = scriptName;
2168 wpid = wait(&wstatus);
2169 } while (wpid != pid && wpid > 0);
2175 execve(scriptName, argv, envp);
2176 error("execve (%s, ...): %m", scriptName);
2180 script_flush_env(ip->client);
2182 return (wstatus & 0xff);
2186 script_set_env(struct client_state *client, const char *prefix,
2187 const char *name, const char *value)
2191 namelen = strlen(name);
2193 for (i = 0; client->scriptEnv[i]; i++)
2194 if (strncmp(client->scriptEnv[i], name, namelen) == 0 &&
2195 client->scriptEnv[i][namelen] == '=')
2198 if (client->scriptEnv[i])
2199 /* Reuse the slot. */
2200 free(client->scriptEnv[i]);
2202 /* New variable. Expand if necessary. */
2203 if (i >= client->scriptEnvsize - 1) {
2204 char **newscriptEnv;
2205 int newscriptEnvsize = client->scriptEnvsize + 50;
2207 newscriptEnv = realloc(client->scriptEnv,
2209 if (newscriptEnv == NULL) {
2210 free(client->scriptEnv);
2211 client->scriptEnv = NULL;
2212 client->scriptEnvsize = 0;
2213 error("script_set_env: no memory for variable");
2215 client->scriptEnv = newscriptEnv;
2216 client->scriptEnvsize = newscriptEnvsize;
2218 /* need to set the NULL pointer at end of array beyond
2220 client->scriptEnv[i + 1] = NULL;
2222 /* Allocate space and format the variable in the appropriate slot. */
2223 client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 +
2225 if (client->scriptEnv[i] == NULL)
2226 error("script_set_env: no memory for variable assignment");
2228 /* No `` or $() command substitution allowed in environment values! */
2229 for (j=0; j < strlen(value); j++)
2233 error("illegal character (%c) in value '%s'", value[j],
2237 snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
2238 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
2242 script_flush_env(struct client_state *client)
2246 for (i = 0; client->scriptEnv[i]; i++) {
2247 free(client->scriptEnv[i]);
2248 client->scriptEnv[i] = NULL;
2250 client->scriptEnvsize = 0;
2254 dhcp_option_ev_name(char *buf, size_t buflen, struct option *option)
2258 for (i = 0; option->name[i]; i++) {
2259 if (i + 1 == buflen)
2261 if (option->name[i] == '-')
2264 buf[i] = option->name[i];
2274 static int state = 0;
2276 if (no_daemon || state)
2281 /* Stop logging to stderr... */
2284 if (daemon(1, 0) == -1)
2287 /* we are chrooted, daemon(3) fails to open /dev/null */
2289 dup2(nullfd, STDIN_FILENO);
2290 dup2(nullfd, STDOUT_FILENO);
2291 dup2(nullfd, STDERR_FILENO);
2298 check_option(struct client_lease *l, int option)
2303 /* we use this, since this is what gets passed to dhclient-script */
2305 opbuf = pretty_print_option(option, l->options[option].data,
2306 l->options[option].len, 0, 0);
2308 sbuf = option_as_string(option, l->options[option].data,
2309 l->options[option].len);
2312 case DHO_SUBNET_MASK:
2313 case DHO_TIME_SERVERS:
2314 case DHO_NAME_SERVERS:
2316 case DHO_DOMAIN_NAME_SERVERS:
2317 case DHO_LOG_SERVERS:
2318 case DHO_COOKIE_SERVERS:
2319 case DHO_LPR_SERVERS:
2320 case DHO_IMPRESS_SERVERS:
2321 case DHO_RESOURCE_LOCATION_SERVERS:
2322 case DHO_SWAP_SERVER:
2323 case DHO_BROADCAST_ADDRESS:
2324 case DHO_NIS_SERVERS:
2325 case DHO_NTP_SERVERS:
2326 case DHO_NETBIOS_NAME_SERVERS:
2327 case DHO_NETBIOS_DD_SERVER:
2328 case DHO_FONT_SERVERS:
2329 case DHO_DHCP_SERVER_IDENTIFIER:
2330 case DHO_NISPLUS_SERVERS:
2331 case DHO_MOBILE_IP_HOME_AGENT:
2332 case DHO_SMTP_SERVER:
2333 case DHO_POP_SERVER:
2334 case DHO_NNTP_SERVER:
2335 case DHO_WWW_SERVER:
2336 case DHO_FINGER_SERVER:
2337 case DHO_IRC_SERVER:
2338 case DHO_STREETTALK_SERVER:
2339 case DHO_STREETTALK_DA_SERVER:
2340 if (!ipv4addrs(opbuf)) {
2341 warning("Invalid IP address in option: %s", opbuf);
2346 case DHO_NIS_DOMAIN:
2347 case DHO_NISPLUS_DOMAIN:
2348 case DHO_TFTP_SERVER_NAME:
2349 if (!res_hnok(sbuf)) {
2350 warning("Bogus Host Name option %d: %s (%s)", option,
2352 l->options[option].len = 0;
2353 free(l->options[option].data);
2356 case DHO_DOMAIN_NAME:
2357 if (!res_hnok(sbuf)) {
2358 if (!check_search(sbuf)) {
2359 warning("Bogus domain search list %d: %s (%s)",
2360 option, sbuf, opbuf);
2361 l->options[option].len = 0;
2362 free(l->options[option].data);
2367 case DHO_TIME_OFFSET:
2369 case DHO_MERIT_DUMP:
2371 case DHO_EXTENSIONS_PATH:
2372 case DHO_IP_FORWARDING:
2373 case DHO_NON_LOCAL_SOURCE_ROUTING:
2374 case DHO_POLICY_FILTER:
2375 case DHO_MAX_DGRAM_REASSEMBLY:
2376 case DHO_DEFAULT_IP_TTL:
2377 case DHO_PATH_MTU_AGING_TIMEOUT:
2378 case DHO_PATH_MTU_PLATEAU_TABLE:
2379 case DHO_INTERFACE_MTU:
2380 case DHO_ALL_SUBNETS_LOCAL:
2381 case DHO_PERFORM_MASK_DISCOVERY:
2382 case DHO_MASK_SUPPLIER:
2383 case DHO_ROUTER_DISCOVERY:
2384 case DHO_ROUTER_SOLICITATION_ADDRESS:
2385 case DHO_STATIC_ROUTES:
2386 case DHO_TRAILER_ENCAPSULATION:
2387 case DHO_ARP_CACHE_TIMEOUT:
2388 case DHO_IEEE802_3_ENCAPSULATION:
2389 case DHO_DEFAULT_TCP_TTL:
2390 case DHO_TCP_KEEPALIVE_INTERVAL:
2391 case DHO_TCP_KEEPALIVE_GARBAGE:
2392 case DHO_VENDOR_ENCAPSULATED_OPTIONS:
2393 case DHO_NETBIOS_NODE_TYPE:
2394 case DHO_NETBIOS_SCOPE:
2395 case DHO_X_DISPLAY_MANAGER:
2396 case DHO_DHCP_REQUESTED_ADDRESS:
2397 case DHO_DHCP_LEASE_TIME:
2398 case DHO_DHCP_OPTION_OVERLOAD:
2399 case DHO_DHCP_MESSAGE_TYPE:
2400 case DHO_DHCP_PARAMETER_REQUEST_LIST:
2401 case DHO_DHCP_MESSAGE:
2402 case DHO_DHCP_MAX_MESSAGE_SIZE:
2403 case DHO_DHCP_RENEWAL_TIME:
2404 case DHO_DHCP_REBINDING_TIME:
2405 case DHO_DHCP_CLASS_IDENTIFIER:
2406 case DHO_DHCP_CLIENT_IDENTIFIER:
2407 case DHO_BOOTFILE_NAME:
2408 case DHO_DHCP_USER_CLASS_ID:
2411 case DHO_CLASSLESS_ROUTES:
2412 return (check_classless_option(l->options[option].data,
2413 l->options[option].len));
2415 warning("unknown dhcp option value 0x%x", option);
2416 return (unknown_ok);
2420 /* RFC 3442 The Classless Static Routes option checks */
2422 check_classless_option(unsigned char *data, int len)
2425 unsigned char width;
2426 in_addr_t addr, mask;
2429 warning("Too small length: %d", len);
2437 } else if (width < 9) {
2438 addr = (in_addr_t)(data[i] << 24);
2440 } else if (width < 17) {
2441 addr = (in_addr_t)(data[i] << 24) +
2442 (in_addr_t)(data[i + 1] << 16);
2444 } else if (width < 25) {
2445 addr = (in_addr_t)(data[i] << 24) +
2446 (in_addr_t)(data[i + 1] << 16) +
2447 (in_addr_t)(data[i + 2] << 8);
2449 } else if (width < 33) {
2450 addr = (in_addr_t)(data[i] << 24) +
2451 (in_addr_t)(data[i + 1] << 16) +
2452 (in_addr_t)(data[i + 2] << 8) +
2456 warning("Incorrect subnet width: %d", width);
2459 mask = (in_addr_t)(~0) << (32 - width);
2465 * ... After deriving a subnet number and subnet mask
2466 * from each destination descriptor, the DHCP client
2467 * MUST zero any bits in the subnet number where the
2468 * corresponding bit in the mask is zero...
2470 if ((addr & mask) != addr) {
2472 data[i - 1] = (unsigned char)(
2473 (addr >> (((32 - width)/8)*8)) & 0xFF);
2478 warning("Incorrect data length: %d (must be %d)", len, i);
2485 res_hnok(const char *dn)
2487 int pch = PERIOD, ch = *dn++;
2489 while (ch != '\0') {
2492 if (periodchar(ch)) {
2494 } else if (periodchar(pch)) {
2495 if (!borderchar(ch))
2497 } else if (periodchar(nch) || nch == '\0') {
2498 if (!borderchar(ch))
2501 if (!middlechar(ch))
2510 check_search(const char *srch)
2512 int pch = PERIOD, ch = *srch++;
2515 /* 256 char limit re resolv.conf(5) */
2516 if (strlen(srch) > 256)
2519 while (whitechar(ch))
2522 while (ch != '\0') {
2525 if (periodchar(ch) || whitechar(ch)) {
2527 } else if (periodchar(pch)) {
2528 if (!borderchar(ch))
2530 } else if (periodchar(nch) || nch == '\0') {
2531 if (!borderchar(ch))
2534 if (!middlechar(ch))
2537 if (!whitechar(ch)) {
2540 while (whitechar(nch)) {
2549 /* 6 domain limit re resolv.conf(5) */
2555 /* Does buf consist only of dotted decimal ipv4 addrs?
2556 * return how many if so,
2557 * otherwise, return 0
2560 ipv4addrs(char * buf)
2565 while (inet_aton(buf, &jnk) == 1){
2567 while (periodchar(*buf) || digitchar(*buf))
2579 option_as_string(unsigned int code, unsigned char *data, int len)
2581 static char optbuf[32768]; /* XXX */
2583 int opleft = sizeof(optbuf);
2584 unsigned char *dp = data;
2587 error("option_as_string: bad code %d", code);
2589 for (; dp < data + len; dp++) {
2590 if (!isascii(*dp) || !isprint(*dp)) {
2591 if (dp + 1 != data + len || *dp != 0) {
2592 snprintf(op, opleft, "\\%03o", *dp);
2596 } else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
2597 *dp == '`' || *dp == '\\') {
2611 warning("dhcp option too large");
2616 fork_privchld(int fd, int fd2)
2618 struct pollfd pfd[1];
2623 error("cannot fork");
2630 setproctitle("%s [priv]", ifi->name);
2633 dup2(nullfd, STDIN_FILENO);
2634 dup2(nullfd, STDOUT_FILENO);
2635 dup2(nullfd, STDERR_FILENO);
2641 pfd[0].events = POLLIN;
2642 if ((nfds = poll(pfd, 1, INFTIM)) == -1)
2644 error("poll error");
2646 if (nfds == 0 || !(pfd[0].revents & POLLIN))