1 /* $OpenBSD: dhclient.c,v 1.63 2005/02/06 17:10:13 krw Exp $ */
4 * SPDX-License-Identifier: BSD-3-Clause
6 * Copyright 2004 Henning Brauer <henning@openbsd.org>
7 * Copyright (c) 1995, 1996, 1997, 1998, 1999
8 * The Internet Software Consortium. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of The Internet Software Consortium nor the names
20 * of its contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
24 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
31 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * This software has been written for the Internet Software Consortium
38 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
39 * Enterprises. To learn more about the Internet Software Consortium,
40 * see ``http://www.vix.com/isc''. To learn more about Vixie
41 * Enterprises, see ``http://www.vix.com''.
43 * This client was substantially modified and enhanced by Elliot Poger
44 * for use on Linux while he was working on the MosquitoNet project at
47 * The current version owes much to Elliot's Linux enhancements, but
48 * was substantially reorganized and partially rewritten by Ted Lemon
49 * so as to use the same networking framework that the Internet Software
50 * Consortium DHCP server uses. Much system-specific configuration code
51 * was moved into a shell script so that as support for more operating
52 * systems is added, it will not be necessary to port and maintain
53 * system-specific configuration code to these operating systems - instead,
54 * the shell script can invoke the native tools to accomplish the same
58 #include <sys/cdefs.h>
59 __FBSDID("$FreeBSD$");
64 #include <sys/capsicum.h>
65 #include <sys/endian.h>
67 #include <capsicum_helpers.h>
70 #include <net80211/ieee80211_freebsd.h>
73 #ifndef _PATH_VAREMPTY
74 #define _PATH_VAREMPTY "/var/empty"
78 #define hyphenchar(c) ((c) == 0x2d)
79 #define bslashchar(c) ((c) == 0x5c)
80 #define periodchar(c) ((c) == PERIOD)
81 #define asterchar(c) ((c) == 0x2a)
82 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
83 ((c) >= 0x61 && (c) <= 0x7a))
84 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
85 #define whitechar(c) ((c) == ' ' || (c) == '\t')
87 #define borderchar(c) (alphachar(c) || digitchar(c))
88 #define middlechar(c) (borderchar(c) || hyphenchar(c))
89 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
91 #define CLIENT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
93 cap_channel_t *capsyslog;
96 static time_t default_lease_time = 43200; /* 12 hours... */
98 const char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
99 char *path_dhclient_db = NULL;
103 static int nullfd = -1;
105 static char hostname[_POSIX_HOST_NAME_MAX + 1];
107 static struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
108 static struct in_addr inaddr_any, inaddr_broadcast;
110 static char *path_dhclient_pidfile;
111 struct pidfh *pidfile;
114 * ASSERT_STATE() does nothing now; it used to be
115 * assert (state_is == state_shouldbe).
117 #define ASSERT_STATE(state_is, state_shouldbe) {}
120 * We need to check that the expiry, renewal and rebind times are not beyond
121 * the end of time (~2038 when a 32-bit time_t is being used).
123 #define TIME_MAX ((((time_t) 1 << (sizeof(time_t) * CHAR_BIT - 2)) - 1) * 2 + 1)
126 static int no_daemon;
127 static int unknown_ok = 1;
130 struct interface_info *ifi;
132 int findproto(char *, int);
133 struct sockaddr *get_ifa(char *, int);
134 void routehandler(struct protocol *);
136 int check_option(struct client_lease *l, int option);
137 int check_classless_option(unsigned char *data, int len);
138 int ipv4addrs(const char * buf);
139 int res_hnok(const char *dn);
140 int check_search(const char *srch);
141 const char *option_as_string(unsigned int code, unsigned char *data, int len);
142 int fork_privchld(int, int);
145 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
146 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
148 /* Minimum MTU is 68 as per RFC791, p. 24 */
151 static time_t scripttime;
154 findproto(char *cp, int n)
161 for (i = 1; i; i <<= 1) {
163 sa = (struct sockaddr *)cp;
169 if (sa->sa_family == AF_INET)
171 if (sa->sa_family == AF_INET6)
184 get_ifa(char *cp, int n)
191 for (i = 1; i; i <<= 1)
193 sa = (struct sockaddr *)cp;
202 static struct iaddr defaddr = { .len = 4 };
203 static uint8_t curbssid[6];
208 struct interface_info *_ifi = arg;
211 * Clear existing state.
213 if (_ifi->client->active != NULL) {
214 script_init("EXPIRE", NULL);
215 script_write_params("old_",
216 _ifi->client->active);
217 if (_ifi->client->alias)
218 script_write_params("alias_",
219 _ifi->client->alias);
222 _ifi->client->state = S_INIT;
226 routehandler(struct protocol *p __unused)
228 char msg[2048], *addr;
229 struct rt_msghdr *rtm;
230 struct if_msghdr *ifm;
231 struct ifa_msghdr *ifam;
232 struct if_announcemsghdr *ifan;
233 struct ieee80211_join_event *jev;
234 struct client_lease *l;
235 time_t t = time(NULL);
236 struct sockaddr_in *sa;
241 n = read(routefd, &msg, sizeof(msg));
242 rtm = (struct rt_msghdr *)msg;
243 if (n < (ssize_t)sizeof(rtm->rtm_msglen) ||
244 n < (ssize_t)rtm->rtm_msglen ||
245 rtm->rtm_version != RTM_VERSION)
248 switch (rtm->rtm_type) {
251 ifam = (struct ifa_msghdr *)rtm;
253 if (ifam->ifam_index != ifi->index)
255 if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
257 if (scripttime == 0 || t < scripttime + 10)
260 sa = (struct sockaddr_in*)get_ifa((char *)(ifam + 1), ifam->ifam_addrs);
264 if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf))
265 error("king bula sez: len mismatch");
266 memcpy(a.iabuf, &sa->sin_addr, a.len);
267 if (addr_eq(a, defaddr))
270 for (l = ifi->client->active; l != NULL; l = l->next)
271 if (addr_eq(a, l->address))
274 if (l == NULL) /* added/deleted addr is not the one we set */
277 addr = inet_ntoa(sa->sin_addr);
278 if (rtm->rtm_type == RTM_NEWADDR) {
280 * XXX: If someone other than us adds our address,
281 * should we assume they are taking over from us,
282 * delete the lease record, and exit without modifying
285 warning("My address (%s) was re-added", addr);
287 warning("My address (%s) was deleted, dhclient exiting",
293 ifm = (struct if_msghdr *)rtm;
294 if (ifm->ifm_index != ifi->index)
296 if ((rtm->rtm_flags & RTF_UP) == 0) {
297 warning("Interface %s is down, dhclient exiting",
301 linkstat = interface_link_status(ifi->name);
302 if (linkstat != ifi->linkstat) {
303 debug("%s link state %s -> %s", ifi->name,
304 ifi->linkstat ? "up" : "down",
305 linkstat ? "up" : "down");
306 ifi->linkstat = linkstat;
312 ifan = (struct if_announcemsghdr *)rtm;
313 if (ifan->ifan_what == IFAN_DEPARTURE &&
314 ifan->ifan_index == ifi->index) {
315 warning("Interface %s is gone, dhclient exiting",
321 ifan = (struct if_announcemsghdr *)rtm;
322 if (ifan->ifan_index != ifi->index)
324 switch (ifan->ifan_what) {
325 case RTM_IEEE80211_ASSOC:
326 case RTM_IEEE80211_REASSOC:
328 * Use assoc/reassoc event to kick state machine
329 * in case we roam. Otherwise fall back to the
330 * normal state machine just like a wired network.
332 jev = (struct ieee80211_join_event *) &ifan[1];
333 if (memcmp(curbssid, jev->iev_addr, 6)) {
337 memcpy(curbssid, jev->iev_addr, 6);
347 script_init("FAIL", NULL);
348 if (ifi->client->alias)
349 script_write_params("alias_", ifi->client->alias);
352 pidfile_remove(pidfile);
359 cap_channel_t *casper;
363 error("unable to start casper");
365 capsyslog = cap_service_open(casper, "system.syslog");
367 if (capsyslog == NULL)
368 error("unable to open system.syslog service");
372 main(int argc, char *argv[])
375 int ch, fd, quiet = 0, i = 0;
377 int immediate_daemon = 0;
384 /* Initially, log errors to stderr as well as to syslogd. */
385 cap_openlog(capsyslog, getprogname(), LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
386 cap_setlogmask(capsyslog, LOG_UPTO(LOG_DEBUG));
388 while ((ch = getopt(argc, argv, "bc:dl:p:qu")) != -1)
391 immediate_daemon = 1;
394 path_dhclient_conf = optarg;
400 path_dhclient_db = optarg;
403 path_dhclient_pidfile = optarg;
421 if (path_dhclient_pidfile == NULL) {
422 asprintf(&path_dhclient_pidfile,
423 "%s/dhclient/dhclient.%s.pid", _PATH_VARRUN, *argv);
424 if (path_dhclient_pidfile == NULL)
427 pidfile = pidfile_open(path_dhclient_pidfile, 0644, &otherpid);
428 if (pidfile == NULL) {
430 error("dhclient already running, pid: %d.", otherpid);
432 error("dhclient already running.");
433 warning("Cannot open or create pidfile: %m");
436 if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL)
438 if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
439 error("Interface name too long");
440 if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s",
441 _PATH_DHCLIENT_DB, ifi->name) == -1)
450 inaddr_broadcast.s_addr = INADDR_BROADCAST;
451 inaddr_any.s_addr = INADDR_ANY;
455 /* The next bit is potentially very time-consuming, so write out
456 the pidfile right away. We will write it out again with the
457 correct pid after daemonizing. */
459 pidfile_write(pidfile);
461 if (!interface_link_status(ifi->name)) {
462 fprintf(stderr, "%s: no link ...", ifi->name);
465 while (!interface_link_status(ifi->name)) {
466 fprintf(stderr, ".");
469 fprintf(stderr, " giving up\n");
474 fprintf(stderr, " got link\n");
478 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
479 error("cannot open %s: %m", _PATH_DEVNULL);
481 if ((pw = getpwnam("_dhcp")) == NULL) {
482 warning("no such user: _dhcp, falling back to \"nobody\"");
483 if ((pw = getpwnam("nobody")) == NULL)
484 error("no such user: nobody");
488 * Obtain hostname before entering capability mode - it won't be
489 * possible then, as reading kern.hostname is not permitted.
491 if (gethostname(hostname, sizeof(hostname)) < 0)
494 priv_script_init("PREINIT", NULL);
495 if (ifi->client->alias)
496 priv_script_write_params("alias_", ifi->client->alias);
499 /* set up the interface */
500 discover_interfaces(ifi);
502 if (pipe(pipe_fd) == -1)
505 fork_privchld(pipe_fd[0], pipe_fd[1]);
514 cap_rights_init(&rights, CAP_READ, CAP_WRITE);
515 if (cap_rights_limit(privfd, &rights) < 0 && errno != ENOSYS)
516 error("can't limit private descriptor: %m");
518 if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
519 error("can't open and lock %s: %m", path_dhclient_db);
520 read_client_leases();
521 rewrite_client_leases();
524 if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
525 add_protocol("AF_ROUTE", routefd, routehandler, ifi);
526 if (shutdown(routefd, SHUT_WR) < 0)
527 error("can't shutdown route socket: %m");
528 cap_rights_init(&rights, CAP_EVENT, CAP_READ);
529 if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS)
530 error("can't limit route socket: %m");
534 setproctitle("%s", ifi->name);
536 /* setgroups(2) is not permitted in capability mode. */
537 if (setgroups(1, &pw->pw_gid) != 0)
538 error("can't restrict groups: %m");
540 if (caph_enter_casper() < 0)
541 error("can't enter capability mode: %m");
544 * If we are not in capability mode (i.e., Capsicum or libcasper is
545 * disabled), try to restrict filesystem access. This will fail if
546 * kern.chroot_allow_open_directories is 0 or the process is jailed.
548 if (cap_getmode(&capmode) < 0 || capmode == 0) {
549 if (chroot(_PATH_VAREMPTY) == -1)
551 if (chdir("/") == -1)
552 error("chdir(\"/\")");
555 if (setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
556 seteuid(pw->pw_uid) || setuid(pw->pw_uid))
557 error("can't drop privileges: %m");
559 if (immediate_daemon)
562 ifi->client->state = S_INIT;
565 bootp_packet_handler = do_packet;
577 fprintf(stderr, "usage: %s [-bdqu] ", getprogname());
578 fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
585 * Each routine is called from the dhclient_state_machine() in one of
587 * -> entering INIT state
588 * -> recvpacket_flag == 0: timeout in this state
589 * -> otherwise: received a packet in this state
591 * Return conditions as handled by dhclient_state_machine():
592 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
593 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
594 * Returns 0: finish the nap which was interrupted for no good reason.
596 * Several per-interface variables are used to keep track of the process:
597 * active_lease: the lease that is being used on the interface
598 * (null pointer if not configured yet).
599 * offered_leases: leases corresponding to DHCPOFFER messages that have
600 * been sent to us by DHCP servers.
601 * acked_leases: leases corresponding to DHCPACK messages that have been
602 * sent to us by DHCP servers.
603 * sendpacket: DHCP packet we're trying to send.
604 * destination: IP address to send sendpacket to
605 * In addition, there are several relevant per-lease variables.
606 * T1_expiry, T2_expiry, lease_expiry: lease milestones
607 * In the active lease, these control the process of renewing the lease;
608 * In leases on the acked_leases list, this simply determines when we
609 * can no longer legitimately use the lease.
613 state_reboot(void *ipp)
615 struct interface_info *ip = ipp;
617 /* If we don't remember an active lease, go straight to INIT. */
618 if (!ip->client->active || ip->client->active->is_bootp) {
623 /* We are in the rebooting state. */
624 ip->client->state = S_REBOOTING;
626 /* make_request doesn't initialize xid because it normally comes
627 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
628 so pick an xid now. */
629 ip->client->xid = arc4random();
631 /* Make a DHCPREQUEST packet, and set appropriate per-interface
633 make_request(ip, ip->client->active);
634 ip->client->destination = iaddr_broadcast;
635 ip->client->first_sending = cur_time;
636 ip->client->interval = ip->client->config->initial_interval;
638 /* Zap the medium list... */
639 ip->client->medium = NULL;
641 /* Send out the first DHCPREQUEST packet. */
646 * Called when a lease has completely expired and we've
647 * been unable to renew it.
650 state_init(void *ipp)
652 struct interface_info *ip = ipp;
654 ASSERT_STATE(state, S_INIT);
656 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
658 make_discover(ip, ip->client->active);
659 ip->client->xid = ip->client->packet.xid;
660 ip->client->destination = iaddr_broadcast;
661 ip->client->state = S_SELECTING;
662 ip->client->first_sending = cur_time;
663 ip->client->interval = ip->client->config->initial_interval;
665 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
671 * state_selecting is called when one or more DHCPOFFER packets
672 * have been received and a configurable period of time has passed.
675 state_selecting(void *ipp)
677 struct interface_info *ip = ipp;
678 struct client_lease *lp, *next, *picked;
680 ASSERT_STATE(state, S_SELECTING);
682 /* Cancel state_selecting and send_discover timeouts, since either
683 one could have got us here. */
684 cancel_timeout(state_selecting, ip);
685 cancel_timeout(send_discover, ip);
687 /* We have received one or more DHCPOFFER packets. Currently,
688 the only criterion by which we judge leases is whether or
689 not we get a response when we arp for them. */
691 for (lp = ip->client->offered_leases; lp; lp = next) {
694 /* Check to see if we got an ARPREPLY for the address
695 in this particular lease. */
697 script_init("ARPCHECK", lp->medium);
698 script_write_params("check_", lp);
700 /* If the ARPCHECK code detects another
701 machine using the offered address, it exits
702 nonzero. We need to send a DHCPDECLINE and
705 make_decline(ip, lp);
713 free_client_lease(lp);
716 ip->client->offered_leases = NULL;
718 /* If we just tossed all the leases we were offered, go back
721 ip->client->state = S_INIT;
726 /* If it was a BOOTREPLY, we can just take the address right now. */
727 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
728 ip->client->new = picked;
730 /* Make up some lease expiry times
731 XXX these should be configurable. */
732 ip->client->new->expiry = cur_time + 12000;
733 ip->client->new->renewal += cur_time + 8000;
734 ip->client->new->rebind += cur_time + 10000;
736 ip->client->state = S_REQUESTING;
738 /* Bind to the address we received. */
743 /* Go to the REQUESTING state. */
744 ip->client->destination = iaddr_broadcast;
745 ip->client->state = S_REQUESTING;
746 ip->client->first_sending = cur_time;
747 ip->client->interval = ip->client->config->initial_interval;
749 /* Make a DHCPREQUEST packet from the lease we picked. */
750 make_request(ip, picked);
751 ip->client->xid = ip->client->packet.xid;
753 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
754 free_client_lease(picked);
756 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
760 /* state_requesting is called when we receive a DHCPACK message after
761 having sent out one or more DHCPREQUEST packets. */
764 dhcpack(struct packet *packet)
766 struct interface_info *ip = packet->interface;
767 struct client_lease *lease;
769 /* If we're not receptive to an offer right now, or if the offer
770 has an unrecognizable transaction id, then just drop it. */
771 if (packet->interface->client->xid != packet->raw->xid ||
772 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
773 (memcmp(packet->interface->hw_address.haddr,
774 packet->raw->chaddr, packet->raw->hlen)))
777 if (ip->client->state != S_REBOOTING &&
778 ip->client->state != S_REQUESTING &&
779 ip->client->state != S_RENEWING &&
780 ip->client->state != S_REBINDING)
783 note("DHCPACK from %s", piaddr(packet->client_addr));
785 lease = packet_to_lease(packet);
787 note("packet_to_lease failed.");
791 ip->client->new = lease;
793 /* Stop resending DHCPREQUEST. */
794 cancel_timeout(send_request, ip);
796 /* Figure out the lease time. */
797 if (ip->client->config->default_actions[DHO_DHCP_LEASE_TIME] ==
799 ip->client->new->expiry = getULong(
800 ip->client->config->defaults[DHO_DHCP_LEASE_TIME].data);
801 else if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
802 ip->client->new->expiry = getULong(
803 ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
805 ip->client->new->expiry = default_lease_time;
806 /* A number that looks negative here is really just very large,
807 because the lease expiry offset is unsigned. Also make sure that
808 the addition of cur_time below does not overflow (a 32 bit) time_t. */
809 if (ip->client->new->expiry < 0 ||
810 ip->client->new->expiry > TIME_MAX - cur_time)
811 ip->client->new->expiry = TIME_MAX - cur_time;
812 /* XXX should be fixed by resetting the client state */
813 if (ip->client->new->expiry < 60)
814 ip->client->new->expiry = 60;
816 /* Unless overridden in the config, take the server-provided renewal
817 * time if there is one. Otherwise figure it out according to the spec.
818 * Also make sure the renewal time does not exceed the expiry time.
820 if (ip->client->config->default_actions[DHO_DHCP_RENEWAL_TIME] ==
822 ip->client->new->renewal = getULong(
823 ip->client->config->defaults[DHO_DHCP_RENEWAL_TIME].data);
824 else if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
825 ip->client->new->renewal = getULong(
826 ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
828 ip->client->new->renewal = ip->client->new->expiry / 2;
829 if (ip->client->new->renewal < 0 ||
830 ip->client->new->renewal > ip->client->new->expiry / 2)
831 ip->client->new->renewal = ip->client->new->expiry / 2;
833 /* Same deal with the rebind time. */
834 if (ip->client->config->default_actions[DHO_DHCP_REBINDING_TIME] ==
836 ip->client->new->rebind = getULong(
837 ip->client->config->defaults[DHO_DHCP_REBINDING_TIME].data);
838 else if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
839 ip->client->new->rebind = getULong(
840 ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
842 ip->client->new->rebind = ip->client->new->renewal / 4 * 7;
843 if (ip->client->new->rebind < 0 ||
844 ip->client->new->rebind > ip->client->new->renewal / 4 * 7)
845 ip->client->new->rebind = ip->client->new->renewal / 4 * 7;
847 /* Convert the time offsets into seconds-since-the-epoch */
848 ip->client->new->expiry += cur_time;
849 ip->client->new->renewal += cur_time;
850 ip->client->new->rebind += cur_time;
856 bind_lease(struct interface_info *ip)
858 struct option_data *opt;
860 /* Remember the medium. */
861 ip->client->new->medium = ip->client->medium;
863 opt = &ip->client->new->options[DHO_INTERFACE_MTU];
864 if (opt->len == sizeof(u_int16_t)) {
866 bool supersede = (ip->client->config->default_actions[DHO_INTERFACE_MTU] ==
870 mtu = getUShort(ip->client->config->defaults[DHO_INTERFACE_MTU].data);
872 mtu = be16dec(opt->data);
875 /* Treat 0 like a user intentionally doesn't want to change MTU and,
876 * therefore, warning is not needed */
877 if (!supersede || mtu != 0)
878 warning("mtu size %u < %d: ignored", (unsigned)mtu, MIN_MTU);
880 interface_set_mtu_unpriv(privfd, mtu);
884 /* Write out the new lease. */
885 write_client_lease(ip, ip->client->new, 0);
887 /* Run the client script with the new parameters. */
888 script_init((ip->client->state == S_REQUESTING ? "BOUND" :
889 (ip->client->state == S_RENEWING ? "RENEW" :
890 (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))),
891 ip->client->new->medium);
892 if (ip->client->active && ip->client->state != S_REBOOTING)
893 script_write_params("old_", ip->client->active);
894 script_write_params("new_", ip->client->new);
895 if (ip->client->alias)
896 script_write_params("alias_", ip->client->alias);
899 /* Replace the old active lease with the new one. */
900 if (ip->client->active)
901 free_client_lease(ip->client->active);
902 ip->client->active = ip->client->new;
903 ip->client->new = NULL;
905 /* Set up a timeout to start the renewal process. */
906 add_timeout(ip->client->active->renewal, state_bound, ip);
908 note("bound to %s -- renewal in %d seconds.",
909 piaddr(ip->client->active->address),
910 (int)(ip->client->active->renewal - cur_time));
911 ip->client->state = S_BOUND;
912 reinitialize_interfaces();
917 * state_bound is called when we've successfully bound to a particular
918 * lease, but the renewal time on that lease has expired. We are
919 * expected to unicast a DHCPREQUEST to the server that gave us our
923 state_bound(void *ipp)
925 struct interface_info *ip = ipp;
927 ASSERT_STATE(state, S_BOUND);
929 /* T1 has expired. */
930 make_request(ip, ip->client->active);
931 ip->client->xid = ip->client->packet.xid;
933 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
934 memcpy(ip->client->destination.iabuf, ip->client->active->
935 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
936 ip->client->destination.len = 4;
938 ip->client->destination = iaddr_broadcast;
940 ip->client->first_sending = cur_time;
941 ip->client->interval = ip->client->config->initial_interval;
942 ip->client->state = S_RENEWING;
944 /* Send the first packet immediately. */
949 bootp(struct packet *packet)
951 struct iaddrlist *ap;
953 if (packet->raw->op != BOOTREPLY)
956 /* If there's a reject list, make sure this packet's sender isn't
958 for (ap = packet->interface->client->config->reject_list;
960 if (addr_eq(packet->client_addr, ap->addr)) {
961 note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
969 dhcp(struct packet *packet)
971 struct iaddrlist *ap;
972 void (*handler)(struct packet *);
975 switch (packet->packet_type) {
992 /* If there's a reject list, make sure this packet's sender isn't
994 for (ap = packet->interface->client->config->reject_list;
996 if (addr_eq(packet->client_addr, ap->addr)) {
997 note("%s from %s rejected.", type, piaddr(ap->addr));
1005 dhcpoffer(struct packet *packet)
1007 struct interface_info *ip = packet->interface;
1008 struct client_lease *lease, *lp;
1010 int arp_timeout_needed, stop_selecting;
1011 const char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
1012 "DHCPOFFER" : "BOOTREPLY";
1014 /* If we're not receptive to an offer right now, or if the offer
1015 has an unrecognizable transaction id, then just drop it. */
1016 if (ip->client->state != S_SELECTING ||
1017 packet->interface->client->xid != packet->raw->xid ||
1018 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
1019 (memcmp(packet->interface->hw_address.haddr,
1020 packet->raw->chaddr, packet->raw->hlen)))
1023 note("%s from %s", name, piaddr(packet->client_addr));
1026 /* If this lease doesn't supply the minimum required parameters,
1028 for (i = 0; ip->client->config->required_options[i]; i++) {
1029 if (!packet->options[ip->client->config->
1030 required_options[i]].len) {
1031 note("%s isn't satisfactory.", name);
1036 /* If we've already seen this lease, don't record it again. */
1037 for (lease = ip->client->offered_leases;
1038 lease; lease = lease->next) {
1039 if (lease->address.len == sizeof(packet->raw->yiaddr) &&
1040 !memcmp(lease->address.iabuf,
1041 &packet->raw->yiaddr, lease->address.len)) {
1042 debug("%s already seen.", name);
1047 lease = packet_to_lease(packet);
1049 note("packet_to_lease failed.");
1053 /* If this lease was acquired through a BOOTREPLY, record that
1055 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
1056 lease->is_bootp = 1;
1058 /* Record the medium under which this lease was offered. */
1059 lease->medium = ip->client->medium;
1061 /* Send out an ARP Request for the offered IP address. */
1062 script_init("ARPSEND", lease->medium);
1063 script_write_params("check_", lease);
1064 /* If the script can't send an ARP request without waiting,
1065 we'll be waiting when we do the ARPCHECK, so don't wait now. */
1067 arp_timeout_needed = 0;
1069 arp_timeout_needed = 2;
1071 /* Figure out when we're supposed to stop selecting. */
1073 ip->client->first_sending + ip->client->config->select_interval;
1075 /* If this is the lease we asked for, put it at the head of the
1076 list, and don't mess with the arp request timeout. */
1077 if (lease->address.len == ip->client->requested_address.len &&
1078 !memcmp(lease->address.iabuf,
1079 ip->client->requested_address.iabuf,
1080 ip->client->requested_address.len)) {
1081 lease->next = ip->client->offered_leases;
1082 ip->client->offered_leases = lease;
1084 /* If we already have an offer, and arping for this
1085 offer would take us past the selection timeout,
1086 then don't extend the timeout - just hope for the
1088 if (ip->client->offered_leases &&
1089 (cur_time + arp_timeout_needed) > stop_selecting)
1090 arp_timeout_needed = 0;
1092 /* Put the lease at the end of the list. */
1094 if (!ip->client->offered_leases)
1095 ip->client->offered_leases = lease;
1097 for (lp = ip->client->offered_leases; lp->next;
1104 /* If we're supposed to stop selecting before we've had time
1105 to wait for the ARPREPLY, add some delay to wait for
1107 if (stop_selecting - cur_time < arp_timeout_needed)
1108 stop_selecting = cur_time + arp_timeout_needed;
1110 /* If the selecting interval has expired, go immediately to
1111 state_selecting(). Otherwise, time out into
1112 state_selecting at the select interval. */
1113 if (stop_selecting <= 0)
1114 state_selecting(ip);
1116 add_timeout(stop_selecting, state_selecting, ip);
1117 cancel_timeout(send_discover, ip);
1121 /* Allocate a client_lease structure and initialize it from the parameters
1122 in the specified packet. */
1124 struct client_lease *
1125 packet_to_lease(struct packet *packet)
1127 struct client_lease *lease;
1130 lease = malloc(sizeof(struct client_lease));
1133 warning("dhcpoffer: no memory to record lease.");
1137 memset(lease, 0, sizeof(*lease));
1139 /* Copy the lease options. */
1140 for (i = 0; i < 256; i++) {
1141 if (packet->options[i].len) {
1142 lease->options[i].data =
1143 malloc(packet->options[i].len + 1);
1144 if (!lease->options[i].data) {
1145 warning("dhcpoffer: no memory for option %d", i);
1146 free_client_lease(lease);
1149 memcpy(lease->options[i].data,
1150 packet->options[i].data,
1151 packet->options[i].len);
1152 lease->options[i].len =
1153 packet->options[i].len;
1154 lease->options[i].data[lease->options[i].len] =
1157 if (!check_option(lease,i)) {
1158 /* ignore a bogus lease offer */
1159 warning("Invalid lease option - ignoring offer");
1160 free_client_lease(lease);
1166 lease->address.len = sizeof(packet->raw->yiaddr);
1167 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
1169 lease->nextserver.len = sizeof(packet->raw->siaddr);
1170 memcpy(lease->nextserver.iabuf, &packet->raw->siaddr, lease->nextserver.len);
1172 /* If the server name was filled out, copy it.
1173 Do not attempt to validate the server name as a host name.
1174 RFC 2131 merely states that sname is NUL-terminated (which do
1175 do not assume) and that it is the server's host name. Since
1176 the ISC client and server allow arbitrary characters, we do
1178 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1179 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
1180 packet->raw->sname[0]) {
1181 lease->server_name = malloc(DHCP_SNAME_LEN + 1);
1182 if (!lease->server_name) {
1183 warning("dhcpoffer: no memory for server name.");
1184 free_client_lease(lease);
1187 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
1188 lease->server_name[DHCP_SNAME_LEN]='\0';
1191 /* Ditto for the filename. */
1192 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1193 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
1194 packet->raw->file[0]) {
1195 /* Don't count on the NUL terminator. */
1196 lease->filename = malloc(DHCP_FILE_LEN + 1);
1197 if (!lease->filename) {
1198 warning("dhcpoffer: no memory for filename.");
1199 free_client_lease(lease);
1202 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
1203 lease->filename[DHCP_FILE_LEN]='\0';
1209 dhcpnak(struct packet *packet)
1211 struct interface_info *ip = packet->interface;
1213 /* If we're not receptive to an offer right now, or if the offer
1214 has an unrecognizable transaction id, then just drop it. */
1215 if (packet->interface->client->xid != packet->raw->xid ||
1216 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
1217 (memcmp(packet->interface->hw_address.haddr,
1218 packet->raw->chaddr, packet->raw->hlen)))
1221 if (ip->client->state != S_REBOOTING &&
1222 ip->client->state != S_REQUESTING &&
1223 ip->client->state != S_RENEWING &&
1224 ip->client->state != S_REBINDING)
1227 note("DHCPNAK from %s", piaddr(packet->client_addr));
1229 if (!ip->client->active) {
1230 note("DHCPNAK with no active lease.\n");
1234 free_client_lease(ip->client->active);
1235 ip->client->active = NULL;
1237 /* Stop sending DHCPREQUEST packets... */
1238 cancel_timeout(send_request, ip);
1240 ip->client->state = S_INIT;
1244 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1245 one after the right interval has expired. If we don't get an offer by
1246 the time we reach the panic interval, call the panic function. */
1249 send_discover(void *ipp)
1251 struct interface_info *ip = ipp;
1252 int interval, increase = 1;
1254 /* Figure out how long it's been since we started transmitting. */
1255 interval = cur_time - ip->client->first_sending;
1257 /* If we're past the panic timeout, call the script and tell it
1258 we haven't found anything for this interface yet. */
1259 if (interval > ip->client->config->timeout) {
1264 /* If we're selecting media, try the whole list before doing
1265 the exponential backoff, but if we've already received an
1266 offer, stop looping, because we obviously have it right. */
1267 if (!ip->client->offered_leases &&
1268 ip->client->config->media) {
1271 if (ip->client->medium) {
1272 ip->client->medium = ip->client->medium->next;
1275 if (!ip->client->medium) {
1277 error("No valid media types for %s!", ip->name);
1278 ip->client->medium = ip->client->config->media;
1282 note("Trying medium \"%s\" %d", ip->client->medium->string,
1284 script_init("MEDIUM", ip->client->medium);
1290 * If we're supposed to increase the interval, do so. If it's
1291 * currently zero (i.e., we haven't sent any packets yet), set
1292 * it to one; otherwise, add to it a random number between zero
1293 * and two times itself. On average, this means that it will
1294 * double with every transmission.
1297 if (!ip->client->interval)
1298 ip->client->interval =
1299 ip->client->config->initial_interval;
1301 ip->client->interval += (arc4random() >> 2) %
1302 (2 * ip->client->interval);
1305 /* Don't backoff past cutoff. */
1306 if (ip->client->interval >
1307 ip->client->config->backoff_cutoff)
1308 ip->client->interval =
1309 ((ip->client->config->backoff_cutoff / 2)
1310 + ((arc4random() >> 2) %
1311 ip->client->config->backoff_cutoff));
1312 } else if (!ip->client->interval)
1313 ip->client->interval =
1314 ip->client->config->initial_interval;
1316 /* If the backoff would take us to the panic timeout, just use that
1318 if (cur_time + ip->client->interval >
1319 ip->client->first_sending + ip->client->config->timeout)
1320 ip->client->interval =
1321 (ip->client->first_sending +
1322 ip->client->config->timeout) - cur_time + 1;
1324 /* Record the number of seconds since we started sending. */
1325 if (interval < 65536)
1326 ip->client->packet.secs = htons(interval);
1328 ip->client->packet.secs = htons(65535);
1329 ip->client->secs = ip->client->packet.secs;
1331 note("DHCPDISCOVER on %s to %s port %d interval %d",
1332 ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT,
1333 (int)ip->client->interval);
1335 /* Send out a packet. */
1336 send_packet_unpriv(privfd, &ip->client->packet,
1337 ip->client->packet_length, inaddr_any, inaddr_broadcast);
1339 add_timeout(cur_time + ip->client->interval, send_discover, ip);
1343 * state_panic gets called if we haven't received any offers in a preset
1344 * amount of time. When this happens, we try to use existing leases
1345 * that haven't yet expired, and failing that, we call the client script
1346 * and hope it can do something.
1349 state_panic(void *ipp)
1351 struct interface_info *ip = ipp;
1352 struct client_lease *loop = ip->client->active;
1353 struct client_lease *lp;
1355 note("No DHCPOFFERS received.");
1357 /* We may not have an active lease, but we may have some
1358 predefined leases that we can try. */
1359 if (!ip->client->active && ip->client->leases)
1362 /* Run through the list of leases and see if one can be used. */
1363 while (ip->client->active) {
1364 if (ip->client->active->expiry > cur_time) {
1365 note("Trying recorded lease %s",
1366 piaddr(ip->client->active->address));
1367 /* Run the client script with the existing
1369 script_init("TIMEOUT",
1370 ip->client->active->medium);
1371 script_write_params("new_", ip->client->active);
1372 if (ip->client->alias)
1373 script_write_params("alias_",
1376 /* If the old lease is still good and doesn't
1377 yet need renewal, go into BOUND state and
1378 timeout at the renewal time. */
1381 ip->client->active->renewal) {
1382 ip->client->state = S_BOUND;
1383 note("bound: renewal in %d seconds.",
1384 (int)(ip->client->active->renewal -
1387 ip->client->active->renewal,
1390 ip->client->state = S_BOUND;
1391 note("bound: immediate renewal.");
1394 reinitialize_interfaces();
1400 /* If there are no other leases, give up. */
1401 if (!ip->client->leases) {
1402 ip->client->leases = ip->client->active;
1403 ip->client->active = NULL;
1408 /* Otherwise, put the active lease at the end of the
1409 lease list, and try another lease.. */
1410 for (lp = ip->client->leases; lp->next; lp = lp->next)
1412 lp->next = ip->client->active;
1414 lp->next->next = NULL;
1415 ip->client->active = ip->client->leases;
1416 ip->client->leases = ip->client->leases->next;
1418 /* If we already tried this lease, we've exhausted the
1419 set of leases, so we might as well give up for
1421 if (ip->client->active == loop)
1424 loop = ip->client->active;
1427 /* No leases were available, or what was available didn't work, so
1428 tell the shell script that we failed to allocate an address,
1429 and try again later. */
1430 note("No working leases in persistent database - sleeping.\n");
1431 script_init("FAIL", NULL);
1432 if (ip->client->alias)
1433 script_write_params("alias_", ip->client->alias);
1435 ip->client->state = S_INIT;
1436 add_timeout(cur_time + ip->client->config->retry_interval, state_init,
1442 send_request(void *ipp)
1444 struct interface_info *ip = ipp;
1445 struct in_addr from, to;
1448 /* Figure out how long it's been since we started transmitting. */
1449 interval = cur_time - ip->client->first_sending;
1451 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1452 past the reboot timeout, go to INIT and see if we can
1453 DISCOVER an address... */
1454 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1455 means either that we're on a network with no DHCP server,
1456 or that our server is down. In the latter case, assuming
1457 that there is a backup DHCP server, DHCPDISCOVER will get
1458 us a new address, but we could also have successfully
1459 reused our old address. In the former case, we're hosed
1460 anyway. This is not a win-prone situation. */
1461 if ((ip->client->state == S_REBOOTING ||
1462 ip->client->state == S_REQUESTING) &&
1463 interval > ip->client->config->reboot_timeout) {
1465 ip->client->state = S_INIT;
1466 cancel_timeout(send_request, ip);
1471 /* If we're in the reboot state, make sure the media is set up
1473 if (ip->client->state == S_REBOOTING &&
1474 !ip->client->medium &&
1475 ip->client->active->medium ) {
1476 script_init("MEDIUM", ip->client->active->medium);
1478 /* If the medium we chose won't fly, go to INIT state. */
1482 /* Record the medium. */
1483 ip->client->medium = ip->client->active->medium;
1486 /* If the lease has expired, relinquish the address and go back
1487 to the INIT state. */
1488 if (ip->client->state != S_REQUESTING &&
1489 cur_time > ip->client->active->expiry) {
1490 /* Run the client script with the new parameters. */
1491 script_init("EXPIRE", NULL);
1492 script_write_params("old_", ip->client->active);
1493 if (ip->client->alias)
1494 script_write_params("alias_", ip->client->alias);
1497 /* Now do a preinit on the interface so that we can
1498 discover a new address. */
1499 script_init("PREINIT", NULL);
1500 if (ip->client->alias)
1501 script_write_params("alias_", ip->client->alias);
1504 ip->client->state = S_INIT;
1509 /* Do the exponential backoff... */
1510 if (!ip->client->interval)
1511 ip->client->interval = ip->client->config->initial_interval;
1513 ip->client->interval += ((arc4random() >> 2) %
1514 (2 * ip->client->interval));
1516 /* Don't backoff past cutoff. */
1517 if (ip->client->interval >
1518 ip->client->config->backoff_cutoff)
1519 ip->client->interval =
1520 ((ip->client->config->backoff_cutoff / 2) +
1521 ((arc4random() >> 2) % ip->client->interval));
1523 /* If the backoff would take us to the expiry time, just set the
1524 timeout to the expiry time. */
1525 if (ip->client->state != S_REQUESTING &&
1526 cur_time + ip->client->interval >
1527 ip->client->active->expiry)
1528 ip->client->interval =
1529 ip->client->active->expiry - cur_time + 1;
1531 /* If the lease T2 time has elapsed, or if we're not yet bound,
1532 broadcast the DHCPREQUEST rather than unicasting. */
1533 if (ip->client->state == S_REQUESTING ||
1534 ip->client->state == S_REBOOTING ||
1535 cur_time > ip->client->active->rebind)
1536 to.s_addr = INADDR_BROADCAST;
1538 memcpy(&to.s_addr, ip->client->destination.iabuf,
1541 if (ip->client->state != S_REQUESTING &&
1542 ip->client->state != S_REBOOTING)
1543 memcpy(&from, ip->client->active->address.iabuf,
1546 from.s_addr = INADDR_ANY;
1548 /* Record the number of seconds since we started sending. */
1549 if (ip->client->state == S_REQUESTING)
1550 ip->client->packet.secs = ip->client->secs;
1552 if (interval < 65536)
1553 ip->client->packet.secs = htons(interval);
1555 ip->client->packet.secs = htons(65535);
1558 note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to),
1561 /* Send out a packet. */
1562 send_packet_unpriv(privfd, &ip->client->packet,
1563 ip->client->packet_length, from, to);
1565 add_timeout(cur_time + ip->client->interval, send_request, ip);
1569 send_decline(void *ipp)
1571 struct interface_info *ip = ipp;
1573 note("DHCPDECLINE on %s to %s port %d", ip->name,
1574 inet_ntoa(inaddr_broadcast), REMOTE_PORT);
1576 /* Send out a packet. */
1577 send_packet_unpriv(privfd, &ip->client->packet,
1578 ip->client->packet_length, inaddr_any, inaddr_broadcast);
1582 make_discover(struct interface_info *ip, struct client_lease *lease)
1584 unsigned char discover = DHCPDISCOVER;
1585 struct tree_cache *options[256];
1586 struct tree_cache option_elements[256];
1589 memset(option_elements, 0, sizeof(option_elements));
1590 memset(options, 0, sizeof(options));
1591 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1593 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1594 i = DHO_DHCP_MESSAGE_TYPE;
1595 options[i] = &option_elements[i];
1596 options[i]->value = &discover;
1597 options[i]->len = sizeof(discover);
1598 options[i]->buf_size = sizeof(discover);
1599 options[i]->timeout = 0xFFFFFFFF;
1601 /* Request the options we want */
1602 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1603 options[i] = &option_elements[i];
1604 options[i]->value = ip->client->config->requested_options;
1605 options[i]->len = ip->client->config->requested_option_count;
1606 options[i]->buf_size =
1607 ip->client->config->requested_option_count;
1608 options[i]->timeout = 0xFFFFFFFF;
1610 /* If we had an address, try to get it again. */
1612 ip->client->requested_address = lease->address;
1613 i = DHO_DHCP_REQUESTED_ADDRESS;
1614 options[i] = &option_elements[i];
1615 options[i]->value = lease->address.iabuf;
1616 options[i]->len = lease->address.len;
1617 options[i]->buf_size = lease->address.len;
1618 options[i]->timeout = 0xFFFFFFFF;
1620 ip->client->requested_address.len = 0;
1622 /* Send any options requested in the config file. */
1623 for (i = 0; i < 256; i++)
1625 ip->client->config->send_options[i].data) {
1626 options[i] = &option_elements[i];
1628 ip->client->config->send_options[i].data;
1630 ip->client->config->send_options[i].len;
1631 options[i]->buf_size =
1632 ip->client->config->send_options[i].len;
1633 options[i]->timeout = 0xFFFFFFFF;
1636 /* send host name if not set via config file. */
1637 if (!options[DHO_HOST_NAME]) {
1638 if (hostname[0] != '\0') {
1640 char* posDot = strchr(hostname, '.');
1642 len = posDot - hostname;
1644 len = strlen(hostname);
1645 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1646 options[DHO_HOST_NAME]->value = hostname;
1647 options[DHO_HOST_NAME]->len = len;
1648 options[DHO_HOST_NAME]->buf_size = len;
1649 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1653 /* set unique client identifier */
1654 char client_ident[sizeof(ip->hw_address.haddr) + 1];
1655 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1656 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1657 ip->hw_address.hlen : sizeof(client_ident)-1;
1658 client_ident[0] = ip->hw_address.htype;
1659 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1660 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1661 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1662 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1663 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1664 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1667 /* Set up the option buffer... */
1668 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1669 options, 0, 0, 0, NULL, 0);
1670 if (ip->client->packet_length < BOOTP_MIN_LEN)
1671 ip->client->packet_length = BOOTP_MIN_LEN;
1673 ip->client->packet.op = BOOTREQUEST;
1674 ip->client->packet.htype = ip->hw_address.htype;
1675 ip->client->packet.hlen = ip->hw_address.hlen;
1676 ip->client->packet.hops = 0;
1677 ip->client->packet.xid = arc4random();
1678 ip->client->packet.secs = 0; /* filled in by send_discover. */
1679 ip->client->packet.flags = 0;
1681 memset(&(ip->client->packet.ciaddr),
1682 0, sizeof(ip->client->packet.ciaddr));
1683 memset(&(ip->client->packet.yiaddr),
1684 0, sizeof(ip->client->packet.yiaddr));
1685 memset(&(ip->client->packet.siaddr),
1686 0, sizeof(ip->client->packet.siaddr));
1687 memset(&(ip->client->packet.giaddr),
1688 0, sizeof(ip->client->packet.giaddr));
1689 memcpy(ip->client->packet.chaddr,
1690 ip->hw_address.haddr, ip->hw_address.hlen);
1695 make_request(struct interface_info *ip, struct client_lease * lease)
1697 unsigned char request = DHCPREQUEST;
1698 struct tree_cache *options[256];
1699 struct tree_cache option_elements[256];
1702 memset(options, 0, sizeof(options));
1703 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1705 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1706 i = DHO_DHCP_MESSAGE_TYPE;
1707 options[i] = &option_elements[i];
1708 options[i]->value = &request;
1709 options[i]->len = sizeof(request);
1710 options[i]->buf_size = sizeof(request);
1711 options[i]->timeout = 0xFFFFFFFF;
1713 /* Request the options we want */
1714 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1715 options[i] = &option_elements[i];
1716 options[i]->value = ip->client->config->requested_options;
1717 options[i]->len = ip->client->config->requested_option_count;
1718 options[i]->buf_size =
1719 ip->client->config->requested_option_count;
1720 options[i]->timeout = 0xFFFFFFFF;
1722 /* If we are requesting an address that hasn't yet been assigned
1723 to us, use the DHCP Requested Address option. */
1724 if (ip->client->state == S_REQUESTING) {
1725 /* Send back the server identifier... */
1726 i = DHO_DHCP_SERVER_IDENTIFIER;
1727 options[i] = &option_elements[i];
1728 options[i]->value = lease->options[i].data;
1729 options[i]->len = lease->options[i].len;
1730 options[i]->buf_size = lease->options[i].len;
1731 options[i]->timeout = 0xFFFFFFFF;
1733 if (ip->client->state == S_REQUESTING ||
1734 ip->client->state == S_REBOOTING) {
1735 ip->client->requested_address = lease->address;
1736 i = DHO_DHCP_REQUESTED_ADDRESS;
1737 options[i] = &option_elements[i];
1738 options[i]->value = lease->address.iabuf;
1739 options[i]->len = lease->address.len;
1740 options[i]->buf_size = lease->address.len;
1741 options[i]->timeout = 0xFFFFFFFF;
1743 ip->client->requested_address.len = 0;
1745 /* Send any options requested in the config file. */
1746 for (i = 0; i < 256; i++)
1748 ip->client->config->send_options[i].data) {
1749 options[i] = &option_elements[i];
1751 ip->client->config->send_options[i].data;
1753 ip->client->config->send_options[i].len;
1754 options[i]->buf_size =
1755 ip->client->config->send_options[i].len;
1756 options[i]->timeout = 0xFFFFFFFF;
1759 /* send host name if not set via config file. */
1760 if (!options[DHO_HOST_NAME]) {
1761 if (hostname[0] != '\0') {
1763 char* posDot = strchr(hostname, '.');
1765 len = posDot - hostname;
1767 len = strlen(hostname);
1768 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1769 options[DHO_HOST_NAME]->value = hostname;
1770 options[DHO_HOST_NAME]->len = len;
1771 options[DHO_HOST_NAME]->buf_size = len;
1772 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1776 /* set unique client identifier */
1777 char client_ident[sizeof(struct hardware)];
1778 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1779 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1780 ip->hw_address.hlen : sizeof(client_ident)-1;
1781 client_ident[0] = ip->hw_address.htype;
1782 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1783 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1784 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1785 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1786 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1787 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1790 /* Set up the option buffer... */
1791 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1792 options, 0, 0, 0, NULL, 0);
1793 if (ip->client->packet_length < BOOTP_MIN_LEN)
1794 ip->client->packet_length = BOOTP_MIN_LEN;
1796 ip->client->packet.op = BOOTREQUEST;
1797 ip->client->packet.htype = ip->hw_address.htype;
1798 ip->client->packet.hlen = ip->hw_address.hlen;
1799 ip->client->packet.hops = 0;
1800 ip->client->packet.xid = ip->client->xid;
1801 ip->client->packet.secs = 0; /* Filled in by send_request. */
1803 /* If we own the address we're requesting, put it in ciaddr;
1804 otherwise set ciaddr to zero. */
1805 if (ip->client->state == S_BOUND ||
1806 ip->client->state == S_RENEWING ||
1807 ip->client->state == S_REBINDING) {
1808 memcpy(&ip->client->packet.ciaddr,
1809 lease->address.iabuf, lease->address.len);
1810 ip->client->packet.flags = 0;
1812 memset(&ip->client->packet.ciaddr, 0,
1813 sizeof(ip->client->packet.ciaddr));
1814 ip->client->packet.flags = 0;
1817 memset(&ip->client->packet.yiaddr, 0,
1818 sizeof(ip->client->packet.yiaddr));
1819 memset(&ip->client->packet.siaddr, 0,
1820 sizeof(ip->client->packet.siaddr));
1821 memset(&ip->client->packet.giaddr, 0,
1822 sizeof(ip->client->packet.giaddr));
1823 memcpy(ip->client->packet.chaddr,
1824 ip->hw_address.haddr, ip->hw_address.hlen);
1828 make_decline(struct interface_info *ip, struct client_lease *lease)
1830 struct tree_cache *options[256], message_type_tree;
1831 struct tree_cache requested_address_tree;
1832 struct tree_cache server_id_tree, client_id_tree;
1833 unsigned char decline = DHCPDECLINE;
1836 memset(options, 0, sizeof(options));
1837 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1839 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1840 i = DHO_DHCP_MESSAGE_TYPE;
1841 options[i] = &message_type_tree;
1842 options[i]->value = &decline;
1843 options[i]->len = sizeof(decline);
1844 options[i]->buf_size = sizeof(decline);
1845 options[i]->timeout = 0xFFFFFFFF;
1847 /* Send back the server identifier... */
1848 i = DHO_DHCP_SERVER_IDENTIFIER;
1849 options[i] = &server_id_tree;
1850 options[i]->value = lease->options[i].data;
1851 options[i]->len = lease->options[i].len;
1852 options[i]->buf_size = lease->options[i].len;
1853 options[i]->timeout = 0xFFFFFFFF;
1855 /* Send back the address we're declining. */
1856 i = DHO_DHCP_REQUESTED_ADDRESS;
1857 options[i] = &requested_address_tree;
1858 options[i]->value = lease->address.iabuf;
1859 options[i]->len = lease->address.len;
1860 options[i]->buf_size = lease->address.len;
1861 options[i]->timeout = 0xFFFFFFFF;
1863 /* Send the uid if the user supplied one. */
1864 i = DHO_DHCP_CLIENT_IDENTIFIER;
1865 if (ip->client->config->send_options[i].len) {
1866 options[i] = &client_id_tree;
1867 options[i]->value = ip->client->config->send_options[i].data;
1868 options[i]->len = ip->client->config->send_options[i].len;
1869 options[i]->buf_size = ip->client->config->send_options[i].len;
1870 options[i]->timeout = 0xFFFFFFFF;
1874 /* Set up the option buffer... */
1875 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1876 options, 0, 0, 0, NULL, 0);
1877 if (ip->client->packet_length < BOOTP_MIN_LEN)
1878 ip->client->packet_length = BOOTP_MIN_LEN;
1880 ip->client->packet.op = BOOTREQUEST;
1881 ip->client->packet.htype = ip->hw_address.htype;
1882 ip->client->packet.hlen = ip->hw_address.hlen;
1883 ip->client->packet.hops = 0;
1884 ip->client->packet.xid = ip->client->xid;
1885 ip->client->packet.secs = 0; /* Filled in by send_request. */
1886 ip->client->packet.flags = 0;
1888 /* ciaddr must always be zero. */
1889 memset(&ip->client->packet.ciaddr, 0,
1890 sizeof(ip->client->packet.ciaddr));
1891 memset(&ip->client->packet.yiaddr, 0,
1892 sizeof(ip->client->packet.yiaddr));
1893 memset(&ip->client->packet.siaddr, 0,
1894 sizeof(ip->client->packet.siaddr));
1895 memset(&ip->client->packet.giaddr, 0,
1896 sizeof(ip->client->packet.giaddr));
1897 memcpy(ip->client->packet.chaddr,
1898 ip->hw_address.haddr, ip->hw_address.hlen);
1902 free_client_lease(struct client_lease *lease)
1906 if (lease->server_name)
1907 free(lease->server_name);
1908 if (lease->filename)
1909 free(lease->filename);
1910 for (i = 0; i < 256; i++) {
1911 if (lease->options[i].len)
1912 free(lease->options[i].data);
1917 static FILE *leaseFile;
1920 rewrite_client_leases(void)
1922 struct client_lease *lp;
1923 cap_rights_t rights;
1926 leaseFile = fopen(path_dhclient_db, "w");
1928 error("can't create %s: %m", path_dhclient_db);
1929 cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_FSYNC,
1930 CAP_FTRUNCATE, CAP_SEEK, CAP_WRITE);
1931 if (cap_rights_limit(fileno(leaseFile), &rights) < 0 &&
1933 error("can't limit lease descriptor: %m");
1935 if (cap_fcntls_limit(fileno(leaseFile), CAP_FCNTL_GETFL) < 0 &&
1937 error("can't limit lease descriptor fcntls: %m");
1944 for (lp = ifi->client->leases; lp; lp = lp->next)
1945 write_client_lease(ifi, lp, 1);
1946 if (ifi->client->active)
1947 write_client_lease(ifi, ifi->client->active, 1);
1950 ftruncate(fileno(leaseFile), ftello(leaseFile));
1951 fsync(fileno(leaseFile));
1955 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1958 static int leases_written;
1963 if (leases_written++ > 20) {
1964 rewrite_client_leases();
1969 /* If the lease came from the config file, we don't need to stash
1970 a copy in the lease database. */
1971 if (lease->is_static)
1974 if (!leaseFile) { /* XXX */
1975 leaseFile = fopen(path_dhclient_db, "w");
1977 error("can't create %s: %m", path_dhclient_db);
1980 fprintf(leaseFile, "lease {\n");
1981 if (lease->is_bootp)
1982 fprintf(leaseFile, " bootp;\n");
1983 fprintf(leaseFile, " interface \"%s\";\n", ip->name);
1984 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
1985 if (lease->nextserver.len == sizeof(inaddr_any) &&
1986 0 != memcmp(lease->nextserver.iabuf, &inaddr_any,
1987 sizeof(inaddr_any)))
1988 fprintf(leaseFile, " next-server %s;\n",
1989 piaddr(lease->nextserver));
1990 if (lease->filename)
1991 fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
1992 if (lease->server_name)
1993 fprintf(leaseFile, " server-name \"%s\";\n",
1994 lease->server_name);
1996 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string);
1997 for (i = 0; i < 256; i++)
1998 if (lease->options[i].len)
1999 fprintf(leaseFile, " option %s %s;\n",
2000 dhcp_options[i].name,
2001 pretty_print_option(i, lease->options[i].data,
2002 lease->options[i].len, 1, 1));
2004 t = gmtime(&lease->renewal);
2005 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
2006 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
2007 t->tm_hour, t->tm_min, t->tm_sec);
2008 t = gmtime(&lease->rebind);
2009 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
2010 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
2011 t->tm_hour, t->tm_min, t->tm_sec);
2012 t = gmtime(&lease->expiry);
2013 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
2014 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
2015 t->tm_hour, t->tm_min, t->tm_sec);
2016 fprintf(leaseFile, "}\n");
2021 script_init(const char *reason, struct string_list *medium)
2023 size_t len, mediumlen = 0;
2024 struct imsg_hdr hdr;
2028 if (medium != NULL && medium->string != NULL)
2029 mediumlen = strlen(medium->string);
2031 hdr.code = IMSG_SCRIPT_INIT;
2032 hdr.len = sizeof(struct imsg_hdr) +
2033 sizeof(size_t) + mediumlen +
2034 sizeof(size_t) + strlen(reason);
2036 if ((buf = buf_open(hdr.len)) == NULL)
2037 error("buf_open: %m");
2040 errs += buf_add(buf, &hdr, sizeof(hdr));
2041 errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
2043 errs += buf_add(buf, medium->string, mediumlen);
2044 len = strlen(reason);
2045 errs += buf_add(buf, &len, sizeof(len));
2046 errs += buf_add(buf, reason, len);
2049 error("buf_add: %m");
2051 if (buf_close(privfd, buf) == -1)
2052 error("buf_close: %m");
2056 priv_script_init(const char *reason, char *medium)
2058 struct interface_info *ip = ifi;
2061 ip->client->scriptEnvsize = 100;
2062 if (ip->client->scriptEnv == NULL)
2063 ip->client->scriptEnv =
2064 malloc(ip->client->scriptEnvsize * sizeof(char *));
2065 if (ip->client->scriptEnv == NULL)
2066 error("script_init: no memory for environment");
2068 ip->client->scriptEnv[0] = strdup(CLIENT_PATH);
2069 if (ip->client->scriptEnv[0] == NULL)
2070 error("script_init: no memory for environment");
2072 ip->client->scriptEnv[1] = NULL;
2074 script_set_env(ip->client, "", "interface", ip->name);
2077 script_set_env(ip->client, "", "medium", medium);
2079 script_set_env(ip->client, "", "reason", reason);
2084 priv_script_write_params(const char *prefix, struct client_lease *lease)
2086 struct interface_info *ip = ifi;
2087 u_int8_t dbuf[1500], *dp = NULL;
2092 script_set_env(ip->client, prefix, "ip_address",
2093 piaddr(lease->address));
2095 if (ip->client->config->default_actions[DHO_SUBNET_MASK] ==
2097 dp = ip->client->config->defaults[DHO_SUBNET_MASK].data;
2098 len = ip->client->config->defaults[DHO_SUBNET_MASK].len;
2100 dp = lease->options[DHO_SUBNET_MASK].data;
2101 len = lease->options[DHO_SUBNET_MASK].len;
2103 if (len && (len < sizeof(lease->address.iabuf))) {
2104 struct iaddr netmask, subnet, broadcast;
2106 memcpy(netmask.iabuf, dp, len);
2108 subnet = subnet_number(lease->address, netmask);
2110 script_set_env(ip->client, prefix, "network_number",
2112 if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
2113 broadcast = broadcast_addr(subnet, netmask);
2115 script_set_env(ip->client, prefix,
2116 "broadcast_address",
2122 if (lease->filename)
2123 script_set_env(ip->client, prefix, "filename", lease->filename);
2124 if (lease->server_name)
2125 script_set_env(ip->client, prefix, "server_name",
2126 lease->server_name);
2127 for (i = 0; i < 256; i++) {
2130 if (ip->client->config->defaults[i].len) {
2131 if (lease->options[i].len) {
2133 ip->client->config->default_actions[i]) {
2134 case ACTION_DEFAULT:
2135 dp = lease->options[i].data;
2136 len = lease->options[i].len;
2138 case ACTION_SUPERSEDE:
2141 config->defaults[i].data;
2143 config->defaults[i].len;
2145 case ACTION_PREPEND:
2147 config->defaults[i].len +
2148 lease->options[i].len;
2149 if (len >= sizeof(dbuf)) {
2150 warning("no space to %s %s",
2152 dhcp_options[i].name);
2158 config->defaults[i].data,
2160 config->defaults[i].len);
2161 memcpy(dp + ip->client->
2162 config->defaults[i].len,
2163 lease->options[i].data,
2164 lease->options[i].len);
2169 * When we append, we assume that we're
2170 * appending to text. Some MS servers
2171 * include a NUL byte at the end of
2172 * the search string provided.
2175 config->defaults[i].len +
2176 lease->options[i].len;
2177 if (len >= sizeof(dbuf)) {
2178 warning("no space to %s %s",
2180 dhcp_options[i].name);
2184 lease->options[i].data,
2185 lease->options[i].len);
2186 for (dp = dbuf + lease->options[i].len;
2187 dp > dbuf; dp--, len--)
2192 config->defaults[i].data,
2194 config->defaults[i].len);
2200 config->defaults[i].data;
2202 config->defaults[i].len;
2204 } else if (lease->options[i].len) {
2205 len = lease->options[i].len;
2206 dp = lease->options[i].data;
2213 if (dhcp_option_ev_name(name, sizeof(name),
2215 script_set_env(ip->client, prefix, name,
2216 pretty_print_option(i, dp, len, 0, 0));
2219 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
2220 script_set_env(ip->client, prefix, "expiry", tbuf);
2224 script_write_params(const char *prefix, struct client_lease *lease)
2226 size_t fn_len = 0, sn_len = 0, pr_len = 0;
2227 struct imsg_hdr hdr;
2231 if (lease->filename != NULL)
2232 fn_len = strlen(lease->filename);
2233 if (lease->server_name != NULL)
2234 sn_len = strlen(lease->server_name);
2236 pr_len = strlen(prefix);
2238 hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
2239 hdr.len = sizeof(hdr) + sizeof(*lease) +
2240 sizeof(fn_len) + fn_len + sizeof(sn_len) + sn_len +
2241 sizeof(pr_len) + pr_len;
2243 for (i = 0; i < 256; i++) {
2244 hdr.len += sizeof(lease->options[i].len);
2245 hdr.len += lease->options[i].len;
2248 scripttime = time(NULL);
2250 if ((buf = buf_open(hdr.len)) == NULL)
2251 error("buf_open: %m");
2254 errs += buf_add(buf, &hdr, sizeof(hdr));
2255 errs += buf_add(buf, lease, sizeof(*lease));
2256 errs += buf_add(buf, &fn_len, sizeof(fn_len));
2257 errs += buf_add(buf, lease->filename, fn_len);
2258 errs += buf_add(buf, &sn_len, sizeof(sn_len));
2259 errs += buf_add(buf, lease->server_name, sn_len);
2260 errs += buf_add(buf, &pr_len, sizeof(pr_len));
2261 errs += buf_add(buf, prefix, pr_len);
2263 for (i = 0; i < 256; i++) {
2264 errs += buf_add(buf, &lease->options[i].len,
2265 sizeof(lease->options[i].len));
2266 errs += buf_add(buf, lease->options[i].data,
2267 lease->options[i].len);
2271 error("buf_add: %m");
2273 if (buf_close(privfd, buf) == -1)
2274 error("buf_close: %m");
2280 struct imsg_hdr hdr;
2284 hdr.code = IMSG_SCRIPT_GO;
2285 hdr.len = sizeof(struct imsg_hdr);
2287 if ((buf = buf_open(hdr.len)) == NULL)
2288 error("buf_open: %m");
2290 if (buf_add(buf, &hdr, sizeof(hdr)))
2291 error("buf_add: %m");
2293 if (buf_close(privfd, buf) == -1)
2294 error("buf_close: %m");
2296 bzero(&hdr, sizeof(hdr));
2297 buf_read(privfd, &hdr, sizeof(hdr));
2298 if (hdr.code != IMSG_SCRIPT_GO_RET)
2299 error("unexpected msg type %u", hdr.code);
2300 if (hdr.len != sizeof(hdr) + sizeof(int))
2301 error("received corrupted message");
2302 buf_read(privfd, &ret, sizeof(ret));
2304 scripttime = time(NULL);
2310 priv_script_go(void)
2312 char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI";
2313 static char client_path[] = CLIENT_PATH;
2314 struct interface_info *ip = ifi;
2315 int pid, wpid, wstatus;
2317 scripttime = time(NULL);
2320 scriptName = ip->client->config->script_name;
2321 envp = ip->client->scriptEnv;
2323 scriptName = top_level_config.script_name;
2325 epp[1] = client_path;
2330 argv[0] = scriptName;
2339 wpid = wait(&wstatus);
2340 } while (wpid != pid && wpid > 0);
2346 execve(scriptName, argv, envp);
2347 error("execve (%s, ...): %m", scriptName);
2351 script_flush_env(ip->client);
2353 return (wstatus & 0xff);
2357 script_set_env(struct client_state *client, const char *prefix,
2358 const char *name, const char *value)
2363 /* No `` or $() command substitution allowed in environment values! */
2364 for (j=0; j < strlen(value); j++)
2368 warning("illegal character (%c) in value '%s'",
2370 /* Ignore this option */
2374 namelen = strlen(name);
2376 for (i = 0; client->scriptEnv[i]; i++)
2377 if (strncmp(client->scriptEnv[i], name, namelen) == 0 &&
2378 client->scriptEnv[i][namelen] == '=')
2381 if (client->scriptEnv[i])
2382 /* Reuse the slot. */
2383 free(client->scriptEnv[i]);
2385 /* New variable. Expand if necessary. */
2386 if (i >= client->scriptEnvsize - 1) {
2387 char **newscriptEnv;
2388 int newscriptEnvsize = client->scriptEnvsize + 50;
2390 newscriptEnv = realloc(client->scriptEnv,
2392 if (newscriptEnv == NULL) {
2393 free(client->scriptEnv);
2394 client->scriptEnv = NULL;
2395 client->scriptEnvsize = 0;
2396 error("script_set_env: no memory for variable");
2398 client->scriptEnv = newscriptEnv;
2399 client->scriptEnvsize = newscriptEnvsize;
2401 /* need to set the NULL pointer at end of array beyond
2403 client->scriptEnv[i + 1] = NULL;
2405 /* Allocate space and format the variable in the appropriate slot. */
2406 client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 +
2408 if (client->scriptEnv[i] == NULL)
2409 error("script_set_env: no memory for variable assignment");
2410 snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
2411 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
2415 script_flush_env(struct client_state *client)
2419 for (i = 0; client->scriptEnv[i]; i++) {
2420 free(client->scriptEnv[i]);
2421 client->scriptEnv[i] = NULL;
2423 client->scriptEnvsize = 0;
2427 dhcp_option_ev_name(char *buf, size_t buflen, struct option *option)
2431 for (i = 0; option->name[i]; i++) {
2432 if (i + 1 == buflen)
2434 if (option->name[i] == '-')
2437 buf[i] = option->name[i];
2447 static int state = 0;
2448 cap_rights_t rights;
2450 if (no_daemon || state)
2455 /* Stop logging to stderr... */
2458 if (daemonfd(-1, nullfd) == -1)
2461 cap_rights_init(&rights);
2463 if (pidfile != NULL)
2464 pidfile_write(pidfile);
2471 if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS)
2472 error("can't limit stdin: %m");
2473 cap_rights_init(&rights, CAP_WRITE);
2474 if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS)
2475 error("can't limit stdout: %m");
2476 if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS)
2477 error("can't limit stderr: %m");
2481 check_option(struct client_lease *l, int option)
2486 /* we use this, since this is what gets passed to dhclient-script */
2488 opbuf = pretty_print_option(option, l->options[option].data,
2489 l->options[option].len, 0, 0);
2491 sbuf = option_as_string(option, l->options[option].data,
2492 l->options[option].len);
2495 case DHO_SUBNET_MASK:
2496 case DHO_TIME_SERVERS:
2497 case DHO_NAME_SERVERS:
2499 case DHO_DOMAIN_NAME_SERVERS:
2500 case DHO_LOG_SERVERS:
2501 case DHO_COOKIE_SERVERS:
2502 case DHO_LPR_SERVERS:
2503 case DHO_IMPRESS_SERVERS:
2504 case DHO_RESOURCE_LOCATION_SERVERS:
2505 case DHO_SWAP_SERVER:
2506 case DHO_BROADCAST_ADDRESS:
2507 case DHO_NIS_SERVERS:
2508 case DHO_NTP_SERVERS:
2509 case DHO_NETBIOS_NAME_SERVERS:
2510 case DHO_NETBIOS_DD_SERVER:
2511 case DHO_FONT_SERVERS:
2512 case DHO_DHCP_SERVER_IDENTIFIER:
2513 case DHO_NISPLUS_SERVERS:
2514 case DHO_MOBILE_IP_HOME_AGENT:
2515 case DHO_SMTP_SERVER:
2516 case DHO_POP_SERVER:
2517 case DHO_NNTP_SERVER:
2518 case DHO_WWW_SERVER:
2519 case DHO_FINGER_SERVER:
2520 case DHO_IRC_SERVER:
2521 case DHO_STREETTALK_SERVER:
2522 case DHO_STREETTALK_DA_SERVER:
2523 if (!ipv4addrs(opbuf)) {
2524 warning("Invalid IP address in option: %s", opbuf);
2529 case DHO_NIS_DOMAIN:
2530 case DHO_NISPLUS_DOMAIN:
2531 case DHO_TFTP_SERVER_NAME:
2532 if (!res_hnok(sbuf)) {
2533 warning("Bogus Host Name option %d: %s (%s)", option,
2535 l->options[option].len = 0;
2536 free(l->options[option].data);
2539 case DHO_DOMAIN_NAME:
2540 case DHO_DOMAIN_SEARCH:
2541 if (!res_hnok(sbuf)) {
2542 if (!check_search(sbuf)) {
2543 warning("Bogus domain search list %d: %s (%s)",
2544 option, sbuf, opbuf);
2545 l->options[option].len = 0;
2546 free(l->options[option].data);
2551 case DHO_TIME_OFFSET:
2553 case DHO_MERIT_DUMP:
2555 case DHO_EXTENSIONS_PATH:
2556 case DHO_IP_FORWARDING:
2557 case DHO_NON_LOCAL_SOURCE_ROUTING:
2558 case DHO_POLICY_FILTER:
2559 case DHO_MAX_DGRAM_REASSEMBLY:
2560 case DHO_DEFAULT_IP_TTL:
2561 case DHO_PATH_MTU_AGING_TIMEOUT:
2562 case DHO_PATH_MTU_PLATEAU_TABLE:
2563 case DHO_INTERFACE_MTU:
2564 case DHO_ALL_SUBNETS_LOCAL:
2565 case DHO_PERFORM_MASK_DISCOVERY:
2566 case DHO_MASK_SUPPLIER:
2567 case DHO_ROUTER_DISCOVERY:
2568 case DHO_ROUTER_SOLICITATION_ADDRESS:
2569 case DHO_STATIC_ROUTES:
2570 case DHO_TRAILER_ENCAPSULATION:
2571 case DHO_ARP_CACHE_TIMEOUT:
2572 case DHO_IEEE802_3_ENCAPSULATION:
2573 case DHO_DEFAULT_TCP_TTL:
2574 case DHO_TCP_KEEPALIVE_INTERVAL:
2575 case DHO_TCP_KEEPALIVE_GARBAGE:
2576 case DHO_VENDOR_ENCAPSULATED_OPTIONS:
2577 case DHO_NETBIOS_NODE_TYPE:
2578 case DHO_NETBIOS_SCOPE:
2579 case DHO_X_DISPLAY_MANAGER:
2580 case DHO_DHCP_REQUESTED_ADDRESS:
2581 case DHO_DHCP_LEASE_TIME:
2582 case DHO_DHCP_OPTION_OVERLOAD:
2583 case DHO_DHCP_MESSAGE_TYPE:
2584 case DHO_DHCP_PARAMETER_REQUEST_LIST:
2585 case DHO_DHCP_MESSAGE:
2586 case DHO_DHCP_MAX_MESSAGE_SIZE:
2587 case DHO_DHCP_RENEWAL_TIME:
2588 case DHO_DHCP_REBINDING_TIME:
2589 case DHO_DHCP_CLASS_IDENTIFIER:
2590 case DHO_DHCP_CLIENT_IDENTIFIER:
2591 case DHO_BOOTFILE_NAME:
2592 case DHO_DHCP_USER_CLASS_ID:
2595 case DHO_CLASSLESS_ROUTES:
2596 return (check_classless_option(l->options[option].data,
2597 l->options[option].len));
2599 warning("unknown dhcp option value 0x%x", option);
2600 return (unknown_ok);
2604 /* RFC 3442 The Classless Static Routes option checks */
2606 check_classless_option(unsigned char *data, int len)
2609 unsigned char width;
2610 in_addr_t addr, mask;
2613 warning("Too small length: %d", len);
2621 } else if (width < 9) {
2622 addr = (in_addr_t)(data[i] << 24);
2624 } else if (width < 17) {
2625 addr = (in_addr_t)(data[i] << 24) +
2626 (in_addr_t)(data[i + 1] << 16);
2628 } else if (width < 25) {
2629 addr = (in_addr_t)(data[i] << 24) +
2630 (in_addr_t)(data[i + 1] << 16) +
2631 (in_addr_t)(data[i + 2] << 8);
2633 } else if (width < 33) {
2634 addr = (in_addr_t)(data[i] << 24) +
2635 (in_addr_t)(data[i + 1] << 16) +
2636 (in_addr_t)(data[i + 2] << 8) +
2640 warning("Incorrect subnet width: %d", width);
2643 mask = (in_addr_t)(~0) << (32 - width);
2649 * ... After deriving a subnet number and subnet mask
2650 * from each destination descriptor, the DHCP client
2651 * MUST zero any bits in the subnet number where the
2652 * corresponding bit in the mask is zero...
2654 if ((addr & mask) != addr) {
2656 data[i - 1] = (unsigned char)(
2657 (addr >> (((32 - width)/8)*8)) & 0xFF);
2662 warning("Incorrect data length: %d (must be %d)", len, i);
2669 res_hnok(const char *dn)
2671 int pch = PERIOD, ch = *dn++;
2673 while (ch != '\0') {
2676 if (periodchar(ch)) {
2678 } else if (periodchar(pch)) {
2679 if (!borderchar(ch))
2681 } else if (periodchar(nch) || nch == '\0') {
2682 if (!borderchar(ch))
2685 if (!middlechar(ch))
2694 check_search(const char *srch)
2696 int pch = PERIOD, ch = *srch++;
2699 /* 256 char limit re resolv.conf(5) */
2700 if (strlen(srch) > 256)
2703 while (whitechar(ch))
2706 while (ch != '\0') {
2709 if (periodchar(ch) || whitechar(ch)) {
2711 } else if (periodchar(pch)) {
2712 if (!borderchar(ch))
2714 } else if (periodchar(nch) || nch == '\0') {
2715 if (!borderchar(ch))
2718 if (!middlechar(ch))
2721 if (!whitechar(ch)) {
2724 while (whitechar(nch)) {
2733 /* 6 domain limit re resolv.conf(5) */
2739 /* Does buf consist only of dotted decimal ipv4 addrs?
2740 * return how many if so,
2741 * otherwise, return 0
2744 ipv4addrs(const char * buf)
2749 while (inet_aton(buf, &jnk) == 1){
2751 while (periodchar(*buf) || digitchar(*buf))
2763 option_as_string(unsigned int code, unsigned char *data, int len)
2765 static char optbuf[32768]; /* XXX */
2767 int opleft = sizeof(optbuf);
2768 unsigned char *dp = data;
2771 error("option_as_string: bad code %d", code);
2773 for (; dp < data + len; dp++) {
2774 if (!isascii(*dp) || !isprint(*dp)) {
2775 if (dp + 1 != data + len || *dp != 0) {
2776 snprintf(op, opleft, "\\%03o", *dp);
2780 } else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
2781 *dp == '`' || *dp == '\\') {
2795 warning("dhcp option too large");
2800 fork_privchld(int fd, int fd2)
2802 struct pollfd pfd[1];
2807 error("cannot fork");
2814 setproctitle("%s [priv]", ifi->name);
2817 dup2(nullfd, STDIN_FILENO);
2818 dup2(nullfd, STDOUT_FILENO);
2819 dup2(nullfd, STDERR_FILENO);
2827 pfd[0].events = POLLIN;
2828 if ((nfds = poll(pfd, 1, INFTIM)) == -1)
2830 error("poll error");
2832 if (nfds == 0 || !(pfd[0].revents & POLLIN))
2835 dispatch_imsg(ifi, fd);