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 ipv4addrs(char * buf);
119 int res_hnok(const char *dn);
120 int check_search(const char *srch);
121 char *option_as_string(unsigned int code, unsigned char *data, int len);
122 int fork_privchld(int, int);
125 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
126 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
131 findproto(char *cp, int n)
138 for (i = 1; i; i <<= 1) {
140 sa = (struct sockaddr *)cp;
146 if (sa->sa_family == AF_INET)
148 if (sa->sa_family == AF_INET6)
161 get_ifa(char *cp, int n)
168 for (i = 1; i; i <<= 1)
170 sa = (struct sockaddr *)cp;
178 struct iaddr defaddr = { 4 };
182 routehandler(struct protocol *p)
185 struct rt_msghdr *rtm;
186 struct if_msghdr *ifm;
187 struct ifa_msghdr *ifam;
188 struct if_announcemsghdr *ifan;
189 struct client_lease *l;
190 time_t t = time(NULL);
195 n = read(routefd, &msg, sizeof(msg));
196 rtm = (struct rt_msghdr *)msg;
197 if (n < sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen ||
198 rtm->rtm_version != RTM_VERSION)
201 switch (rtm->rtm_type) {
204 * XXX: If someone other than us adds our address,
205 * we should assume they are taking over from us,
206 * delete the lease record, and exit without modifying
211 ifam = (struct ifa_msghdr *)rtm;
213 if (ifam->ifam_index != ifi->index)
215 if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
217 if (scripttime == 0 || t < scripttime + 10)
220 sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs);
224 if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf))
225 error("king bula sez: len mismatch");
226 memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len);
227 if (addr_eq(a, defaddr))
230 for (l = ifi->client->active; l != NULL; l = l->next)
231 if (addr_eq(a, l->address))
234 if (l == NULL) /* deleted addr is not the one we set */
238 ifm = (struct if_msghdr *)rtm;
239 if (ifm->ifm_index != ifi->index)
241 if ((rtm->rtm_flags & RTF_UP) == 0)
245 ifan = (struct if_announcemsghdr *)rtm;
246 if (ifan->ifan_what == IFAN_DEPARTURE &&
247 ifan->ifan_index == ifi->index)
251 ifan = (struct if_announcemsghdr *)rtm;
252 if (ifan->ifan_index != ifi->index)
254 switch (ifan->ifan_what) {
255 case RTM_IEEE80211_ASSOC:
256 case RTM_IEEE80211_REASSOC:
259 case RTM_IEEE80211_DISASSOC:
261 * Clear existing state; transition to the init
262 * state and then wait for either a link down
263 * notification or an associate event.
265 if (ifi->client->active != NULL) {
266 script_init("EXPIRE", NULL);
267 script_write_params("old_",
268 ifi->client->active);
269 if (ifi->client->alias)
270 script_write_params("alias_",
274 ifi->client->state = S_INIT;
284 script_init("FAIL", NULL);
285 if (ifi->client->alias)
286 script_write_params("alias_", ifi->client->alias);
292 main(int argc, char *argv[])
294 extern char *__progname;
295 int ch, fd, quiet = 0, i = 0;
297 int immediate_daemon = 0;
300 /* Initially, log errors to stderr as well as to syslogd. */
301 openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
302 setlogmask(LOG_UPTO(LOG_INFO));
304 while ((ch = getopt(argc, argv, "bc:dl:nqu")) != -1)
307 immediate_daemon = 1;
310 path_dhclient_conf = optarg;
316 path_dhclient_db = optarg;
334 if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL)
336 if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
337 error("Interface name too long");
338 if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s",
339 _PATH_DHCLIENT_DB, ifi->name) == -1)
348 memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
349 sockaddr_broadcast.sin_family = AF_INET;
350 sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
351 sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
352 sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast);
353 inaddr_any.s_addr = INADDR_ANY;
357 if (!interface_link_status(ifi->name)) {
358 fprintf(stderr, "%s: no link ...", ifi->name);
361 while (!interface_link_status(ifi->name)) {
362 fprintf(stderr, ".");
365 fprintf(stderr, " giving up\n");
370 fprintf(stderr, " got link\n");
373 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
374 error("cannot open %s: %m", _PATH_DEVNULL);
376 if ((pw = getpwnam("_dhcp")) == NULL) {
377 warning("no such user: _dhcp, falling back to \"nobody\"");
378 if ((pw = getpwnam("nobody")) == NULL)
379 error("no such user: nobody");
382 if (pipe(pipe_fd) == -1)
385 fork_privchld(pipe_fd[0], pipe_fd[1]);
390 if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
391 error("can't open and lock %s: %m", path_dhclient_db);
392 read_client_leases();
393 rewrite_client_leases();
396 priv_script_init("PREINIT", NULL);
397 if (ifi->client->alias)
398 priv_script_write_params("alias_", ifi->client->alias);
401 if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
402 add_protocol("AF_ROUTE", routefd, routehandler, ifi);
404 /* set up the interface */
405 discover_interfaces(ifi);
407 if (chroot(_PATH_VAREMPTY) == -1)
409 if (chdir("/") == -1)
410 error("chdir(\"/\")");
412 if (setgroups(1, &pw->pw_gid) ||
413 setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
414 seteuid(pw->pw_uid) || setuid(pw->pw_uid))
415 error("can't drop privileges: %m");
419 setproctitle("%s", ifi->name);
421 if (immediate_daemon)
424 ifi->client->state = S_INIT;
427 bootp_packet_handler = do_packet;
438 extern char *__progname;
440 fprintf(stderr, "usage: %s [-dqu] ", __progname);
441 fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
448 * Each routine is called from the dhclient_state_machine() in one of
450 * -> entering INIT state
451 * -> recvpacket_flag == 0: timeout in this state
452 * -> otherwise: received a packet in this state
454 * Return conditions as handled by dhclient_state_machine():
455 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
456 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
457 * Returns 0: finish the nap which was interrupted for no good reason.
459 * Several per-interface variables are used to keep track of the process:
460 * active_lease: the lease that is being used on the interface
461 * (null pointer if not configured yet).
462 * offered_leases: leases corresponding to DHCPOFFER messages that have
463 * been sent to us by DHCP servers.
464 * acked_leases: leases corresponding to DHCPACK messages that have been
465 * sent to us by DHCP servers.
466 * sendpacket: DHCP packet we're trying to send.
467 * destination: IP address to send sendpacket to
468 * In addition, there are several relevant per-lease variables.
469 * T1_expiry, T2_expiry, lease_expiry: lease milestones
470 * In the active lease, these control the process of renewing the lease;
471 * In leases on the acked_leases list, this simply determines when we
472 * can no longer legitimately use the lease.
476 state_reboot(void *ipp)
478 struct interface_info *ip = ipp;
480 /* If we don't remember an active lease, go straight to INIT. */
481 if (!ip->client->active || ip->client->active->is_bootp) {
486 /* We are in the rebooting state. */
487 ip->client->state = S_REBOOTING;
489 /* make_request doesn't initialize xid because it normally comes
490 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
491 so pick an xid now. */
492 ip->client->xid = arc4random();
494 /* Make a DHCPREQUEST packet, and set appropriate per-interface
496 make_request(ip, ip->client->active);
497 ip->client->destination = iaddr_broadcast;
498 ip->client->first_sending = cur_time;
499 ip->client->interval = ip->client->config->initial_interval;
501 /* Zap the medium list... */
502 ip->client->medium = NULL;
504 /* Send out the first DHCPREQUEST packet. */
509 * Called when a lease has completely expired and we've
510 * been unable to renew it.
513 state_init(void *ipp)
515 struct interface_info *ip = ipp;
517 ASSERT_STATE(state, S_INIT);
519 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
521 make_discover(ip, ip->client->active);
522 ip->client->xid = ip->client->packet.xid;
523 ip->client->destination = iaddr_broadcast;
524 ip->client->state = S_SELECTING;
525 ip->client->first_sending = cur_time;
526 ip->client->interval = ip->client->config->initial_interval;
528 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
534 * state_selecting is called when one or more DHCPOFFER packets
535 * have been received and a configurable period of time has passed.
538 state_selecting(void *ipp)
540 struct interface_info *ip = ipp;
541 struct client_lease *lp, *next, *picked;
543 ASSERT_STATE(state, S_SELECTING);
545 /* Cancel state_selecting and send_discover timeouts, since either
546 one could have got us here. */
547 cancel_timeout(state_selecting, ip);
548 cancel_timeout(send_discover, ip);
550 /* We have received one or more DHCPOFFER packets. Currently,
551 the only criterion by which we judge leases is whether or
552 not we get a response when we arp for them. */
554 for (lp = ip->client->offered_leases; lp; lp = next) {
557 /* Check to see if we got an ARPREPLY for the address
558 in this particular lease. */
560 script_init("ARPCHECK", lp->medium);
561 script_write_params("check_", lp);
563 /* If the ARPCHECK code detects another
564 machine using the offered address, it exits
565 nonzero. We need to send a DHCPDECLINE and
568 make_decline(ip, lp);
576 free_client_lease(lp);
579 ip->client->offered_leases = NULL;
581 /* If we just tossed all the leases we were offered, go back
584 ip->client->state = S_INIT;
589 /* If it was a BOOTREPLY, we can just take the address right now. */
590 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
591 ip->client->new = picked;
593 /* Make up some lease expiry times
594 XXX these should be configurable. */
595 ip->client->new->expiry = cur_time + 12000;
596 ip->client->new->renewal += cur_time + 8000;
597 ip->client->new->rebind += cur_time + 10000;
599 ip->client->state = S_REQUESTING;
601 /* Bind to the address we received. */
606 /* Go to the REQUESTING state. */
607 ip->client->destination = iaddr_broadcast;
608 ip->client->state = S_REQUESTING;
609 ip->client->first_sending = cur_time;
610 ip->client->interval = ip->client->config->initial_interval;
612 /* Make a DHCPREQUEST packet from the lease we picked. */
613 make_request(ip, picked);
614 ip->client->xid = ip->client->packet.xid;
616 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
617 free_client_lease(picked);
619 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
623 /* state_requesting is called when we receive a DHCPACK message after
624 having sent out one or more DHCPREQUEST packets. */
627 dhcpack(struct packet *packet)
629 struct interface_info *ip = packet->interface;
630 struct client_lease *lease;
632 /* If we're not receptive to an offer right now, or if the offer
633 has an unrecognizable transaction id, then just drop it. */
634 if (packet->interface->client->xid != packet->raw->xid ||
635 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
636 (memcmp(packet->interface->hw_address.haddr,
637 packet->raw->chaddr, packet->raw->hlen)))
640 if (ip->client->state != S_REBOOTING &&
641 ip->client->state != S_REQUESTING &&
642 ip->client->state != S_RENEWING &&
643 ip->client->state != S_REBINDING)
646 note("DHCPACK from %s", piaddr(packet->client_addr));
648 lease = packet_to_lease(packet);
650 note("packet_to_lease failed.");
654 ip->client->new = lease;
656 /* Stop resending DHCPREQUEST. */
657 cancel_timeout(send_request, ip);
659 /* Figure out the lease time. */
660 if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
661 ip->client->new->expiry = getULong(
662 ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
664 ip->client->new->expiry = default_lease_time;
665 /* A number that looks negative here is really just very large,
666 because the lease expiry offset is unsigned. */
667 if (ip->client->new->expiry < 0)
668 ip->client->new->expiry = TIME_MAX;
669 /* XXX should be fixed by resetting the client state */
670 if (ip->client->new->expiry < 60)
671 ip->client->new->expiry = 60;
673 /* Take the server-provided renewal time if there is one;
674 otherwise figure it out according to the spec. */
675 if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
676 ip->client->new->renewal = getULong(
677 ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
679 ip->client->new->renewal = ip->client->new->expiry / 2;
681 /* Same deal with the rebind time. */
682 if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
683 ip->client->new->rebind = getULong(
684 ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
686 ip->client->new->rebind = ip->client->new->renewal +
687 ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
689 ip->client->new->expiry += cur_time;
690 /* Lease lengths can never be negative. */
691 if (ip->client->new->expiry < cur_time)
692 ip->client->new->expiry = TIME_MAX;
693 ip->client->new->renewal += cur_time;
694 if (ip->client->new->renewal < cur_time)
695 ip->client->new->renewal = TIME_MAX;
696 ip->client->new->rebind += cur_time;
697 if (ip->client->new->rebind < cur_time)
698 ip->client->new->rebind = TIME_MAX;
704 bind_lease(struct interface_info *ip)
706 /* Remember the medium. */
707 ip->client->new->medium = ip->client->medium;
709 /* Write out the new lease. */
710 write_client_lease(ip, ip->client->new, 0);
712 /* Run the client script with the new parameters. */
713 script_init((ip->client->state == S_REQUESTING ? "BOUND" :
714 (ip->client->state == S_RENEWING ? "RENEW" :
715 (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))),
716 ip->client->new->medium);
717 if (ip->client->active && ip->client->state != S_REBOOTING)
718 script_write_params("old_", ip->client->active);
719 script_write_params("new_", ip->client->new);
720 if (ip->client->alias)
721 script_write_params("alias_", ip->client->alias);
724 /* Replace the old active lease with the new one. */
725 if (ip->client->active)
726 free_client_lease(ip->client->active);
727 ip->client->active = ip->client->new;
728 ip->client->new = NULL;
730 /* Set up a timeout to start the renewal process. */
731 add_timeout(ip->client->active->renewal, state_bound, ip);
733 note("bound to %s -- renewal in %d seconds.",
734 piaddr(ip->client->active->address),
735 (int)(ip->client->active->renewal - cur_time));
736 ip->client->state = S_BOUND;
737 reinitialize_interfaces();
742 * state_bound is called when we've successfully bound to a particular
743 * lease, but the renewal time on that lease has expired. We are
744 * expected to unicast a DHCPREQUEST to the server that gave us our
748 state_bound(void *ipp)
750 struct interface_info *ip = ipp;
752 ASSERT_STATE(state, S_BOUND);
754 /* T1 has expired. */
755 make_request(ip, ip->client->active);
756 ip->client->xid = ip->client->packet.xid;
758 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
759 memcpy(ip->client->destination.iabuf, ip->client->active->
760 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
761 ip->client->destination.len = 4;
763 ip->client->destination = iaddr_broadcast;
765 ip->client->first_sending = cur_time;
766 ip->client->interval = ip->client->config->initial_interval;
767 ip->client->state = S_RENEWING;
769 /* Send the first packet immediately. */
774 bootp(struct packet *packet)
776 struct iaddrlist *ap;
778 if (packet->raw->op != BOOTREPLY)
781 /* If there's a reject list, make sure this packet's sender isn't
783 for (ap = packet->interface->client->config->reject_list;
785 if (addr_eq(packet->client_addr, ap->addr)) {
786 note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
794 dhcp(struct packet *packet)
796 struct iaddrlist *ap;
797 void (*handler)(struct packet *);
800 switch (packet->packet_type) {
817 /* If there's a reject list, make sure this packet's sender isn't
819 for (ap = packet->interface->client->config->reject_list;
821 if (addr_eq(packet->client_addr, ap->addr)) {
822 note("%s from %s rejected.", type, piaddr(ap->addr));
830 dhcpoffer(struct packet *packet)
832 struct interface_info *ip = packet->interface;
833 struct client_lease *lease, *lp;
835 int arp_timeout_needed, stop_selecting;
836 char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
837 "DHCPOFFER" : "BOOTREPLY";
839 /* If we're not receptive to an offer right now, or if the offer
840 has an unrecognizable transaction id, then just drop it. */
841 if (ip->client->state != S_SELECTING ||
842 packet->interface->client->xid != packet->raw->xid ||
843 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
844 (memcmp(packet->interface->hw_address.haddr,
845 packet->raw->chaddr, packet->raw->hlen)))
848 note("%s from %s", name, piaddr(packet->client_addr));
851 /* If this lease doesn't supply the minimum required parameters,
853 for (i = 0; ip->client->config->required_options[i]; i++) {
854 if (!packet->options[ip->client->config->
855 required_options[i]].len) {
856 note("%s isn't satisfactory.", name);
861 /* If we've already seen this lease, don't record it again. */
862 for (lease = ip->client->offered_leases;
863 lease; lease = lease->next) {
864 if (lease->address.len == sizeof(packet->raw->yiaddr) &&
865 !memcmp(lease->address.iabuf,
866 &packet->raw->yiaddr, lease->address.len)) {
867 debug("%s already seen.", name);
872 lease = packet_to_lease(packet);
874 note("packet_to_lease failed.");
878 /* If this lease was acquired through a BOOTREPLY, record that
880 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
883 /* Record the medium under which this lease was offered. */
884 lease->medium = ip->client->medium;
886 /* Send out an ARP Request for the offered IP address. */
887 script_init("ARPSEND", lease->medium);
888 script_write_params("check_", lease);
889 /* If the script can't send an ARP request without waiting,
890 we'll be waiting when we do the ARPCHECK, so don't wait now. */
892 arp_timeout_needed = 0;
894 arp_timeout_needed = 2;
896 /* Figure out when we're supposed to stop selecting. */
898 ip->client->first_sending + ip->client->config->select_interval;
900 /* If this is the lease we asked for, put it at the head of the
901 list, and don't mess with the arp request timeout. */
902 if (lease->address.len == ip->client->requested_address.len &&
903 !memcmp(lease->address.iabuf,
904 ip->client->requested_address.iabuf,
905 ip->client->requested_address.len)) {
906 lease->next = ip->client->offered_leases;
907 ip->client->offered_leases = lease;
909 /* If we already have an offer, and arping for this
910 offer would take us past the selection timeout,
911 then don't extend the timeout - just hope for the
913 if (ip->client->offered_leases &&
914 (cur_time + arp_timeout_needed) > stop_selecting)
915 arp_timeout_needed = 0;
917 /* Put the lease at the end of the list. */
919 if (!ip->client->offered_leases)
920 ip->client->offered_leases = lease;
922 for (lp = ip->client->offered_leases; lp->next;
929 /* If we're supposed to stop selecting before we've had time
930 to wait for the ARPREPLY, add some delay to wait for
932 if (stop_selecting - cur_time < arp_timeout_needed)
933 stop_selecting = cur_time + arp_timeout_needed;
935 /* If the selecting interval has expired, go immediately to
936 state_selecting(). Otherwise, time out into
937 state_selecting at the select interval. */
938 if (stop_selecting <= 0)
941 add_timeout(stop_selecting, state_selecting, ip);
942 cancel_timeout(send_discover, ip);
946 /* Allocate a client_lease structure and initialize it from the parameters
947 in the specified packet. */
949 struct client_lease *
950 packet_to_lease(struct packet *packet)
952 struct client_lease *lease;
955 lease = malloc(sizeof(struct client_lease));
958 warning("dhcpoffer: no memory to record lease.");
962 memset(lease, 0, sizeof(*lease));
964 /* Copy the lease options. */
965 for (i = 0; i < 256; i++) {
966 if (packet->options[i].len) {
967 lease->options[i].data =
968 malloc(packet->options[i].len + 1);
969 if (!lease->options[i].data) {
970 warning("dhcpoffer: no memory for option %d", i);
971 free_client_lease(lease);
974 memcpy(lease->options[i].data,
975 packet->options[i].data,
976 packet->options[i].len);
977 lease->options[i].len =
978 packet->options[i].len;
979 lease->options[i].data[lease->options[i].len] =
982 if (!check_option(lease,i)) {
983 /* ignore a bogus lease offer */
984 warning("Invalid lease option - ignoring offer");
985 free_client_lease(lease);
991 lease->address.len = sizeof(packet->raw->yiaddr);
992 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
994 /* If the server name was filled out, copy it.
995 Do not attempt to validate the server name as a host name.
996 RFC 2131 merely states that sname is NUL-terminated (which do
997 do not assume) and that it is the server's host name. Since
998 the ISC client and server allow arbitrary characters, we do
1000 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1001 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
1002 packet->raw->sname[0]) {
1003 lease->server_name = malloc(DHCP_SNAME_LEN + 1);
1004 if (!lease->server_name) {
1005 warning("dhcpoffer: no memory for server name.");
1006 free_client_lease(lease);
1009 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
1010 lease->server_name[DHCP_SNAME_LEN]='\0';
1013 /* Ditto for the filename. */
1014 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1015 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
1016 packet->raw->file[0]) {
1017 /* Don't count on the NUL terminator. */
1018 lease->filename = malloc(DHCP_FILE_LEN + 1);
1019 if (!lease->filename) {
1020 warning("dhcpoffer: no memory for filename.");
1021 free_client_lease(lease);
1024 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
1025 lease->filename[DHCP_FILE_LEN]='\0';
1031 dhcpnak(struct packet *packet)
1033 struct interface_info *ip = packet->interface;
1035 /* If we're not receptive to an offer right now, or if the offer
1036 has an unrecognizable transaction id, then just drop it. */
1037 if (packet->interface->client->xid != packet->raw->xid ||
1038 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
1039 (memcmp(packet->interface->hw_address.haddr,
1040 packet->raw->chaddr, packet->raw->hlen)))
1043 if (ip->client->state != S_REBOOTING &&
1044 ip->client->state != S_REQUESTING &&
1045 ip->client->state != S_RENEWING &&
1046 ip->client->state != S_REBINDING)
1049 note("DHCPNAK from %s", piaddr(packet->client_addr));
1051 if (!ip->client->active) {
1052 note("DHCPNAK with no active lease.\n");
1056 free_client_lease(ip->client->active);
1057 ip->client->active = NULL;
1059 /* Stop sending DHCPREQUEST packets... */
1060 cancel_timeout(send_request, ip);
1062 ip->client->state = S_INIT;
1066 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1067 one after the right interval has expired. If we don't get an offer by
1068 the time we reach the panic interval, call the panic function. */
1071 send_discover(void *ipp)
1073 struct interface_info *ip = ipp;
1074 int interval, increase = 1;
1076 /* Figure out how long it's been since we started transmitting. */
1077 interval = cur_time - ip->client->first_sending;
1079 /* If we're past the panic timeout, call the script and tell it
1080 we haven't found anything for this interface yet. */
1081 if (interval > ip->client->config->timeout) {
1086 /* If we're selecting media, try the whole list before doing
1087 the exponential backoff, but if we've already received an
1088 offer, stop looping, because we obviously have it right. */
1089 if (!ip->client->offered_leases &&
1090 ip->client->config->media) {
1093 if (ip->client->medium) {
1094 ip->client->medium = ip->client->medium->next;
1097 if (!ip->client->medium) {
1099 error("No valid media types for %s!", ip->name);
1100 ip->client->medium = ip->client->config->media;
1104 note("Trying medium \"%s\" %d", ip->client->medium->string,
1106 script_init("MEDIUM", ip->client->medium);
1112 * If we're supposed to increase the interval, do so. If it's
1113 * currently zero (i.e., we haven't sent any packets yet), set
1114 * it to one; otherwise, add to it a random number between zero
1115 * and two times itself. On average, this means that it will
1116 * double with every transmission.
1119 if (!ip->client->interval)
1120 ip->client->interval =
1121 ip->client->config->initial_interval;
1123 ip->client->interval += (arc4random() >> 2) %
1124 (2 * ip->client->interval);
1127 /* Don't backoff past cutoff. */
1128 if (ip->client->interval >
1129 ip->client->config->backoff_cutoff)
1130 ip->client->interval =
1131 ((ip->client->config->backoff_cutoff / 2)
1132 + ((arc4random() >> 2) %
1133 ip->client->config->backoff_cutoff));
1134 } else if (!ip->client->interval)
1135 ip->client->interval =
1136 ip->client->config->initial_interval;
1138 /* If the backoff would take us to the panic timeout, just use that
1140 if (cur_time + ip->client->interval >
1141 ip->client->first_sending + ip->client->config->timeout)
1142 ip->client->interval =
1143 (ip->client->first_sending +
1144 ip->client->config->timeout) - cur_time + 1;
1146 /* Record the number of seconds since we started sending. */
1147 if (interval < 65536)
1148 ip->client->packet.secs = htons(interval);
1150 ip->client->packet.secs = htons(65535);
1151 ip->client->secs = ip->client->packet.secs;
1153 note("DHCPDISCOVER on %s to %s port %d interval %d",
1154 ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
1155 ntohs(sockaddr_broadcast.sin_port),
1156 (int)ip->client->interval);
1158 /* Send out a packet. */
1159 (void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
1160 inaddr_any, &sockaddr_broadcast, NULL);
1162 add_timeout(cur_time + ip->client->interval, send_discover, ip);
1166 * state_panic gets called if we haven't received any offers in a preset
1167 * amount of time. When this happens, we try to use existing leases
1168 * that haven't yet expired, and failing that, we call the client script
1169 * and hope it can do something.
1172 state_panic(void *ipp)
1174 struct interface_info *ip = ipp;
1175 struct client_lease *loop = ip->client->active;
1176 struct client_lease *lp;
1178 note("No DHCPOFFERS received.");
1180 /* We may not have an active lease, but we may have some
1181 predefined leases that we can try. */
1182 if (!ip->client->active && ip->client->leases)
1185 /* Run through the list of leases and see if one can be used. */
1186 while (ip->client->active) {
1187 if (ip->client->active->expiry > cur_time) {
1188 note("Trying recorded lease %s",
1189 piaddr(ip->client->active->address));
1190 /* Run the client script with the existing
1192 script_init("TIMEOUT",
1193 ip->client->active->medium);
1194 script_write_params("new_", ip->client->active);
1195 if (ip->client->alias)
1196 script_write_params("alias_",
1199 /* If the old lease is still good and doesn't
1200 yet need renewal, go into BOUND state and
1201 timeout at the renewal time. */
1204 ip->client->active->renewal) {
1205 ip->client->state = S_BOUND;
1206 note("bound: renewal in %d seconds.",
1207 (int)(ip->client->active->renewal -
1210 ip->client->active->renewal,
1213 ip->client->state = S_BOUND;
1214 note("bound: immediate renewal.");
1217 reinitialize_interfaces();
1223 /* If there are no other leases, give up. */
1224 if (!ip->client->leases) {
1225 ip->client->leases = ip->client->active;
1226 ip->client->active = NULL;
1231 /* Otherwise, put the active lease at the end of the
1232 lease list, and try another lease.. */
1233 for (lp = ip->client->leases; lp->next; lp = lp->next)
1235 lp->next = ip->client->active;
1237 lp->next->next = NULL;
1238 ip->client->active = ip->client->leases;
1239 ip->client->leases = ip->client->leases->next;
1241 /* If we already tried this lease, we've exhausted the
1242 set of leases, so we might as well give up for
1244 if (ip->client->active == loop)
1247 loop = ip->client->active;
1250 /* No leases were available, or what was available didn't work, so
1251 tell the shell script that we failed to allocate an address,
1252 and try again later. */
1253 note("No working leases in persistent database - sleeping.\n");
1254 script_init("FAIL", NULL);
1255 if (ip->client->alias)
1256 script_write_params("alias_", ip->client->alias);
1258 ip->client->state = S_INIT;
1259 add_timeout(cur_time + ip->client->config->retry_interval, state_init,
1265 send_request(void *ipp)
1267 struct interface_info *ip = ipp;
1268 struct sockaddr_in destination;
1269 struct in_addr from;
1272 /* Figure out how long it's been since we started transmitting. */
1273 interval = cur_time - ip->client->first_sending;
1275 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1276 past the reboot timeout, go to INIT and see if we can
1277 DISCOVER an address... */
1278 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1279 means either that we're on a network with no DHCP server,
1280 or that our server is down. In the latter case, assuming
1281 that there is a backup DHCP server, DHCPDISCOVER will get
1282 us a new address, but we could also have successfully
1283 reused our old address. In the former case, we're hosed
1284 anyway. This is not a win-prone situation. */
1285 if ((ip->client->state == S_REBOOTING ||
1286 ip->client->state == S_REQUESTING) &&
1287 interval > ip->client->config->reboot_timeout) {
1289 ip->client->state = S_INIT;
1290 cancel_timeout(send_request, ip);
1295 /* If we're in the reboot state, make sure the media is set up
1297 if (ip->client->state == S_REBOOTING &&
1298 !ip->client->medium &&
1299 ip->client->active->medium ) {
1300 script_init("MEDIUM", ip->client->active->medium);
1302 /* If the medium we chose won't fly, go to INIT state. */
1306 /* Record the medium. */
1307 ip->client->medium = ip->client->active->medium;
1310 /* If the lease has expired, relinquish the address and go back
1311 to the INIT state. */
1312 if (ip->client->state != S_REQUESTING &&
1313 cur_time > ip->client->active->expiry) {
1314 /* Run the client script with the new parameters. */
1315 script_init("EXPIRE", NULL);
1316 script_write_params("old_", ip->client->active);
1317 if (ip->client->alias)
1318 script_write_params("alias_", ip->client->alias);
1321 /* Now do a preinit on the interface so that we can
1322 discover a new address. */
1323 script_init("PREINIT", NULL);
1324 if (ip->client->alias)
1325 script_write_params("alias_", ip->client->alias);
1328 ip->client->state = S_INIT;
1333 /* Do the exponential backoff... */
1334 if (!ip->client->interval)
1335 ip->client->interval = ip->client->config->initial_interval;
1337 ip->client->interval += ((arc4random() >> 2) %
1338 (2 * ip->client->interval));
1340 /* Don't backoff past cutoff. */
1341 if (ip->client->interval >
1342 ip->client->config->backoff_cutoff)
1343 ip->client->interval =
1344 ((ip->client->config->backoff_cutoff / 2) +
1345 ((arc4random() >> 2) % ip->client->interval));
1347 /* If the backoff would take us to the expiry time, just set the
1348 timeout to the expiry time. */
1349 if (ip->client->state != S_REQUESTING &&
1350 cur_time + ip->client->interval >
1351 ip->client->active->expiry)
1352 ip->client->interval =
1353 ip->client->active->expiry - cur_time + 1;
1355 /* If the lease T2 time has elapsed, or if we're not yet bound,
1356 broadcast the DHCPREQUEST rather than unicasting. */
1357 memset(&destination, 0, sizeof(destination));
1358 if (ip->client->state == S_REQUESTING ||
1359 ip->client->state == S_REBOOTING ||
1360 cur_time > ip->client->active->rebind)
1361 destination.sin_addr.s_addr = INADDR_BROADCAST;
1363 memcpy(&destination.sin_addr.s_addr,
1364 ip->client->destination.iabuf,
1365 sizeof(destination.sin_addr.s_addr));
1366 destination.sin_port = htons(REMOTE_PORT);
1367 destination.sin_family = AF_INET;
1368 destination.sin_len = sizeof(destination);
1370 if (ip->client->state != S_REQUESTING)
1371 memcpy(&from, ip->client->active->address.iabuf,
1374 from.s_addr = INADDR_ANY;
1376 /* Record the number of seconds since we started sending. */
1377 if (ip->client->state == S_REQUESTING)
1378 ip->client->packet.secs = ip->client->secs;
1380 if (interval < 65536)
1381 ip->client->packet.secs = htons(interval);
1383 ip->client->packet.secs = htons(65535);
1386 note("DHCPREQUEST on %s to %s port %d", ip->name,
1387 inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
1389 /* Send out a packet. */
1390 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1391 from, &destination, NULL);
1393 add_timeout(cur_time + ip->client->interval, send_request, ip);
1397 send_decline(void *ipp)
1399 struct interface_info *ip = ipp;
1401 note("DHCPDECLINE on %s to %s port %d", ip->name,
1402 inet_ntoa(sockaddr_broadcast.sin_addr),
1403 ntohs(sockaddr_broadcast.sin_port));
1405 /* Send out a packet. */
1406 (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
1407 inaddr_any, &sockaddr_broadcast, NULL);
1411 make_discover(struct interface_info *ip, struct client_lease *lease)
1413 unsigned char discover = DHCPDISCOVER;
1414 struct tree_cache *options[256];
1415 struct tree_cache option_elements[256];
1418 memset(option_elements, 0, sizeof(option_elements));
1419 memset(options, 0, sizeof(options));
1420 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1422 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1423 i = DHO_DHCP_MESSAGE_TYPE;
1424 options[i] = &option_elements[i];
1425 options[i]->value = &discover;
1426 options[i]->len = sizeof(discover);
1427 options[i]->buf_size = sizeof(discover);
1428 options[i]->timeout = 0xFFFFFFFF;
1430 /* Request the options we want */
1431 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1432 options[i] = &option_elements[i];
1433 options[i]->value = ip->client->config->requested_options;
1434 options[i]->len = ip->client->config->requested_option_count;
1435 options[i]->buf_size =
1436 ip->client->config->requested_option_count;
1437 options[i]->timeout = 0xFFFFFFFF;
1439 /* If we had an address, try to get it again. */
1441 ip->client->requested_address = lease->address;
1442 i = DHO_DHCP_REQUESTED_ADDRESS;
1443 options[i] = &option_elements[i];
1444 options[i]->value = lease->address.iabuf;
1445 options[i]->len = lease->address.len;
1446 options[i]->buf_size = lease->address.len;
1447 options[i]->timeout = 0xFFFFFFFF;
1449 ip->client->requested_address.len = 0;
1451 /* Send any options requested in the config file. */
1452 for (i = 0; i < 256; i++)
1454 ip->client->config->send_options[i].data) {
1455 options[i] = &option_elements[i];
1457 ip->client->config->send_options[i].data;
1459 ip->client->config->send_options[i].len;
1460 options[i]->buf_size =
1461 ip->client->config->send_options[i].len;
1462 options[i]->timeout = 0xFFFFFFFF;
1465 /* Set up the option buffer... */
1466 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1467 options, 0, 0, 0, NULL, 0);
1468 if (ip->client->packet_length < BOOTP_MIN_LEN)
1469 ip->client->packet_length = BOOTP_MIN_LEN;
1471 ip->client->packet.op = BOOTREQUEST;
1472 ip->client->packet.htype = ip->hw_address.htype;
1473 ip->client->packet.hlen = ip->hw_address.hlen;
1474 ip->client->packet.hops = 0;
1475 ip->client->packet.xid = arc4random();
1476 ip->client->packet.secs = 0; /* filled in by send_discover. */
1477 ip->client->packet.flags = 0;
1479 memset(&(ip->client->packet.ciaddr),
1480 0, sizeof(ip->client->packet.ciaddr));
1481 memset(&(ip->client->packet.yiaddr),
1482 0, sizeof(ip->client->packet.yiaddr));
1483 memset(&(ip->client->packet.siaddr),
1484 0, sizeof(ip->client->packet.siaddr));
1485 memset(&(ip->client->packet.giaddr),
1486 0, sizeof(ip->client->packet.giaddr));
1487 memcpy(ip->client->packet.chaddr,
1488 ip->hw_address.haddr, ip->hw_address.hlen);
1493 make_request(struct interface_info *ip, struct client_lease * lease)
1495 unsigned char request = DHCPREQUEST;
1496 struct tree_cache *options[256];
1497 struct tree_cache option_elements[256];
1500 memset(options, 0, sizeof(options));
1501 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1503 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1504 i = DHO_DHCP_MESSAGE_TYPE;
1505 options[i] = &option_elements[i];
1506 options[i]->value = &request;
1507 options[i]->len = sizeof(request);
1508 options[i]->buf_size = sizeof(request);
1509 options[i]->timeout = 0xFFFFFFFF;
1511 /* Request the options we want */
1512 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1513 options[i] = &option_elements[i];
1514 options[i]->value = ip->client->config->requested_options;
1515 options[i]->len = ip->client->config->requested_option_count;
1516 options[i]->buf_size =
1517 ip->client->config->requested_option_count;
1518 options[i]->timeout = 0xFFFFFFFF;
1520 /* If we are requesting an address that hasn't yet been assigned
1521 to us, use the DHCP Requested Address option. */
1522 if (ip->client->state == S_REQUESTING) {
1523 /* Send back the server identifier... */
1524 i = DHO_DHCP_SERVER_IDENTIFIER;
1525 options[i] = &option_elements[i];
1526 options[i]->value = lease->options[i].data;
1527 options[i]->len = lease->options[i].len;
1528 options[i]->buf_size = lease->options[i].len;
1529 options[i]->timeout = 0xFFFFFFFF;
1531 if (ip->client->state == S_REQUESTING ||
1532 ip->client->state == S_REBOOTING) {
1533 ip->client->requested_address = lease->address;
1534 i = DHO_DHCP_REQUESTED_ADDRESS;
1535 options[i] = &option_elements[i];
1536 options[i]->value = lease->address.iabuf;
1537 options[i]->len = lease->address.len;
1538 options[i]->buf_size = lease->address.len;
1539 options[i]->timeout = 0xFFFFFFFF;
1541 ip->client->requested_address.len = 0;
1543 /* Send any options requested in the config file. */
1544 for (i = 0; i < 256; i++)
1546 ip->client->config->send_options[i].data) {
1547 options[i] = &option_elements[i];
1549 ip->client->config->send_options[i].data;
1551 ip->client->config->send_options[i].len;
1552 options[i]->buf_size =
1553 ip->client->config->send_options[i].len;
1554 options[i]->timeout = 0xFFFFFFFF;
1557 /* Set up the option buffer... */
1558 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1559 options, 0, 0, 0, NULL, 0);
1560 if (ip->client->packet_length < BOOTP_MIN_LEN)
1561 ip->client->packet_length = BOOTP_MIN_LEN;
1563 ip->client->packet.op = BOOTREQUEST;
1564 ip->client->packet.htype = ip->hw_address.htype;
1565 ip->client->packet.hlen = ip->hw_address.hlen;
1566 ip->client->packet.hops = 0;
1567 ip->client->packet.xid = ip->client->xid;
1568 ip->client->packet.secs = 0; /* Filled in by send_request. */
1570 /* If we own the address we're requesting, put it in ciaddr;
1571 otherwise set ciaddr to zero. */
1572 if (ip->client->state == S_BOUND ||
1573 ip->client->state == S_RENEWING ||
1574 ip->client->state == S_REBINDING) {
1575 memcpy(&ip->client->packet.ciaddr,
1576 lease->address.iabuf, lease->address.len);
1577 ip->client->packet.flags = 0;
1579 memset(&ip->client->packet.ciaddr, 0,
1580 sizeof(ip->client->packet.ciaddr));
1581 ip->client->packet.flags = 0;
1584 memset(&ip->client->packet.yiaddr, 0,
1585 sizeof(ip->client->packet.yiaddr));
1586 memset(&ip->client->packet.siaddr, 0,
1587 sizeof(ip->client->packet.siaddr));
1588 memset(&ip->client->packet.giaddr, 0,
1589 sizeof(ip->client->packet.giaddr));
1590 memcpy(ip->client->packet.chaddr,
1591 ip->hw_address.haddr, ip->hw_address.hlen);
1595 make_decline(struct interface_info *ip, struct client_lease *lease)
1597 struct tree_cache *options[256], message_type_tree;
1598 struct tree_cache requested_address_tree;
1599 struct tree_cache server_id_tree, client_id_tree;
1600 unsigned char decline = DHCPDECLINE;
1603 memset(options, 0, sizeof(options));
1604 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1606 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1607 i = DHO_DHCP_MESSAGE_TYPE;
1608 options[i] = &message_type_tree;
1609 options[i]->value = &decline;
1610 options[i]->len = sizeof(decline);
1611 options[i]->buf_size = sizeof(decline);
1612 options[i]->timeout = 0xFFFFFFFF;
1614 /* Send back the server identifier... */
1615 i = DHO_DHCP_SERVER_IDENTIFIER;
1616 options[i] = &server_id_tree;
1617 options[i]->value = lease->options[i].data;
1618 options[i]->len = lease->options[i].len;
1619 options[i]->buf_size = lease->options[i].len;
1620 options[i]->timeout = 0xFFFFFFFF;
1622 /* Send back the address we're declining. */
1623 i = DHO_DHCP_REQUESTED_ADDRESS;
1624 options[i] = &requested_address_tree;
1625 options[i]->value = lease->address.iabuf;
1626 options[i]->len = lease->address.len;
1627 options[i]->buf_size = lease->address.len;
1628 options[i]->timeout = 0xFFFFFFFF;
1630 /* Send the uid if the user supplied one. */
1631 i = DHO_DHCP_CLIENT_IDENTIFIER;
1632 if (ip->client->config->send_options[i].len) {
1633 options[i] = &client_id_tree;
1634 options[i]->value = ip->client->config->send_options[i].data;
1635 options[i]->len = ip->client->config->send_options[i].len;
1636 options[i]->buf_size = ip->client->config->send_options[i].len;
1637 options[i]->timeout = 0xFFFFFFFF;
1641 /* Set up the option buffer... */
1642 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1643 options, 0, 0, 0, NULL, 0);
1644 if (ip->client->packet_length < BOOTP_MIN_LEN)
1645 ip->client->packet_length = BOOTP_MIN_LEN;
1647 ip->client->packet.op = BOOTREQUEST;
1648 ip->client->packet.htype = ip->hw_address.htype;
1649 ip->client->packet.hlen = ip->hw_address.hlen;
1650 ip->client->packet.hops = 0;
1651 ip->client->packet.xid = ip->client->xid;
1652 ip->client->packet.secs = 0; /* Filled in by send_request. */
1653 ip->client->packet.flags = 0;
1655 /* ciaddr must always be zero. */
1656 memset(&ip->client->packet.ciaddr, 0,
1657 sizeof(ip->client->packet.ciaddr));
1658 memset(&ip->client->packet.yiaddr, 0,
1659 sizeof(ip->client->packet.yiaddr));
1660 memset(&ip->client->packet.siaddr, 0,
1661 sizeof(ip->client->packet.siaddr));
1662 memset(&ip->client->packet.giaddr, 0,
1663 sizeof(ip->client->packet.giaddr));
1664 memcpy(ip->client->packet.chaddr,
1665 ip->hw_address.haddr, ip->hw_address.hlen);
1669 free_client_lease(struct client_lease *lease)
1673 if (lease->server_name)
1674 free(lease->server_name);
1675 if (lease->filename)
1676 free(lease->filename);
1677 for (i = 0; i < 256; i++) {
1678 if (lease->options[i].len)
1679 free(lease->options[i].data);
1687 rewrite_client_leases(void)
1689 struct client_lease *lp;
1692 leaseFile = fopen(path_dhclient_db, "w");
1694 error("can't create %s: %m", path_dhclient_db);
1700 for (lp = ifi->client->leases; lp; lp = lp->next)
1701 write_client_lease(ifi, lp, 1);
1702 if (ifi->client->active)
1703 write_client_lease(ifi, ifi->client->active, 1);
1706 ftruncate(fileno(leaseFile), ftello(leaseFile));
1707 fsync(fileno(leaseFile));
1711 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1714 static int leases_written;
1719 if (leases_written++ > 20) {
1720 rewrite_client_leases();
1725 /* If the lease came from the config file, we don't need to stash
1726 a copy in the lease database. */
1727 if (lease->is_static)
1730 if (!leaseFile) { /* XXX */
1731 leaseFile = fopen(path_dhclient_db, "w");
1733 error("can't create %s: %m", path_dhclient_db);
1736 fprintf(leaseFile, "lease {\n");
1737 if (lease->is_bootp)
1738 fprintf(leaseFile, " bootp;\n");
1739 fprintf(leaseFile, " interface \"%s\";\n", ip->name);
1740 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
1741 if (lease->filename)
1742 fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
1743 if (lease->server_name)
1744 fprintf(leaseFile, " server-name \"%s\";\n",
1745 lease->server_name);
1747 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string);
1748 for (i = 0; i < 256; i++)
1749 if (lease->options[i].len)
1750 fprintf(leaseFile, " option %s %s;\n",
1751 dhcp_options[i].name,
1752 pretty_print_option(i, lease->options[i].data,
1753 lease->options[i].len, 1, 1));
1755 t = gmtime(&lease->renewal);
1756 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1757 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1758 t->tm_hour, t->tm_min, t->tm_sec);
1759 t = gmtime(&lease->rebind);
1760 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1761 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1762 t->tm_hour, t->tm_min, t->tm_sec);
1763 t = gmtime(&lease->expiry);
1764 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1765 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1766 t->tm_hour, t->tm_min, t->tm_sec);
1767 fprintf(leaseFile, "}\n");
1772 script_init(char *reason, struct string_list *medium)
1774 size_t len, mediumlen = 0;
1775 struct imsg_hdr hdr;
1779 if (medium != NULL && medium->string != NULL)
1780 mediumlen = strlen(medium->string);
1782 hdr.code = IMSG_SCRIPT_INIT;
1783 hdr.len = sizeof(struct imsg_hdr) +
1784 sizeof(size_t) + mediumlen +
1785 sizeof(size_t) + strlen(reason);
1787 if ((buf = buf_open(hdr.len)) == NULL)
1788 error("buf_open: %m");
1791 errs += buf_add(buf, &hdr, sizeof(hdr));
1792 errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
1794 errs += buf_add(buf, medium->string, mediumlen);
1795 len = strlen(reason);
1796 errs += buf_add(buf, &len, sizeof(len));
1797 errs += buf_add(buf, reason, len);
1800 error("buf_add: %m");
1802 if (buf_close(privfd, buf) == -1)
1803 error("buf_close: %m");
1807 priv_script_init(char *reason, char *medium)
1809 struct interface_info *ip = ifi;
1812 ip->client->scriptEnvsize = 100;
1813 if (ip->client->scriptEnv == NULL)
1814 ip->client->scriptEnv =
1815 malloc(ip->client->scriptEnvsize * sizeof(char *));
1816 if (ip->client->scriptEnv == NULL)
1817 error("script_init: no memory for environment");
1819 ip->client->scriptEnv[0] = strdup(CLIENT_PATH);
1820 if (ip->client->scriptEnv[0] == NULL)
1821 error("script_init: no memory for environment");
1823 ip->client->scriptEnv[1] = NULL;
1825 script_set_env(ip->client, "", "interface", ip->name);
1828 script_set_env(ip->client, "", "medium", medium);
1830 script_set_env(ip->client, "", "reason", reason);
1835 priv_script_write_params(char *prefix, struct client_lease *lease)
1837 struct interface_info *ip = ifi;
1838 u_int8_t dbuf[1500], *dp = NULL;
1842 script_set_env(ip->client, prefix, "ip_address",
1843 piaddr(lease->address));
1845 if (ip->client->config->default_actions[DHO_SUBNET_MASK] ==
1847 dp = ip->client->config->defaults[DHO_SUBNET_MASK].data;
1848 len = ip->client->config->defaults[DHO_SUBNET_MASK].len;
1850 dp = lease->options[DHO_SUBNET_MASK].data;
1851 len = lease->options[DHO_SUBNET_MASK].len;
1853 if (len && (len < sizeof(lease->address.iabuf))) {
1854 struct iaddr netmask, subnet, broadcast;
1856 memcpy(netmask.iabuf, dp, len);
1858 subnet = subnet_number(lease->address, netmask);
1860 script_set_env(ip->client, prefix, "network_number",
1862 if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
1863 broadcast = broadcast_addr(subnet, netmask);
1865 script_set_env(ip->client, prefix,
1866 "broadcast_address",
1872 if (lease->filename)
1873 script_set_env(ip->client, prefix, "filename", lease->filename);
1874 if (lease->server_name)
1875 script_set_env(ip->client, prefix, "server_name",
1876 lease->server_name);
1877 for (i = 0; i < 256; i++) {
1880 if (ip->client->config->defaults[i].len) {
1881 if (lease->options[i].len) {
1883 ip->client->config->default_actions[i]) {
1884 case ACTION_DEFAULT:
1885 dp = lease->options[i].data;
1886 len = lease->options[i].len;
1888 case ACTION_SUPERSEDE:
1891 config->defaults[i].data;
1893 config->defaults[i].len;
1895 case ACTION_PREPEND:
1897 config->defaults[i].len +
1898 lease->options[i].len;
1899 if (len > sizeof(dbuf)) {
1900 warning("no space to %s %s",
1902 dhcp_options[i].name);
1908 config->defaults[i].data,
1910 config->defaults[i].len);
1911 memcpy(dp + ip->client->
1912 config->defaults[i].len,
1913 lease->options[i].data,
1914 lease->options[i].len);
1919 config->defaults[i].len +
1920 lease->options[i].len;
1921 if (len > sizeof(dbuf)) {
1922 warning("no space to %s %s",
1924 dhcp_options[i].name);
1929 lease->options[i].data,
1930 lease->options[i].len);
1931 memcpy(dp + lease->options[i].len,
1933 config->defaults[i].data,
1935 config->defaults[i].len);
1940 config->defaults[i].data;
1942 config->defaults[i].len;
1944 } else if (lease->options[i].len) {
1945 len = lease->options[i].len;
1946 dp = lease->options[i].data;
1953 if (dhcp_option_ev_name(name, sizeof(name),
1955 script_set_env(ip->client, prefix, name,
1956 pretty_print_option(i, dp, len, 0, 0));
1959 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
1960 script_set_env(ip->client, prefix, "expiry", tbuf);
1964 script_write_params(char *prefix, struct client_lease *lease)
1966 size_t fn_len = 0, sn_len = 0, pr_len = 0;
1967 struct imsg_hdr hdr;
1971 if (lease->filename != NULL)
1972 fn_len = strlen(lease->filename);
1973 if (lease->server_name != NULL)
1974 sn_len = strlen(lease->server_name);
1976 pr_len = strlen(prefix);
1978 hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
1979 hdr.len = sizeof(hdr) + sizeof(struct client_lease) +
1980 sizeof(size_t) + fn_len + sizeof(size_t) + sn_len +
1981 sizeof(size_t) + pr_len;
1983 for (i = 0; i < 256; i++)
1984 hdr.len += sizeof(int) + lease->options[i].len;
1986 scripttime = time(NULL);
1988 if ((buf = buf_open(hdr.len)) == NULL)
1989 error("buf_open: %m");
1992 errs += buf_add(buf, &hdr, sizeof(hdr));
1993 errs += buf_add(buf, lease, sizeof(struct client_lease));
1994 errs += buf_add(buf, &fn_len, sizeof(fn_len));
1995 errs += buf_add(buf, lease->filename, fn_len);
1996 errs += buf_add(buf, &sn_len, sizeof(sn_len));
1997 errs += buf_add(buf, lease->server_name, sn_len);
1998 errs += buf_add(buf, &pr_len, sizeof(pr_len));
1999 errs += buf_add(buf, prefix, pr_len);
2001 for (i = 0; i < 256; i++) {
2002 errs += buf_add(buf, &lease->options[i].len,
2003 sizeof(lease->options[i].len));
2004 errs += buf_add(buf, lease->options[i].data,
2005 lease->options[i].len);
2009 error("buf_add: %m");
2011 if (buf_close(privfd, buf) == -1)
2012 error("buf_close: %m");
2018 struct imsg_hdr hdr;
2022 scripttime = time(NULL);
2024 hdr.code = IMSG_SCRIPT_GO;
2025 hdr.len = sizeof(struct imsg_hdr);
2027 if ((buf = buf_open(hdr.len)) == NULL)
2028 error("buf_open: %m");
2030 if (buf_add(buf, &hdr, sizeof(hdr)))
2031 error("buf_add: %m");
2033 if (buf_close(privfd, buf) == -1)
2034 error("buf_close: %m");
2036 bzero(&hdr, sizeof(hdr));
2037 buf_read(privfd, &hdr, sizeof(hdr));
2038 if (hdr.code != IMSG_SCRIPT_GO_RET)
2039 error("unexpected msg type %u", hdr.code);
2040 if (hdr.len != sizeof(hdr) + sizeof(int))
2041 error("received corrupted message");
2042 buf_read(privfd, &ret, sizeof(ret));
2048 priv_script_go(void)
2050 char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI";
2051 static char client_path[] = CLIENT_PATH;
2052 struct interface_info *ip = ifi;
2053 int pid, wpid, wstatus;
2055 scripttime = time(NULL);
2058 scriptName = ip->client->config->script_name;
2059 envp = ip->client->scriptEnv;
2061 scriptName = top_level_config.script_name;
2063 epp[1] = client_path;
2068 argv[0] = scriptName;
2077 wpid = wait(&wstatus);
2078 } while (wpid != pid && wpid > 0);
2084 execve(scriptName, argv, envp);
2085 error("execve (%s, ...): %m", scriptName);
2089 script_flush_env(ip->client);
2091 return (wstatus & 0xff);
2095 script_set_env(struct client_state *client, const char *prefix,
2096 const char *name, const char *value)
2100 namelen = strlen(name);
2102 for (i = 0; client->scriptEnv[i]; i++)
2103 if (strncmp(client->scriptEnv[i], name, namelen) == 0 &&
2104 client->scriptEnv[i][namelen] == '=')
2107 if (client->scriptEnv[i])
2108 /* Reuse the slot. */
2109 free(client->scriptEnv[i]);
2111 /* New variable. Expand if necessary. */
2112 if (i >= client->scriptEnvsize - 1) {
2113 char **newscriptEnv;
2114 int newscriptEnvsize = client->scriptEnvsize + 50;
2116 newscriptEnv = realloc(client->scriptEnv,
2118 if (newscriptEnv == NULL) {
2119 free(client->scriptEnv);
2120 client->scriptEnv = NULL;
2121 client->scriptEnvsize = 0;
2122 error("script_set_env: no memory for variable");
2124 client->scriptEnv = newscriptEnv;
2125 client->scriptEnvsize = newscriptEnvsize;
2127 /* need to set the NULL pointer at end of array beyond
2129 client->scriptEnv[i + 1] = NULL;
2131 /* Allocate space and format the variable in the appropriate slot. */
2132 client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 +
2134 if (client->scriptEnv[i] == NULL)
2135 error("script_set_env: no memory for variable assignment");
2137 /* No `` or $() command substitution allowed in environment values! */
2138 for (j=0; j < strlen(value); j++)
2142 error("illegal character (%c) in value '%s'", value[j],
2146 snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
2147 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
2151 script_flush_env(struct client_state *client)
2155 for (i = 0; client->scriptEnv[i]; i++) {
2156 free(client->scriptEnv[i]);
2157 client->scriptEnv[i] = NULL;
2159 client->scriptEnvsize = 0;
2163 dhcp_option_ev_name(char *buf, size_t buflen, struct option *option)
2167 for (i = 0; option->name[i]; i++) {
2168 if (i + 1 == buflen)
2170 if (option->name[i] == '-')
2173 buf[i] = option->name[i];
2183 static int state = 0;
2185 if (no_daemon || state)
2190 /* Stop logging to stderr... */
2193 if (daemon(1, 0) == -1)
2196 /* we are chrooted, daemon(3) fails to open /dev/null */
2198 dup2(nullfd, STDIN_FILENO);
2199 dup2(nullfd, STDOUT_FILENO);
2200 dup2(nullfd, STDERR_FILENO);
2207 check_option(struct client_lease *l, int option)
2212 /* we use this, since this is what gets passed to dhclient-script */
2214 opbuf = pretty_print_option(option, l->options[option].data,
2215 l->options[option].len, 0, 0);
2217 sbuf = option_as_string(option, l->options[option].data,
2218 l->options[option].len);
2221 case DHO_SUBNET_MASK:
2222 case DHO_TIME_SERVERS:
2223 case DHO_NAME_SERVERS:
2225 case DHO_DOMAIN_NAME_SERVERS:
2226 case DHO_LOG_SERVERS:
2227 case DHO_COOKIE_SERVERS:
2228 case DHO_LPR_SERVERS:
2229 case DHO_IMPRESS_SERVERS:
2230 case DHO_RESOURCE_LOCATION_SERVERS:
2231 case DHO_SWAP_SERVER:
2232 case DHO_BROADCAST_ADDRESS:
2233 case DHO_NIS_SERVERS:
2234 case DHO_NTP_SERVERS:
2235 case DHO_NETBIOS_NAME_SERVERS:
2236 case DHO_NETBIOS_DD_SERVER:
2237 case DHO_FONT_SERVERS:
2238 case DHO_DHCP_SERVER_IDENTIFIER:
2239 case DHO_SMTP_SERVER:
2240 case DHO_POP_SERVER:
2241 case DHO_NNTP_SERVER:
2242 case DHO_WWW_SERVER:
2243 case DHO_FINGER_SERVER:
2244 case DHO_IRC_SERVER:
2245 if (!ipv4addrs(opbuf)) {
2246 warning("Invalid IP address in option: %s", opbuf);
2251 case DHO_NIS_DOMAIN:
2252 if (!res_hnok(sbuf)) {
2253 warning("Bogus Host Name option %d: %s (%s)", option,
2255 l->options[option].len = 0;
2256 free(l->options[option].data);
2260 case DHO_DOMAIN_NAME:
2261 if (!res_hnok(sbuf)) {
2262 if (!check_search(sbuf)) {
2263 warning("Bogus domain search list %d: %s (%s)",
2264 option, sbuf, opbuf);
2265 l->options[option].len = 0;
2266 free(l->options[option].data);
2271 case DHO_TIME_OFFSET:
2273 case DHO_MERIT_DUMP:
2275 case DHO_EXTENSIONS_PATH:
2276 case DHO_IP_FORWARDING:
2277 case DHO_NON_LOCAL_SOURCE_ROUTING:
2278 case DHO_POLICY_FILTER:
2279 case DHO_MAX_DGRAM_REASSEMBLY:
2280 case DHO_DEFAULT_IP_TTL:
2281 case DHO_PATH_MTU_AGING_TIMEOUT:
2282 case DHO_PATH_MTU_PLATEAU_TABLE:
2283 case DHO_INTERFACE_MTU:
2284 case DHO_ALL_SUBNETS_LOCAL:
2285 case DHO_PERFORM_MASK_DISCOVERY:
2286 case DHO_MASK_SUPPLIER:
2287 case DHO_ROUTER_DISCOVERY:
2288 case DHO_ROUTER_SOLICITATION_ADDRESS:
2289 case DHO_STATIC_ROUTES:
2290 case DHO_TRAILER_ENCAPSULATION:
2291 case DHO_ARP_CACHE_TIMEOUT:
2292 case DHO_IEEE802_3_ENCAPSULATION:
2293 case DHO_DEFAULT_TCP_TTL:
2294 case DHO_TCP_KEEPALIVE_INTERVAL:
2295 case DHO_TCP_KEEPALIVE_GARBAGE:
2296 case DHO_VENDOR_ENCAPSULATED_OPTIONS:
2297 case DHO_NETBIOS_NODE_TYPE:
2298 case DHO_NETBIOS_SCOPE:
2299 case DHO_X_DISPLAY_MANAGER:
2300 case DHO_DHCP_REQUESTED_ADDRESS:
2301 case DHO_DHCP_LEASE_TIME:
2302 case DHO_DHCP_OPTION_OVERLOAD:
2303 case DHO_DHCP_MESSAGE_TYPE:
2304 case DHO_DHCP_PARAMETER_REQUEST_LIST:
2305 case DHO_DHCP_MESSAGE:
2306 case DHO_DHCP_MAX_MESSAGE_SIZE:
2307 case DHO_DHCP_RENEWAL_TIME:
2308 case DHO_DHCP_REBINDING_TIME:
2309 case DHO_DHCP_CLASS_IDENTIFIER:
2310 case DHO_DHCP_CLIENT_IDENTIFIER:
2311 case DHO_DHCP_USER_CLASS_ID:
2315 warning("unknown dhcp option value 0x%x", option);
2316 return (unknown_ok);
2321 res_hnok(const char *dn)
2323 int pch = PERIOD, ch = *dn++;
2325 while (ch != '\0') {
2328 if (periodchar(ch)) {
2330 } else if (periodchar(pch)) {
2331 if (!borderchar(ch))
2333 } else if (periodchar(nch) || nch == '\0') {
2334 if (!borderchar(ch))
2337 if (!middlechar(ch))
2346 check_search(const char *srch)
2348 int pch = PERIOD, ch = *srch++;
2351 /* 256 char limit re resolv.conf(5) */
2352 if (strlen(srch) > 256)
2355 while (whitechar(ch))
2358 while (ch != '\0') {
2361 if (periodchar(ch) || whitechar(ch)) {
2363 } else if (periodchar(pch)) {
2364 if (!borderchar(ch))
2366 } else if (periodchar(nch) || nch == '\0') {
2367 if (!borderchar(ch))
2370 if (!middlechar(ch))
2373 if (!whitechar(ch)) {
2376 while (whitechar(nch)) {
2385 /* 6 domain limit re resolv.conf(5) */
2391 /* Does buf consist only of dotted decimal ipv4 addrs?
2392 * return how many if so,
2393 * otherwise, return 0
2396 ipv4addrs(char * buf)
2401 while (inet_aton(buf, &jnk) == 1){
2403 while (periodchar(*buf) || digitchar(*buf))
2415 option_as_string(unsigned int code, unsigned char *data, int len)
2417 static char optbuf[32768]; /* XXX */
2419 int opleft = sizeof(optbuf);
2420 unsigned char *dp = data;
2423 error("option_as_string: bad code %d", code);
2425 for (; dp < data + len; dp++) {
2426 if (!isascii(*dp) || !isprint(*dp)) {
2427 if (dp + 1 != data + len || *dp != 0) {
2428 snprintf(op, opleft, "\\%03o", *dp);
2432 } else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
2433 *dp == '`' || *dp == '\\') {
2447 warning("dhcp option too large");
2452 fork_privchld(int fd, int fd2)
2454 struct pollfd pfd[1];
2459 error("cannot fork");
2466 setproctitle("%s [priv]", ifi->name);
2468 dup2(nullfd, STDIN_FILENO);
2469 dup2(nullfd, STDOUT_FILENO);
2470 dup2(nullfd, STDERR_FILENO);
2476 pfd[0].events = POLLIN;
2477 if ((nfds = poll(pfd, 1, INFTIM)) == -1)
2479 error("poll error");
2481 if (nfds == 0 || !(pfd[0].revents & POLLIN))