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 <sys/capsicum.h>
63 #include <sys/endian.h>
65 #include <net80211/ieee80211_freebsd.h>
67 #ifndef _PATH_VAREMPTY
68 #define _PATH_VAREMPTY "/var/empty"
72 #define hyphenchar(c) ((c) == 0x2d)
73 #define bslashchar(c) ((c) == 0x5c)
74 #define periodchar(c) ((c) == PERIOD)
75 #define asterchar(c) ((c) == 0x2a)
76 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
77 ((c) >= 0x61 && (c) <= 0x7a))
78 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
79 #define whitechar(c) ((c) == ' ' || (c) == '\t')
81 #define borderchar(c) (alphachar(c) || digitchar(c))
82 #define middlechar(c) (borderchar(c) || hyphenchar(c))
83 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
85 #define CLIENT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
88 time_t default_lease_time = 43200; /* 12 hours... */
90 char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
91 char *path_dhclient_db = NULL;
97 char hostname[_POSIX_HOST_NAME_MAX + 1];
99 struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
100 struct in_addr inaddr_any, inaddr_broadcast;
102 char *path_dhclient_pidfile;
103 struct pidfh *pidfile;
106 * ASSERT_STATE() does nothing now; it used to be
107 * assert (state_is == state_shouldbe).
109 #define ASSERT_STATE(state_is, state_shouldbe) {}
111 #define TIME_MAX 2147483647
118 struct interface_info *ifi;
120 int findproto(char *, int);
121 struct sockaddr *get_ifa(char *, int);
122 void routehandler(struct protocol *);
124 int check_option(struct client_lease *l, int option);
125 int check_classless_option(unsigned char *data, int len);
126 int ipv4addrs(char * buf);
127 int res_hnok(const char *dn);
128 int check_search(const char *srch);
129 char *option_as_string(unsigned int code, unsigned char *data, int len);
130 int fork_privchld(int, int);
133 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
134 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
136 /* Minimum MTU is 68 as per RFC791, p. 24 */
139 static time_t scripttime;
142 findproto(char *cp, int n)
149 for (i = 1; i; i <<= 1) {
151 sa = (struct sockaddr *)cp;
157 if (sa->sa_family == AF_INET)
159 if (sa->sa_family == AF_INET6)
172 get_ifa(char *cp, int n)
179 for (i = 1; i; i <<= 1)
181 sa = (struct sockaddr *)cp;
190 struct iaddr defaddr = { 4 };
196 struct interface_info *ifi = arg;
199 * Clear existing state.
201 if (ifi->client->active != NULL) {
202 script_init("EXPIRE", NULL);
203 script_write_params("old_",
204 ifi->client->active);
205 if (ifi->client->alias)
206 script_write_params("alias_",
210 ifi->client->state = S_INIT;
215 routehandler(struct protocol *p)
217 char msg[2048], *addr;
218 struct rt_msghdr *rtm;
219 struct if_msghdr *ifm;
220 struct ifa_msghdr *ifam;
221 struct if_announcemsghdr *ifan;
222 struct ieee80211_join_event *jev;
223 struct client_lease *l;
224 time_t t = time(NULL);
230 n = read(routefd, &msg, sizeof(msg));
231 rtm = (struct rt_msghdr *)msg;
232 if (n < sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen ||
233 rtm->rtm_version != RTM_VERSION)
236 switch (rtm->rtm_type) {
239 ifam = (struct ifa_msghdr *)rtm;
241 if (ifam->ifam_index != ifi->index)
243 if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
245 if (scripttime == 0 || t < scripttime + 10)
248 sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs);
252 if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf))
253 error("king bula sez: len mismatch");
254 memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len);
255 if (addr_eq(a, defaddr))
258 for (l = ifi->client->active; l != NULL; l = l->next)
259 if (addr_eq(a, l->address))
262 if (l == NULL) /* added/deleted addr is not the one we set */
265 addr = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
266 if (rtm->rtm_type == RTM_NEWADDR) {
268 * XXX: If someone other than us adds our address,
269 * should we assume they are taking over from us,
270 * delete the lease record, and exit without modifying
273 warning("My address (%s) was re-added", addr);
275 warning("My address (%s) was deleted, dhclient exiting",
281 ifm = (struct if_msghdr *)rtm;
282 if (ifm->ifm_index != ifi->index)
284 if ((rtm->rtm_flags & RTF_UP) == 0) {
285 warning("Interface %s is down, dhclient exiting",
289 linkstat = interface_link_status(ifi->name);
290 if (linkstat != ifi->linkstat) {
291 debug("%s link state %s -> %s", ifi->name,
292 ifi->linkstat ? "up" : "down",
293 linkstat ? "up" : "down");
294 ifi->linkstat = linkstat;
300 ifan = (struct if_announcemsghdr *)rtm;
301 if (ifan->ifan_what == IFAN_DEPARTURE &&
302 ifan->ifan_index == ifi->index) {
303 warning("Interface %s is gone, dhclient exiting",
309 ifan = (struct if_announcemsghdr *)rtm;
310 if (ifan->ifan_index != ifi->index)
312 switch (ifan->ifan_what) {
313 case RTM_IEEE80211_ASSOC:
314 case RTM_IEEE80211_REASSOC:
316 * Use assoc/reassoc event to kick state machine
317 * in case we roam. Otherwise fall back to the
318 * normal state machine just like a wired network.
320 jev = (struct ieee80211_join_event *) &ifan[1];
321 if (memcmp(curbssid, jev->iev_addr, 6)) {
325 memcpy(curbssid, jev->iev_addr, 6);
335 script_init("FAIL", NULL);
336 if (ifi->client->alias)
337 script_write_params("alias_", ifi->client->alias);
340 pidfile_remove(pidfile);
345 main(int argc, char *argv[])
347 extern char *__progname;
348 int ch, fd, quiet = 0, i = 0;
350 int immediate_daemon = 0;
355 /* Initially, log errors to stderr as well as to syslogd. */
356 openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
357 setlogmask(LOG_UPTO(LOG_DEBUG));
359 while ((ch = getopt(argc, argv, "bc:dl:p:qu")) != -1)
362 immediate_daemon = 1;
365 path_dhclient_conf = optarg;
371 path_dhclient_db = optarg;
374 path_dhclient_pidfile = optarg;
392 if (path_dhclient_pidfile == NULL) {
393 asprintf(&path_dhclient_pidfile,
394 "%sdhclient.%s.pid", _PATH_VARRUN, *argv);
395 if (path_dhclient_pidfile == NULL)
398 pidfile = pidfile_open(path_dhclient_pidfile, 0644, &otherpid);
399 if (pidfile == NULL) {
401 error("dhclient already running, pid: %d.", otherpid);
403 error("dhclient already running.");
404 warning("Cannot open or create pidfile: %m");
407 if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL)
409 if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
410 error("Interface name too long");
411 if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s",
412 _PATH_DHCLIENT_DB, ifi->name) == -1)
421 inaddr_broadcast.s_addr = INADDR_BROADCAST;
422 inaddr_any.s_addr = INADDR_ANY;
426 /* The next bit is potentially very time-consuming, so write out
427 the pidfile right away. We will write it out again with the
428 correct pid after daemonizing. */
430 pidfile_write(pidfile);
432 if (!interface_link_status(ifi->name)) {
433 fprintf(stderr, "%s: no link ...", ifi->name);
436 while (!interface_link_status(ifi->name)) {
437 fprintf(stderr, ".");
440 fprintf(stderr, " giving up\n");
445 fprintf(stderr, " got link\n");
449 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
450 error("cannot open %s: %m", _PATH_DEVNULL);
452 if ((pw = getpwnam("_dhcp")) == NULL) {
453 warning("no such user: _dhcp, falling back to \"nobody\"");
454 if ((pw = getpwnam("nobody")) == NULL)
455 error("no such user: nobody");
459 * Obtain hostname before entering capability mode - it won't be
460 * possible then, as reading kern.hostname is not permitted.
462 if (gethostname(hostname, sizeof(hostname)) < 0)
465 priv_script_init("PREINIT", NULL);
466 if (ifi->client->alias)
467 priv_script_write_params("alias_", ifi->client->alias);
470 /* set up the interface */
471 discover_interfaces(ifi);
473 if (pipe(pipe_fd) == -1)
476 fork_privchld(pipe_fd[0], pipe_fd[1]);
485 cap_rights_init(&rights, CAP_READ, CAP_WRITE);
486 if (cap_rights_limit(privfd, &rights) < 0 && errno != ENOSYS)
487 error("can't limit private descriptor: %m");
489 if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
490 error("can't open and lock %s: %m", path_dhclient_db);
491 read_client_leases();
492 rewrite_client_leases();
495 if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
496 add_protocol("AF_ROUTE", routefd, routehandler, ifi);
497 if (shutdown(routefd, SHUT_WR) < 0)
498 error("can't shutdown route socket: %m");
499 cap_rights_init(&rights, CAP_EVENT, CAP_READ);
500 if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS)
501 error("can't limit route socket: %m");
503 if (chroot(_PATH_VAREMPTY) == -1)
505 if (chdir("/") == -1)
506 error("chdir(\"/\")");
508 if (setgroups(1, &pw->pw_gid) ||
509 setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
510 seteuid(pw->pw_uid) || setuid(pw->pw_uid))
511 error("can't drop privileges: %m");
515 setproctitle("%s", ifi->name);
517 if (cap_enter() < 0 && errno != ENOSYS)
518 error("can't enter capability mode: %m");
520 if (immediate_daemon)
523 ifi->client->state = S_INIT;
526 bootp_packet_handler = do_packet;
537 extern char *__progname;
539 fprintf(stderr, "usage: %s [-bdqu] ", __progname);
540 fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
547 * Each routine is called from the dhclient_state_machine() in one of
549 * -> entering INIT state
550 * -> recvpacket_flag == 0: timeout in this state
551 * -> otherwise: received a packet in this state
553 * Return conditions as handled by dhclient_state_machine():
554 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
555 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
556 * Returns 0: finish the nap which was interrupted for no good reason.
558 * Several per-interface variables are used to keep track of the process:
559 * active_lease: the lease that is being used on the interface
560 * (null pointer if not configured yet).
561 * offered_leases: leases corresponding to DHCPOFFER messages that have
562 * been sent to us by DHCP servers.
563 * acked_leases: leases corresponding to DHCPACK messages that have been
564 * sent to us by DHCP servers.
565 * sendpacket: DHCP packet we're trying to send.
566 * destination: IP address to send sendpacket to
567 * In addition, there are several relevant per-lease variables.
568 * T1_expiry, T2_expiry, lease_expiry: lease milestones
569 * In the active lease, these control the process of renewing the lease;
570 * In leases on the acked_leases list, this simply determines when we
571 * can no longer legitimately use the lease.
575 state_reboot(void *ipp)
577 struct interface_info *ip = ipp;
579 /* If we don't remember an active lease, go straight to INIT. */
580 if (!ip->client->active || ip->client->active->is_bootp) {
585 /* We are in the rebooting state. */
586 ip->client->state = S_REBOOTING;
588 /* make_request doesn't initialize xid because it normally comes
589 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
590 so pick an xid now. */
591 ip->client->xid = arc4random();
593 /* Make a DHCPREQUEST packet, and set appropriate per-interface
595 make_request(ip, ip->client->active);
596 ip->client->destination = iaddr_broadcast;
597 ip->client->first_sending = cur_time;
598 ip->client->interval = ip->client->config->initial_interval;
600 /* Zap the medium list... */
601 ip->client->medium = NULL;
603 /* Send out the first DHCPREQUEST packet. */
608 * Called when a lease has completely expired and we've
609 * been unable to renew it.
612 state_init(void *ipp)
614 struct interface_info *ip = ipp;
616 ASSERT_STATE(state, S_INIT);
618 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
620 make_discover(ip, ip->client->active);
621 ip->client->xid = ip->client->packet.xid;
622 ip->client->destination = iaddr_broadcast;
623 ip->client->state = S_SELECTING;
624 ip->client->first_sending = cur_time;
625 ip->client->interval = ip->client->config->initial_interval;
627 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
633 * state_selecting is called when one or more DHCPOFFER packets
634 * have been received and a configurable period of time has passed.
637 state_selecting(void *ipp)
639 struct interface_info *ip = ipp;
640 struct client_lease *lp, *next, *picked;
642 ASSERT_STATE(state, S_SELECTING);
644 /* Cancel state_selecting and send_discover timeouts, since either
645 one could have got us here. */
646 cancel_timeout(state_selecting, ip);
647 cancel_timeout(send_discover, ip);
649 /* We have received one or more DHCPOFFER packets. Currently,
650 the only criterion by which we judge leases is whether or
651 not we get a response when we arp for them. */
653 for (lp = ip->client->offered_leases; lp; lp = next) {
656 /* Check to see if we got an ARPREPLY for the address
657 in this particular lease. */
659 script_init("ARPCHECK", lp->medium);
660 script_write_params("check_", lp);
662 /* If the ARPCHECK code detects another
663 machine using the offered address, it exits
664 nonzero. We need to send a DHCPDECLINE and
667 make_decline(ip, lp);
675 free_client_lease(lp);
678 ip->client->offered_leases = NULL;
680 /* If we just tossed all the leases we were offered, go back
683 ip->client->state = S_INIT;
688 /* If it was a BOOTREPLY, we can just take the address right now. */
689 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
690 ip->client->new = picked;
692 /* Make up some lease expiry times
693 XXX these should be configurable. */
694 ip->client->new->expiry = cur_time + 12000;
695 ip->client->new->renewal += cur_time + 8000;
696 ip->client->new->rebind += cur_time + 10000;
698 ip->client->state = S_REQUESTING;
700 /* Bind to the address we received. */
705 /* Go to the REQUESTING state. */
706 ip->client->destination = iaddr_broadcast;
707 ip->client->state = S_REQUESTING;
708 ip->client->first_sending = cur_time;
709 ip->client->interval = ip->client->config->initial_interval;
711 /* Make a DHCPREQUEST packet from the lease we picked. */
712 make_request(ip, picked);
713 ip->client->xid = ip->client->packet.xid;
715 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
716 free_client_lease(picked);
718 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
722 /* state_requesting is called when we receive a DHCPACK message after
723 having sent out one or more DHCPREQUEST packets. */
726 dhcpack(struct packet *packet)
728 struct interface_info *ip = packet->interface;
729 struct client_lease *lease;
731 /* If we're not receptive to an offer right now, or if the offer
732 has an unrecognizable transaction id, then just drop it. */
733 if (packet->interface->client->xid != packet->raw->xid ||
734 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
735 (memcmp(packet->interface->hw_address.haddr,
736 packet->raw->chaddr, packet->raw->hlen)))
739 if (ip->client->state != S_REBOOTING &&
740 ip->client->state != S_REQUESTING &&
741 ip->client->state != S_RENEWING &&
742 ip->client->state != S_REBINDING)
745 note("DHCPACK from %s", piaddr(packet->client_addr));
747 lease = packet_to_lease(packet);
749 note("packet_to_lease failed.");
753 ip->client->new = lease;
755 /* Stop resending DHCPREQUEST. */
756 cancel_timeout(send_request, ip);
758 /* Figure out the lease time. */
759 if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
760 ip->client->new->expiry = getULong(
761 ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
763 ip->client->new->expiry = default_lease_time;
764 /* A number that looks negative here is really just very large,
765 because the lease expiry offset is unsigned. */
766 if (ip->client->new->expiry < 0)
767 ip->client->new->expiry = TIME_MAX;
768 /* XXX should be fixed by resetting the client state */
769 if (ip->client->new->expiry < 60)
770 ip->client->new->expiry = 60;
772 /* Take the server-provided renewal time if there is one;
773 otherwise figure it out according to the spec. */
774 if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
775 ip->client->new->renewal = getULong(
776 ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
778 ip->client->new->renewal = ip->client->new->expiry / 2;
780 /* Same deal with the rebind time. */
781 if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
782 ip->client->new->rebind = getULong(
783 ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
785 ip->client->new->rebind = ip->client->new->renewal +
786 ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
788 ip->client->new->expiry += cur_time;
789 /* Lease lengths can never be negative. */
790 if (ip->client->new->expiry < cur_time)
791 ip->client->new->expiry = TIME_MAX;
792 ip->client->new->renewal += cur_time;
793 if (ip->client->new->renewal < cur_time)
794 ip->client->new->renewal = TIME_MAX;
795 ip->client->new->rebind += cur_time;
796 if (ip->client->new->rebind < cur_time)
797 ip->client->new->rebind = TIME_MAX;
803 bind_lease(struct interface_info *ip)
805 struct option_data *opt;
807 /* Remember the medium. */
808 ip->client->new->medium = ip->client->medium;
810 opt = &ip->client->new->options[DHO_INTERFACE_MTU];
811 if (opt->len == sizeof(u_int16_t)) {
812 u_int16_t mtu = be16dec(opt->data);
814 warning("mtu size %u < %d: ignored", (unsigned)mtu, MIN_MTU);
816 interface_set_mtu_unpriv(privfd, mtu);
819 /* Write out the new lease. */
820 write_client_lease(ip, ip->client->new, 0);
822 /* Run the client script with the new parameters. */
823 script_init((ip->client->state == S_REQUESTING ? "BOUND" :
824 (ip->client->state == S_RENEWING ? "RENEW" :
825 (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))),
826 ip->client->new->medium);
827 if (ip->client->active && ip->client->state != S_REBOOTING)
828 script_write_params("old_", ip->client->active);
829 script_write_params("new_", ip->client->new);
830 if (ip->client->alias)
831 script_write_params("alias_", ip->client->alias);
834 /* Replace the old active lease with the new one. */
835 if (ip->client->active)
836 free_client_lease(ip->client->active);
837 ip->client->active = ip->client->new;
838 ip->client->new = NULL;
840 /* Set up a timeout to start the renewal process. */
841 add_timeout(ip->client->active->renewal, state_bound, ip);
843 note("bound to %s -- renewal in %d seconds.",
844 piaddr(ip->client->active->address),
845 (int)(ip->client->active->renewal - cur_time));
846 ip->client->state = S_BOUND;
847 reinitialize_interfaces();
852 * state_bound is called when we've successfully bound to a particular
853 * lease, but the renewal time on that lease has expired. We are
854 * expected to unicast a DHCPREQUEST to the server that gave us our
858 state_bound(void *ipp)
860 struct interface_info *ip = ipp;
862 ASSERT_STATE(state, S_BOUND);
864 /* T1 has expired. */
865 make_request(ip, ip->client->active);
866 ip->client->xid = ip->client->packet.xid;
868 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
869 memcpy(ip->client->destination.iabuf, ip->client->active->
870 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
871 ip->client->destination.len = 4;
873 ip->client->destination = iaddr_broadcast;
875 ip->client->first_sending = cur_time;
876 ip->client->interval = ip->client->config->initial_interval;
877 ip->client->state = S_RENEWING;
879 /* Send the first packet immediately. */
884 bootp(struct packet *packet)
886 struct iaddrlist *ap;
888 if (packet->raw->op != BOOTREPLY)
891 /* If there's a reject list, make sure this packet's sender isn't
893 for (ap = packet->interface->client->config->reject_list;
895 if (addr_eq(packet->client_addr, ap->addr)) {
896 note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
904 dhcp(struct packet *packet)
906 struct iaddrlist *ap;
907 void (*handler)(struct packet *);
910 switch (packet->packet_type) {
927 /* If there's a reject list, make sure this packet's sender isn't
929 for (ap = packet->interface->client->config->reject_list;
931 if (addr_eq(packet->client_addr, ap->addr)) {
932 note("%s from %s rejected.", type, piaddr(ap->addr));
940 dhcpoffer(struct packet *packet)
942 struct interface_info *ip = packet->interface;
943 struct client_lease *lease, *lp;
945 int arp_timeout_needed, stop_selecting;
946 char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
947 "DHCPOFFER" : "BOOTREPLY";
949 /* If we're not receptive to an offer right now, or if the offer
950 has an unrecognizable transaction id, then just drop it. */
951 if (ip->client->state != S_SELECTING ||
952 packet->interface->client->xid != packet->raw->xid ||
953 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
954 (memcmp(packet->interface->hw_address.haddr,
955 packet->raw->chaddr, packet->raw->hlen)))
958 note("%s from %s", name, piaddr(packet->client_addr));
961 /* If this lease doesn't supply the minimum required parameters,
963 for (i = 0; ip->client->config->required_options[i]; i++) {
964 if (!packet->options[ip->client->config->
965 required_options[i]].len) {
966 note("%s isn't satisfactory.", name);
971 /* If we've already seen this lease, don't record it again. */
972 for (lease = ip->client->offered_leases;
973 lease; lease = lease->next) {
974 if (lease->address.len == sizeof(packet->raw->yiaddr) &&
975 !memcmp(lease->address.iabuf,
976 &packet->raw->yiaddr, lease->address.len)) {
977 debug("%s already seen.", name);
982 lease = packet_to_lease(packet);
984 note("packet_to_lease failed.");
988 /* If this lease was acquired through a BOOTREPLY, record that
990 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
993 /* Record the medium under which this lease was offered. */
994 lease->medium = ip->client->medium;
996 /* Send out an ARP Request for the offered IP address. */
997 script_init("ARPSEND", lease->medium);
998 script_write_params("check_", lease);
999 /* If the script can't send an ARP request without waiting,
1000 we'll be waiting when we do the ARPCHECK, so don't wait now. */
1002 arp_timeout_needed = 0;
1004 arp_timeout_needed = 2;
1006 /* Figure out when we're supposed to stop selecting. */
1008 ip->client->first_sending + ip->client->config->select_interval;
1010 /* If this is the lease we asked for, put it at the head of the
1011 list, and don't mess with the arp request timeout. */
1012 if (lease->address.len == ip->client->requested_address.len &&
1013 !memcmp(lease->address.iabuf,
1014 ip->client->requested_address.iabuf,
1015 ip->client->requested_address.len)) {
1016 lease->next = ip->client->offered_leases;
1017 ip->client->offered_leases = lease;
1019 /* If we already have an offer, and arping for this
1020 offer would take us past the selection timeout,
1021 then don't extend the timeout - just hope for the
1023 if (ip->client->offered_leases &&
1024 (cur_time + arp_timeout_needed) > stop_selecting)
1025 arp_timeout_needed = 0;
1027 /* Put the lease at the end of the list. */
1029 if (!ip->client->offered_leases)
1030 ip->client->offered_leases = lease;
1032 for (lp = ip->client->offered_leases; lp->next;
1039 /* If we're supposed to stop selecting before we've had time
1040 to wait for the ARPREPLY, add some delay to wait for
1042 if (stop_selecting - cur_time < arp_timeout_needed)
1043 stop_selecting = cur_time + arp_timeout_needed;
1045 /* If the selecting interval has expired, go immediately to
1046 state_selecting(). Otherwise, time out into
1047 state_selecting at the select interval. */
1048 if (stop_selecting <= 0)
1049 state_selecting(ip);
1051 add_timeout(stop_selecting, state_selecting, ip);
1052 cancel_timeout(send_discover, ip);
1056 /* Allocate a client_lease structure and initialize it from the parameters
1057 in the specified packet. */
1059 struct client_lease *
1060 packet_to_lease(struct packet *packet)
1062 struct client_lease *lease;
1065 lease = malloc(sizeof(struct client_lease));
1068 warning("dhcpoffer: no memory to record lease.");
1072 memset(lease, 0, sizeof(*lease));
1074 /* Copy the lease options. */
1075 for (i = 0; i < 256; i++) {
1076 if (packet->options[i].len) {
1077 lease->options[i].data =
1078 malloc(packet->options[i].len + 1);
1079 if (!lease->options[i].data) {
1080 warning("dhcpoffer: no memory for option %d", i);
1081 free_client_lease(lease);
1084 memcpy(lease->options[i].data,
1085 packet->options[i].data,
1086 packet->options[i].len);
1087 lease->options[i].len =
1088 packet->options[i].len;
1089 lease->options[i].data[lease->options[i].len] =
1092 if (!check_option(lease,i)) {
1093 /* ignore a bogus lease offer */
1094 warning("Invalid lease option - ignoring offer");
1095 free_client_lease(lease);
1101 lease->address.len = sizeof(packet->raw->yiaddr);
1102 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
1104 lease->nextserver.len = sizeof(packet->raw->siaddr);
1105 memcpy(lease->nextserver.iabuf, &packet->raw->siaddr, lease->nextserver.len);
1107 /* If the server name was filled out, copy it.
1108 Do not attempt to validate the server name as a host name.
1109 RFC 2131 merely states that sname is NUL-terminated (which do
1110 do not assume) and that it is the server's host name. Since
1111 the ISC client and server allow arbitrary characters, we do
1113 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1114 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
1115 packet->raw->sname[0]) {
1116 lease->server_name = malloc(DHCP_SNAME_LEN + 1);
1117 if (!lease->server_name) {
1118 warning("dhcpoffer: no memory for server name.");
1119 free_client_lease(lease);
1122 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
1123 lease->server_name[DHCP_SNAME_LEN]='\0';
1126 /* Ditto for the filename. */
1127 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1128 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
1129 packet->raw->file[0]) {
1130 /* Don't count on the NUL terminator. */
1131 lease->filename = malloc(DHCP_FILE_LEN + 1);
1132 if (!lease->filename) {
1133 warning("dhcpoffer: no memory for filename.");
1134 free_client_lease(lease);
1137 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
1138 lease->filename[DHCP_FILE_LEN]='\0';
1144 dhcpnak(struct packet *packet)
1146 struct interface_info *ip = packet->interface;
1148 /* If we're not receptive to an offer right now, or if the offer
1149 has an unrecognizable transaction id, then just drop it. */
1150 if (packet->interface->client->xid != packet->raw->xid ||
1151 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
1152 (memcmp(packet->interface->hw_address.haddr,
1153 packet->raw->chaddr, packet->raw->hlen)))
1156 if (ip->client->state != S_REBOOTING &&
1157 ip->client->state != S_REQUESTING &&
1158 ip->client->state != S_RENEWING &&
1159 ip->client->state != S_REBINDING)
1162 note("DHCPNAK from %s", piaddr(packet->client_addr));
1164 if (!ip->client->active) {
1165 note("DHCPNAK with no active lease.\n");
1169 free_client_lease(ip->client->active);
1170 ip->client->active = NULL;
1172 /* Stop sending DHCPREQUEST packets... */
1173 cancel_timeout(send_request, ip);
1175 ip->client->state = S_INIT;
1179 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1180 one after the right interval has expired. If we don't get an offer by
1181 the time we reach the panic interval, call the panic function. */
1184 send_discover(void *ipp)
1186 struct interface_info *ip = ipp;
1187 int interval, increase = 1;
1189 /* Figure out how long it's been since we started transmitting. */
1190 interval = cur_time - ip->client->first_sending;
1192 /* If we're past the panic timeout, call the script and tell it
1193 we haven't found anything for this interface yet. */
1194 if (interval > ip->client->config->timeout) {
1199 /* If we're selecting media, try the whole list before doing
1200 the exponential backoff, but if we've already received an
1201 offer, stop looping, because we obviously have it right. */
1202 if (!ip->client->offered_leases &&
1203 ip->client->config->media) {
1206 if (ip->client->medium) {
1207 ip->client->medium = ip->client->medium->next;
1210 if (!ip->client->medium) {
1212 error("No valid media types for %s!", ip->name);
1213 ip->client->medium = ip->client->config->media;
1217 note("Trying medium \"%s\" %d", ip->client->medium->string,
1219 script_init("MEDIUM", ip->client->medium);
1225 * If we're supposed to increase the interval, do so. If it's
1226 * currently zero (i.e., we haven't sent any packets yet), set
1227 * it to one; otherwise, add to it a random number between zero
1228 * and two times itself. On average, this means that it will
1229 * double with every transmission.
1232 if (!ip->client->interval)
1233 ip->client->interval =
1234 ip->client->config->initial_interval;
1236 ip->client->interval += (arc4random() >> 2) %
1237 (2 * ip->client->interval);
1240 /* Don't backoff past cutoff. */
1241 if (ip->client->interval >
1242 ip->client->config->backoff_cutoff)
1243 ip->client->interval =
1244 ((ip->client->config->backoff_cutoff / 2)
1245 + ((arc4random() >> 2) %
1246 ip->client->config->backoff_cutoff));
1247 } else if (!ip->client->interval)
1248 ip->client->interval =
1249 ip->client->config->initial_interval;
1251 /* If the backoff would take us to the panic timeout, just use that
1253 if (cur_time + ip->client->interval >
1254 ip->client->first_sending + ip->client->config->timeout)
1255 ip->client->interval =
1256 (ip->client->first_sending +
1257 ip->client->config->timeout) - cur_time + 1;
1259 /* Record the number of seconds since we started sending. */
1260 if (interval < 65536)
1261 ip->client->packet.secs = htons(interval);
1263 ip->client->packet.secs = htons(65535);
1264 ip->client->secs = ip->client->packet.secs;
1266 note("DHCPDISCOVER on %s to %s port %d interval %d",
1267 ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT,
1268 (int)ip->client->interval);
1270 /* Send out a packet. */
1271 send_packet_unpriv(privfd, &ip->client->packet,
1272 ip->client->packet_length, inaddr_any, inaddr_broadcast);
1274 add_timeout(cur_time + ip->client->interval, send_discover, ip);
1278 * state_panic gets called if we haven't received any offers in a preset
1279 * amount of time. When this happens, we try to use existing leases
1280 * that haven't yet expired, and failing that, we call the client script
1281 * and hope it can do something.
1284 state_panic(void *ipp)
1286 struct interface_info *ip = ipp;
1287 struct client_lease *loop = ip->client->active;
1288 struct client_lease *lp;
1290 note("No DHCPOFFERS received.");
1292 /* We may not have an active lease, but we may have some
1293 predefined leases that we can try. */
1294 if (!ip->client->active && ip->client->leases)
1297 /* Run through the list of leases and see if one can be used. */
1298 while (ip->client->active) {
1299 if (ip->client->active->expiry > cur_time) {
1300 note("Trying recorded lease %s",
1301 piaddr(ip->client->active->address));
1302 /* Run the client script with the existing
1304 script_init("TIMEOUT",
1305 ip->client->active->medium);
1306 script_write_params("new_", ip->client->active);
1307 if (ip->client->alias)
1308 script_write_params("alias_",
1311 /* If the old lease is still good and doesn't
1312 yet need renewal, go into BOUND state and
1313 timeout at the renewal time. */
1316 ip->client->active->renewal) {
1317 ip->client->state = S_BOUND;
1318 note("bound: renewal in %d seconds.",
1319 (int)(ip->client->active->renewal -
1322 ip->client->active->renewal,
1325 ip->client->state = S_BOUND;
1326 note("bound: immediate renewal.");
1329 reinitialize_interfaces();
1335 /* If there are no other leases, give up. */
1336 if (!ip->client->leases) {
1337 ip->client->leases = ip->client->active;
1338 ip->client->active = NULL;
1343 /* Otherwise, put the active lease at the end of the
1344 lease list, and try another lease.. */
1345 for (lp = ip->client->leases; lp->next; lp = lp->next)
1347 lp->next = ip->client->active;
1349 lp->next->next = NULL;
1350 ip->client->active = ip->client->leases;
1351 ip->client->leases = ip->client->leases->next;
1353 /* If we already tried this lease, we've exhausted the
1354 set of leases, so we might as well give up for
1356 if (ip->client->active == loop)
1359 loop = ip->client->active;
1362 /* No leases were available, or what was available didn't work, so
1363 tell the shell script that we failed to allocate an address,
1364 and try again later. */
1365 note("No working leases in persistent database - sleeping.\n");
1366 script_init("FAIL", NULL);
1367 if (ip->client->alias)
1368 script_write_params("alias_", ip->client->alias);
1370 ip->client->state = S_INIT;
1371 add_timeout(cur_time + ip->client->config->retry_interval, state_init,
1377 send_request(void *ipp)
1379 struct interface_info *ip = ipp;
1380 struct in_addr from, to;
1383 /* Figure out how long it's been since we started transmitting. */
1384 interval = cur_time - ip->client->first_sending;
1386 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1387 past the reboot timeout, go to INIT and see if we can
1388 DISCOVER an address... */
1389 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1390 means either that we're on a network with no DHCP server,
1391 or that our server is down. In the latter case, assuming
1392 that there is a backup DHCP server, DHCPDISCOVER will get
1393 us a new address, but we could also have successfully
1394 reused our old address. In the former case, we're hosed
1395 anyway. This is not a win-prone situation. */
1396 if ((ip->client->state == S_REBOOTING ||
1397 ip->client->state == S_REQUESTING) &&
1398 interval > ip->client->config->reboot_timeout) {
1400 ip->client->state = S_INIT;
1401 cancel_timeout(send_request, ip);
1406 /* If we're in the reboot state, make sure the media is set up
1408 if (ip->client->state == S_REBOOTING &&
1409 !ip->client->medium &&
1410 ip->client->active->medium ) {
1411 script_init("MEDIUM", ip->client->active->medium);
1413 /* If the medium we chose won't fly, go to INIT state. */
1417 /* Record the medium. */
1418 ip->client->medium = ip->client->active->medium;
1421 /* If the lease has expired, relinquish the address and go back
1422 to the INIT state. */
1423 if (ip->client->state != S_REQUESTING &&
1424 cur_time > ip->client->active->expiry) {
1425 /* Run the client script with the new parameters. */
1426 script_init("EXPIRE", NULL);
1427 script_write_params("old_", ip->client->active);
1428 if (ip->client->alias)
1429 script_write_params("alias_", ip->client->alias);
1432 /* Now do a preinit on the interface so that we can
1433 discover a new address. */
1434 script_init("PREINIT", NULL);
1435 if (ip->client->alias)
1436 script_write_params("alias_", ip->client->alias);
1439 ip->client->state = S_INIT;
1444 /* Do the exponential backoff... */
1445 if (!ip->client->interval)
1446 ip->client->interval = ip->client->config->initial_interval;
1448 ip->client->interval += ((arc4random() >> 2) %
1449 (2 * ip->client->interval));
1451 /* Don't backoff past cutoff. */
1452 if (ip->client->interval >
1453 ip->client->config->backoff_cutoff)
1454 ip->client->interval =
1455 ((ip->client->config->backoff_cutoff / 2) +
1456 ((arc4random() >> 2) % ip->client->interval));
1458 /* If the backoff would take us to the expiry time, just set the
1459 timeout to the expiry time. */
1460 if (ip->client->state != S_REQUESTING &&
1461 cur_time + ip->client->interval >
1462 ip->client->active->expiry)
1463 ip->client->interval =
1464 ip->client->active->expiry - cur_time + 1;
1466 /* If the lease T2 time has elapsed, or if we're not yet bound,
1467 broadcast the DHCPREQUEST rather than unicasting. */
1468 if (ip->client->state == S_REQUESTING ||
1469 ip->client->state == S_REBOOTING ||
1470 cur_time > ip->client->active->rebind)
1471 to.s_addr = INADDR_BROADCAST;
1473 memcpy(&to.s_addr, ip->client->destination.iabuf,
1476 if (ip->client->state != S_REQUESTING)
1477 memcpy(&from, ip->client->active->address.iabuf,
1480 from.s_addr = INADDR_ANY;
1482 /* Record the number of seconds since we started sending. */
1483 if (ip->client->state == S_REQUESTING)
1484 ip->client->packet.secs = ip->client->secs;
1486 if (interval < 65536)
1487 ip->client->packet.secs = htons(interval);
1489 ip->client->packet.secs = htons(65535);
1492 note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to),
1495 /* Send out a packet. */
1496 send_packet_unpriv(privfd, &ip->client->packet,
1497 ip->client->packet_length, from, to);
1499 add_timeout(cur_time + ip->client->interval, send_request, ip);
1503 send_decline(void *ipp)
1505 struct interface_info *ip = ipp;
1507 note("DHCPDECLINE on %s to %s port %d", ip->name,
1508 inet_ntoa(inaddr_broadcast), REMOTE_PORT);
1510 /* Send out a packet. */
1511 send_packet_unpriv(privfd, &ip->client->packet,
1512 ip->client->packet_length, inaddr_any, inaddr_broadcast);
1516 make_discover(struct interface_info *ip, struct client_lease *lease)
1518 unsigned char discover = DHCPDISCOVER;
1519 struct tree_cache *options[256];
1520 struct tree_cache option_elements[256];
1523 memset(option_elements, 0, sizeof(option_elements));
1524 memset(options, 0, sizeof(options));
1525 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1527 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1528 i = DHO_DHCP_MESSAGE_TYPE;
1529 options[i] = &option_elements[i];
1530 options[i]->value = &discover;
1531 options[i]->len = sizeof(discover);
1532 options[i]->buf_size = sizeof(discover);
1533 options[i]->timeout = 0xFFFFFFFF;
1535 /* Request the options we want */
1536 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1537 options[i] = &option_elements[i];
1538 options[i]->value = ip->client->config->requested_options;
1539 options[i]->len = ip->client->config->requested_option_count;
1540 options[i]->buf_size =
1541 ip->client->config->requested_option_count;
1542 options[i]->timeout = 0xFFFFFFFF;
1544 /* If we had an address, try to get it again. */
1546 ip->client->requested_address = lease->address;
1547 i = DHO_DHCP_REQUESTED_ADDRESS;
1548 options[i] = &option_elements[i];
1549 options[i]->value = lease->address.iabuf;
1550 options[i]->len = lease->address.len;
1551 options[i]->buf_size = lease->address.len;
1552 options[i]->timeout = 0xFFFFFFFF;
1554 ip->client->requested_address.len = 0;
1556 /* Send any options requested in the config file. */
1557 for (i = 0; i < 256; i++)
1559 ip->client->config->send_options[i].data) {
1560 options[i] = &option_elements[i];
1562 ip->client->config->send_options[i].data;
1564 ip->client->config->send_options[i].len;
1565 options[i]->buf_size =
1566 ip->client->config->send_options[i].len;
1567 options[i]->timeout = 0xFFFFFFFF;
1570 /* send host name if not set via config file. */
1571 if (!options[DHO_HOST_NAME]) {
1572 if (hostname[0] != '\0') {
1574 char* posDot = strchr(hostname, '.');
1576 len = posDot - hostname;
1578 len = strlen(hostname);
1579 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1580 options[DHO_HOST_NAME]->value = hostname;
1581 options[DHO_HOST_NAME]->len = len;
1582 options[DHO_HOST_NAME]->buf_size = len;
1583 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1587 /* set unique client identifier */
1588 char client_ident[sizeof(ip->hw_address.haddr) + 1];
1589 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1590 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1591 ip->hw_address.hlen : sizeof(client_ident)-1;
1592 client_ident[0] = ip->hw_address.htype;
1593 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1594 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1595 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1596 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1597 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1598 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1601 /* Set up the option buffer... */
1602 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1603 options, 0, 0, 0, NULL, 0);
1604 if (ip->client->packet_length < BOOTP_MIN_LEN)
1605 ip->client->packet_length = BOOTP_MIN_LEN;
1607 ip->client->packet.op = BOOTREQUEST;
1608 ip->client->packet.htype = ip->hw_address.htype;
1609 ip->client->packet.hlen = ip->hw_address.hlen;
1610 ip->client->packet.hops = 0;
1611 ip->client->packet.xid = arc4random();
1612 ip->client->packet.secs = 0; /* filled in by send_discover. */
1613 ip->client->packet.flags = 0;
1615 memset(&(ip->client->packet.ciaddr),
1616 0, sizeof(ip->client->packet.ciaddr));
1617 memset(&(ip->client->packet.yiaddr),
1618 0, sizeof(ip->client->packet.yiaddr));
1619 memset(&(ip->client->packet.siaddr),
1620 0, sizeof(ip->client->packet.siaddr));
1621 memset(&(ip->client->packet.giaddr),
1622 0, sizeof(ip->client->packet.giaddr));
1623 memcpy(ip->client->packet.chaddr,
1624 ip->hw_address.haddr, ip->hw_address.hlen);
1629 make_request(struct interface_info *ip, struct client_lease * lease)
1631 unsigned char request = DHCPREQUEST;
1632 struct tree_cache *options[256];
1633 struct tree_cache option_elements[256];
1636 memset(options, 0, sizeof(options));
1637 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1639 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1640 i = DHO_DHCP_MESSAGE_TYPE;
1641 options[i] = &option_elements[i];
1642 options[i]->value = &request;
1643 options[i]->len = sizeof(request);
1644 options[i]->buf_size = sizeof(request);
1645 options[i]->timeout = 0xFFFFFFFF;
1647 /* Request the options we want */
1648 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1649 options[i] = &option_elements[i];
1650 options[i]->value = ip->client->config->requested_options;
1651 options[i]->len = ip->client->config->requested_option_count;
1652 options[i]->buf_size =
1653 ip->client->config->requested_option_count;
1654 options[i]->timeout = 0xFFFFFFFF;
1656 /* If we are requesting an address that hasn't yet been assigned
1657 to us, use the DHCP Requested Address option. */
1658 if (ip->client->state == S_REQUESTING) {
1659 /* Send back the server identifier... */
1660 i = DHO_DHCP_SERVER_IDENTIFIER;
1661 options[i] = &option_elements[i];
1662 options[i]->value = lease->options[i].data;
1663 options[i]->len = lease->options[i].len;
1664 options[i]->buf_size = lease->options[i].len;
1665 options[i]->timeout = 0xFFFFFFFF;
1667 if (ip->client->state == S_REQUESTING ||
1668 ip->client->state == S_REBOOTING) {
1669 ip->client->requested_address = lease->address;
1670 i = DHO_DHCP_REQUESTED_ADDRESS;
1671 options[i] = &option_elements[i];
1672 options[i]->value = lease->address.iabuf;
1673 options[i]->len = lease->address.len;
1674 options[i]->buf_size = lease->address.len;
1675 options[i]->timeout = 0xFFFFFFFF;
1677 ip->client->requested_address.len = 0;
1679 /* Send any options requested in the config file. */
1680 for (i = 0; i < 256; i++)
1682 ip->client->config->send_options[i].data) {
1683 options[i] = &option_elements[i];
1685 ip->client->config->send_options[i].data;
1687 ip->client->config->send_options[i].len;
1688 options[i]->buf_size =
1689 ip->client->config->send_options[i].len;
1690 options[i]->timeout = 0xFFFFFFFF;
1693 /* send host name if not set via config file. */
1694 if (!options[DHO_HOST_NAME]) {
1695 if (hostname[0] != '\0') {
1697 char* posDot = strchr(hostname, '.');
1699 len = posDot - hostname;
1701 len = strlen(hostname);
1702 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1703 options[DHO_HOST_NAME]->value = hostname;
1704 options[DHO_HOST_NAME]->len = len;
1705 options[DHO_HOST_NAME]->buf_size = len;
1706 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1710 /* set unique client identifier */
1711 char client_ident[sizeof(struct hardware)];
1712 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1713 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1714 ip->hw_address.hlen : sizeof(client_ident)-1;
1715 client_ident[0] = ip->hw_address.htype;
1716 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1717 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1718 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1719 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1720 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1721 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1724 /* Set up the option buffer... */
1725 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1726 options, 0, 0, 0, NULL, 0);
1727 if (ip->client->packet_length < BOOTP_MIN_LEN)
1728 ip->client->packet_length = BOOTP_MIN_LEN;
1730 ip->client->packet.op = BOOTREQUEST;
1731 ip->client->packet.htype = ip->hw_address.htype;
1732 ip->client->packet.hlen = ip->hw_address.hlen;
1733 ip->client->packet.hops = 0;
1734 ip->client->packet.xid = ip->client->xid;
1735 ip->client->packet.secs = 0; /* Filled in by send_request. */
1737 /* If we own the address we're requesting, put it in ciaddr;
1738 otherwise set ciaddr to zero. */
1739 if (ip->client->state == S_BOUND ||
1740 ip->client->state == S_RENEWING ||
1741 ip->client->state == S_REBINDING) {
1742 memcpy(&ip->client->packet.ciaddr,
1743 lease->address.iabuf, lease->address.len);
1744 ip->client->packet.flags = 0;
1746 memset(&ip->client->packet.ciaddr, 0,
1747 sizeof(ip->client->packet.ciaddr));
1748 ip->client->packet.flags = 0;
1751 memset(&ip->client->packet.yiaddr, 0,
1752 sizeof(ip->client->packet.yiaddr));
1753 memset(&ip->client->packet.siaddr, 0,
1754 sizeof(ip->client->packet.siaddr));
1755 memset(&ip->client->packet.giaddr, 0,
1756 sizeof(ip->client->packet.giaddr));
1757 memcpy(ip->client->packet.chaddr,
1758 ip->hw_address.haddr, ip->hw_address.hlen);
1762 make_decline(struct interface_info *ip, struct client_lease *lease)
1764 struct tree_cache *options[256], message_type_tree;
1765 struct tree_cache requested_address_tree;
1766 struct tree_cache server_id_tree, client_id_tree;
1767 unsigned char decline = DHCPDECLINE;
1770 memset(options, 0, sizeof(options));
1771 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1773 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1774 i = DHO_DHCP_MESSAGE_TYPE;
1775 options[i] = &message_type_tree;
1776 options[i]->value = &decline;
1777 options[i]->len = sizeof(decline);
1778 options[i]->buf_size = sizeof(decline);
1779 options[i]->timeout = 0xFFFFFFFF;
1781 /* Send back the server identifier... */
1782 i = DHO_DHCP_SERVER_IDENTIFIER;
1783 options[i] = &server_id_tree;
1784 options[i]->value = lease->options[i].data;
1785 options[i]->len = lease->options[i].len;
1786 options[i]->buf_size = lease->options[i].len;
1787 options[i]->timeout = 0xFFFFFFFF;
1789 /* Send back the address we're declining. */
1790 i = DHO_DHCP_REQUESTED_ADDRESS;
1791 options[i] = &requested_address_tree;
1792 options[i]->value = lease->address.iabuf;
1793 options[i]->len = lease->address.len;
1794 options[i]->buf_size = lease->address.len;
1795 options[i]->timeout = 0xFFFFFFFF;
1797 /* Send the uid if the user supplied one. */
1798 i = DHO_DHCP_CLIENT_IDENTIFIER;
1799 if (ip->client->config->send_options[i].len) {
1800 options[i] = &client_id_tree;
1801 options[i]->value = ip->client->config->send_options[i].data;
1802 options[i]->len = ip->client->config->send_options[i].len;
1803 options[i]->buf_size = ip->client->config->send_options[i].len;
1804 options[i]->timeout = 0xFFFFFFFF;
1808 /* Set up the option buffer... */
1809 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1810 options, 0, 0, 0, NULL, 0);
1811 if (ip->client->packet_length < BOOTP_MIN_LEN)
1812 ip->client->packet_length = BOOTP_MIN_LEN;
1814 ip->client->packet.op = BOOTREQUEST;
1815 ip->client->packet.htype = ip->hw_address.htype;
1816 ip->client->packet.hlen = ip->hw_address.hlen;
1817 ip->client->packet.hops = 0;
1818 ip->client->packet.xid = ip->client->xid;
1819 ip->client->packet.secs = 0; /* Filled in by send_request. */
1820 ip->client->packet.flags = 0;
1822 /* ciaddr must always be zero. */
1823 memset(&ip->client->packet.ciaddr, 0,
1824 sizeof(ip->client->packet.ciaddr));
1825 memset(&ip->client->packet.yiaddr, 0,
1826 sizeof(ip->client->packet.yiaddr));
1827 memset(&ip->client->packet.siaddr, 0,
1828 sizeof(ip->client->packet.siaddr));
1829 memset(&ip->client->packet.giaddr, 0,
1830 sizeof(ip->client->packet.giaddr));
1831 memcpy(ip->client->packet.chaddr,
1832 ip->hw_address.haddr, ip->hw_address.hlen);
1836 free_client_lease(struct client_lease *lease)
1840 if (lease->server_name)
1841 free(lease->server_name);
1842 if (lease->filename)
1843 free(lease->filename);
1844 for (i = 0; i < 256; i++) {
1845 if (lease->options[i].len)
1846 free(lease->options[i].data);
1854 rewrite_client_leases(void)
1856 struct client_lease *lp;
1857 cap_rights_t rights;
1860 leaseFile = fopen(path_dhclient_db, "w");
1862 error("can't create %s: %m", path_dhclient_db);
1863 cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_FSYNC,
1864 CAP_FTRUNCATE, CAP_SEEK, CAP_WRITE);
1865 if (cap_rights_limit(fileno(leaseFile), &rights) < 0 &&
1867 error("can't limit lease descriptor: %m");
1869 if (cap_fcntls_limit(fileno(leaseFile), CAP_FCNTL_GETFL) < 0 &&
1871 error("can't limit lease descriptor fcntls: %m");
1878 for (lp = ifi->client->leases; lp; lp = lp->next)
1879 write_client_lease(ifi, lp, 1);
1880 if (ifi->client->active)
1881 write_client_lease(ifi, ifi->client->active, 1);
1884 ftruncate(fileno(leaseFile), ftello(leaseFile));
1885 fsync(fileno(leaseFile));
1889 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1892 static int leases_written;
1897 if (leases_written++ > 20) {
1898 rewrite_client_leases();
1903 /* If the lease came from the config file, we don't need to stash
1904 a copy in the lease database. */
1905 if (lease->is_static)
1908 if (!leaseFile) { /* XXX */
1909 leaseFile = fopen(path_dhclient_db, "w");
1911 error("can't create %s: %m", path_dhclient_db);
1914 fprintf(leaseFile, "lease {\n");
1915 if (lease->is_bootp)
1916 fprintf(leaseFile, " bootp;\n");
1917 fprintf(leaseFile, " interface \"%s\";\n", ip->name);
1918 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
1919 if (lease->nextserver.len == sizeof(inaddr_any) &&
1920 0 != memcmp(lease->nextserver.iabuf, &inaddr_any,
1921 sizeof(inaddr_any)))
1922 fprintf(leaseFile, " next-server %s;\n",
1923 piaddr(lease->nextserver));
1924 if (lease->filename)
1925 fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
1926 if (lease->server_name)
1927 fprintf(leaseFile, " server-name \"%s\";\n",
1928 lease->server_name);
1930 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string);
1931 for (i = 0; i < 256; i++)
1932 if (lease->options[i].len)
1933 fprintf(leaseFile, " option %s %s;\n",
1934 dhcp_options[i].name,
1935 pretty_print_option(i, lease->options[i].data,
1936 lease->options[i].len, 1, 1));
1938 t = gmtime(&lease->renewal);
1939 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1940 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1941 t->tm_hour, t->tm_min, t->tm_sec);
1942 t = gmtime(&lease->rebind);
1943 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1944 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1945 t->tm_hour, t->tm_min, t->tm_sec);
1946 t = gmtime(&lease->expiry);
1947 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1948 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1949 t->tm_hour, t->tm_min, t->tm_sec);
1950 fprintf(leaseFile, "}\n");
1955 script_init(char *reason, struct string_list *medium)
1957 size_t len, mediumlen = 0;
1958 struct imsg_hdr hdr;
1962 if (medium != NULL && medium->string != NULL)
1963 mediumlen = strlen(medium->string);
1965 hdr.code = IMSG_SCRIPT_INIT;
1966 hdr.len = sizeof(struct imsg_hdr) +
1967 sizeof(size_t) + mediumlen +
1968 sizeof(size_t) + strlen(reason);
1970 if ((buf = buf_open(hdr.len)) == NULL)
1971 error("buf_open: %m");
1974 errs += buf_add(buf, &hdr, sizeof(hdr));
1975 errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
1977 errs += buf_add(buf, medium->string, mediumlen);
1978 len = strlen(reason);
1979 errs += buf_add(buf, &len, sizeof(len));
1980 errs += buf_add(buf, reason, len);
1983 error("buf_add: %m");
1985 if (buf_close(privfd, buf) == -1)
1986 error("buf_close: %m");
1990 priv_script_init(char *reason, char *medium)
1992 struct interface_info *ip = ifi;
1995 ip->client->scriptEnvsize = 100;
1996 if (ip->client->scriptEnv == NULL)
1997 ip->client->scriptEnv =
1998 malloc(ip->client->scriptEnvsize * sizeof(char *));
1999 if (ip->client->scriptEnv == NULL)
2000 error("script_init: no memory for environment");
2002 ip->client->scriptEnv[0] = strdup(CLIENT_PATH);
2003 if (ip->client->scriptEnv[0] == NULL)
2004 error("script_init: no memory for environment");
2006 ip->client->scriptEnv[1] = NULL;
2008 script_set_env(ip->client, "", "interface", ip->name);
2011 script_set_env(ip->client, "", "medium", medium);
2013 script_set_env(ip->client, "", "reason", reason);
2018 priv_script_write_params(char *prefix, struct client_lease *lease)
2020 struct interface_info *ip = ifi;
2021 u_int8_t dbuf[1500], *dp = NULL;
2025 script_set_env(ip->client, prefix, "ip_address",
2026 piaddr(lease->address));
2028 if (ip->client->config->default_actions[DHO_SUBNET_MASK] ==
2030 dp = ip->client->config->defaults[DHO_SUBNET_MASK].data;
2031 len = ip->client->config->defaults[DHO_SUBNET_MASK].len;
2033 dp = lease->options[DHO_SUBNET_MASK].data;
2034 len = lease->options[DHO_SUBNET_MASK].len;
2036 if (len && (len < sizeof(lease->address.iabuf))) {
2037 struct iaddr netmask, subnet, broadcast;
2039 memcpy(netmask.iabuf, dp, len);
2041 subnet = subnet_number(lease->address, netmask);
2043 script_set_env(ip->client, prefix, "network_number",
2045 if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
2046 broadcast = broadcast_addr(subnet, netmask);
2048 script_set_env(ip->client, prefix,
2049 "broadcast_address",
2055 if (lease->filename)
2056 script_set_env(ip->client, prefix, "filename", lease->filename);
2057 if (lease->server_name)
2058 script_set_env(ip->client, prefix, "server_name",
2059 lease->server_name);
2060 for (i = 0; i < 256; i++) {
2063 if (ip->client->config->defaults[i].len) {
2064 if (lease->options[i].len) {
2066 ip->client->config->default_actions[i]) {
2067 case ACTION_DEFAULT:
2068 dp = lease->options[i].data;
2069 len = lease->options[i].len;
2071 case ACTION_SUPERSEDE:
2074 config->defaults[i].data;
2076 config->defaults[i].len;
2078 case ACTION_PREPEND:
2080 config->defaults[i].len +
2081 lease->options[i].len;
2082 if (len >= sizeof(dbuf)) {
2083 warning("no space to %s %s",
2085 dhcp_options[i].name);
2091 config->defaults[i].data,
2093 config->defaults[i].len);
2094 memcpy(dp + ip->client->
2095 config->defaults[i].len,
2096 lease->options[i].data,
2097 lease->options[i].len);
2102 * When we append, we assume that we're
2103 * appending to text. Some MS servers
2104 * include a NUL byte at the end of
2105 * the search string provided.
2108 config->defaults[i].len +
2109 lease->options[i].len;
2110 if (len >= sizeof(dbuf)) {
2111 warning("no space to %s %s",
2113 dhcp_options[i].name);
2117 lease->options[i].data,
2118 lease->options[i].len);
2119 for (dp = dbuf + lease->options[i].len;
2120 dp > dbuf; dp--, len--)
2125 config->defaults[i].data,
2127 config->defaults[i].len);
2133 config->defaults[i].data;
2135 config->defaults[i].len;
2137 } else if (lease->options[i].len) {
2138 len = lease->options[i].len;
2139 dp = lease->options[i].data;
2146 if (dhcp_option_ev_name(name, sizeof(name),
2148 script_set_env(ip->client, prefix, name,
2149 pretty_print_option(i, dp, len, 0, 0));
2152 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
2153 script_set_env(ip->client, prefix, "expiry", tbuf);
2157 script_write_params(char *prefix, struct client_lease *lease)
2159 size_t fn_len = 0, sn_len = 0, pr_len = 0;
2160 struct imsg_hdr hdr;
2164 if (lease->filename != NULL)
2165 fn_len = strlen(lease->filename);
2166 if (lease->server_name != NULL)
2167 sn_len = strlen(lease->server_name);
2169 pr_len = strlen(prefix);
2171 hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
2172 hdr.len = sizeof(hdr) + sizeof(struct client_lease) +
2173 sizeof(size_t) + fn_len + sizeof(size_t) + sn_len +
2174 sizeof(size_t) + pr_len;
2176 for (i = 0; i < 256; i++)
2177 hdr.len += sizeof(int) + lease->options[i].len;
2179 scripttime = time(NULL);
2181 if ((buf = buf_open(hdr.len)) == NULL)
2182 error("buf_open: %m");
2185 errs += buf_add(buf, &hdr, sizeof(hdr));
2186 errs += buf_add(buf, lease, sizeof(struct client_lease));
2187 errs += buf_add(buf, &fn_len, sizeof(fn_len));
2188 errs += buf_add(buf, lease->filename, fn_len);
2189 errs += buf_add(buf, &sn_len, sizeof(sn_len));
2190 errs += buf_add(buf, lease->server_name, sn_len);
2191 errs += buf_add(buf, &pr_len, sizeof(pr_len));
2192 errs += buf_add(buf, prefix, pr_len);
2194 for (i = 0; i < 256; i++) {
2195 errs += buf_add(buf, &lease->options[i].len,
2196 sizeof(lease->options[i].len));
2197 errs += buf_add(buf, lease->options[i].data,
2198 lease->options[i].len);
2202 error("buf_add: %m");
2204 if (buf_close(privfd, buf) == -1)
2205 error("buf_close: %m");
2211 struct imsg_hdr hdr;
2215 hdr.code = IMSG_SCRIPT_GO;
2216 hdr.len = sizeof(struct imsg_hdr);
2218 if ((buf = buf_open(hdr.len)) == NULL)
2219 error("buf_open: %m");
2221 if (buf_add(buf, &hdr, sizeof(hdr)))
2222 error("buf_add: %m");
2224 if (buf_close(privfd, buf) == -1)
2225 error("buf_close: %m");
2227 bzero(&hdr, sizeof(hdr));
2228 buf_read(privfd, &hdr, sizeof(hdr));
2229 if (hdr.code != IMSG_SCRIPT_GO_RET)
2230 error("unexpected msg type %u", hdr.code);
2231 if (hdr.len != sizeof(hdr) + sizeof(int))
2232 error("received corrupted message");
2233 buf_read(privfd, &ret, sizeof(ret));
2235 scripttime = time(NULL);
2241 priv_script_go(void)
2243 char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI";
2244 static char client_path[] = CLIENT_PATH;
2245 struct interface_info *ip = ifi;
2246 int pid, wpid, wstatus;
2248 scripttime = time(NULL);
2251 scriptName = ip->client->config->script_name;
2252 envp = ip->client->scriptEnv;
2254 scriptName = top_level_config.script_name;
2256 epp[1] = client_path;
2261 argv[0] = scriptName;
2270 wpid = wait(&wstatus);
2271 } while (wpid != pid && wpid > 0);
2277 execve(scriptName, argv, envp);
2278 error("execve (%s, ...): %m", scriptName);
2282 script_flush_env(ip->client);
2284 return (wstatus & 0xff);
2288 script_set_env(struct client_state *client, const char *prefix,
2289 const char *name, const char *value)
2293 /* No `` or $() command substitution allowed in environment values! */
2294 for (j=0; j < strlen(value); j++)
2298 warning("illegal character (%c) in value '%s'",
2300 /* Ignore this option */
2304 namelen = strlen(name);
2306 for (i = 0; client->scriptEnv[i]; i++)
2307 if (strncmp(client->scriptEnv[i], name, namelen) == 0 &&
2308 client->scriptEnv[i][namelen] == '=')
2311 if (client->scriptEnv[i])
2312 /* Reuse the slot. */
2313 free(client->scriptEnv[i]);
2315 /* New variable. Expand if necessary. */
2316 if (i >= client->scriptEnvsize - 1) {
2317 char **newscriptEnv;
2318 int newscriptEnvsize = client->scriptEnvsize + 50;
2320 newscriptEnv = realloc(client->scriptEnv,
2322 if (newscriptEnv == NULL) {
2323 free(client->scriptEnv);
2324 client->scriptEnv = NULL;
2325 client->scriptEnvsize = 0;
2326 error("script_set_env: no memory for variable");
2328 client->scriptEnv = newscriptEnv;
2329 client->scriptEnvsize = newscriptEnvsize;
2331 /* need to set the NULL pointer at end of array beyond
2333 client->scriptEnv[i + 1] = NULL;
2335 /* Allocate space and format the variable in the appropriate slot. */
2336 client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 +
2338 if (client->scriptEnv[i] == NULL)
2339 error("script_set_env: no memory for variable assignment");
2340 snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
2341 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
2345 script_flush_env(struct client_state *client)
2349 for (i = 0; client->scriptEnv[i]; i++) {
2350 free(client->scriptEnv[i]);
2351 client->scriptEnv[i] = NULL;
2353 client->scriptEnvsize = 0;
2357 dhcp_option_ev_name(char *buf, size_t buflen, struct option *option)
2361 for (i = 0; option->name[i]; i++) {
2362 if (i + 1 == buflen)
2364 if (option->name[i] == '-')
2367 buf[i] = option->name[i];
2377 static int state = 0;
2378 cap_rights_t rights;
2380 if (no_daemon || state)
2385 /* Stop logging to stderr... */
2388 if (daemon(1, 0) == -1)
2391 cap_rights_init(&rights);
2393 if (pidfile != NULL) {
2394 pidfile_write(pidfile);
2395 if (cap_rights_limit(pidfile_fileno(pidfile), &rights) < 0 &&
2397 error("can't limit pidfile descriptor: %m");
2401 /* we are chrooted, daemon(3) fails to open /dev/null */
2403 dup2(nullfd, STDIN_FILENO);
2404 dup2(nullfd, STDOUT_FILENO);
2405 dup2(nullfd, STDERR_FILENO);
2410 if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS)
2411 error("can't limit stdin: %m");
2412 cap_rights_init(&rights, CAP_WRITE);
2413 if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS)
2414 error("can't limit stdout: %m");
2415 if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS)
2416 error("can't limit stderr: %m");
2420 check_option(struct client_lease *l, int option)
2425 /* we use this, since this is what gets passed to dhclient-script */
2427 opbuf = pretty_print_option(option, l->options[option].data,
2428 l->options[option].len, 0, 0);
2430 sbuf = option_as_string(option, l->options[option].data,
2431 l->options[option].len);
2434 case DHO_SUBNET_MASK:
2435 case DHO_TIME_SERVERS:
2436 case DHO_NAME_SERVERS:
2438 case DHO_DOMAIN_NAME_SERVERS:
2439 case DHO_LOG_SERVERS:
2440 case DHO_COOKIE_SERVERS:
2441 case DHO_LPR_SERVERS:
2442 case DHO_IMPRESS_SERVERS:
2443 case DHO_RESOURCE_LOCATION_SERVERS:
2444 case DHO_SWAP_SERVER:
2445 case DHO_BROADCAST_ADDRESS:
2446 case DHO_NIS_SERVERS:
2447 case DHO_NTP_SERVERS:
2448 case DHO_NETBIOS_NAME_SERVERS:
2449 case DHO_NETBIOS_DD_SERVER:
2450 case DHO_FONT_SERVERS:
2451 case DHO_DHCP_SERVER_IDENTIFIER:
2452 case DHO_NISPLUS_SERVERS:
2453 case DHO_MOBILE_IP_HOME_AGENT:
2454 case DHO_SMTP_SERVER:
2455 case DHO_POP_SERVER:
2456 case DHO_NNTP_SERVER:
2457 case DHO_WWW_SERVER:
2458 case DHO_FINGER_SERVER:
2459 case DHO_IRC_SERVER:
2460 case DHO_STREETTALK_SERVER:
2461 case DHO_STREETTALK_DA_SERVER:
2462 if (!ipv4addrs(opbuf)) {
2463 warning("Invalid IP address in option: %s", opbuf);
2468 case DHO_NIS_DOMAIN:
2469 case DHO_NISPLUS_DOMAIN:
2470 case DHO_TFTP_SERVER_NAME:
2471 if (!res_hnok(sbuf)) {
2472 warning("Bogus Host Name option %d: %s (%s)", option,
2474 l->options[option].len = 0;
2475 free(l->options[option].data);
2478 case DHO_DOMAIN_NAME:
2479 case DHO_DOMAIN_SEARCH:
2480 if (!res_hnok(sbuf)) {
2481 if (!check_search(sbuf)) {
2482 warning("Bogus domain search list %d: %s (%s)",
2483 option, sbuf, opbuf);
2484 l->options[option].len = 0;
2485 free(l->options[option].data);
2490 case DHO_TIME_OFFSET:
2492 case DHO_MERIT_DUMP:
2494 case DHO_EXTENSIONS_PATH:
2495 case DHO_IP_FORWARDING:
2496 case DHO_NON_LOCAL_SOURCE_ROUTING:
2497 case DHO_POLICY_FILTER:
2498 case DHO_MAX_DGRAM_REASSEMBLY:
2499 case DHO_DEFAULT_IP_TTL:
2500 case DHO_PATH_MTU_AGING_TIMEOUT:
2501 case DHO_PATH_MTU_PLATEAU_TABLE:
2502 case DHO_INTERFACE_MTU:
2503 case DHO_ALL_SUBNETS_LOCAL:
2504 case DHO_PERFORM_MASK_DISCOVERY:
2505 case DHO_MASK_SUPPLIER:
2506 case DHO_ROUTER_DISCOVERY:
2507 case DHO_ROUTER_SOLICITATION_ADDRESS:
2508 case DHO_STATIC_ROUTES:
2509 case DHO_TRAILER_ENCAPSULATION:
2510 case DHO_ARP_CACHE_TIMEOUT:
2511 case DHO_IEEE802_3_ENCAPSULATION:
2512 case DHO_DEFAULT_TCP_TTL:
2513 case DHO_TCP_KEEPALIVE_INTERVAL:
2514 case DHO_TCP_KEEPALIVE_GARBAGE:
2515 case DHO_VENDOR_ENCAPSULATED_OPTIONS:
2516 case DHO_NETBIOS_NODE_TYPE:
2517 case DHO_NETBIOS_SCOPE:
2518 case DHO_X_DISPLAY_MANAGER:
2519 case DHO_DHCP_REQUESTED_ADDRESS:
2520 case DHO_DHCP_LEASE_TIME:
2521 case DHO_DHCP_OPTION_OVERLOAD:
2522 case DHO_DHCP_MESSAGE_TYPE:
2523 case DHO_DHCP_PARAMETER_REQUEST_LIST:
2524 case DHO_DHCP_MESSAGE:
2525 case DHO_DHCP_MAX_MESSAGE_SIZE:
2526 case DHO_DHCP_RENEWAL_TIME:
2527 case DHO_DHCP_REBINDING_TIME:
2528 case DHO_DHCP_CLASS_IDENTIFIER:
2529 case DHO_DHCP_CLIENT_IDENTIFIER:
2530 case DHO_BOOTFILE_NAME:
2531 case DHO_DHCP_USER_CLASS_ID:
2534 case DHO_CLASSLESS_ROUTES:
2535 return (check_classless_option(l->options[option].data,
2536 l->options[option].len));
2538 warning("unknown dhcp option value 0x%x", option);
2539 return (unknown_ok);
2543 /* RFC 3442 The Classless Static Routes option checks */
2545 check_classless_option(unsigned char *data, int len)
2548 unsigned char width;
2549 in_addr_t addr, mask;
2552 warning("Too small length: %d", len);
2560 } else if (width < 9) {
2561 addr = (in_addr_t)(data[i] << 24);
2563 } else if (width < 17) {
2564 addr = (in_addr_t)(data[i] << 24) +
2565 (in_addr_t)(data[i + 1] << 16);
2567 } else if (width < 25) {
2568 addr = (in_addr_t)(data[i] << 24) +
2569 (in_addr_t)(data[i + 1] << 16) +
2570 (in_addr_t)(data[i + 2] << 8);
2572 } else if (width < 33) {
2573 addr = (in_addr_t)(data[i] << 24) +
2574 (in_addr_t)(data[i + 1] << 16) +
2575 (in_addr_t)(data[i + 2] << 8) +
2579 warning("Incorrect subnet width: %d", width);
2582 mask = (in_addr_t)(~0) << (32 - width);
2588 * ... After deriving a subnet number and subnet mask
2589 * from each destination descriptor, the DHCP client
2590 * MUST zero any bits in the subnet number where the
2591 * corresponding bit in the mask is zero...
2593 if ((addr & mask) != addr) {
2595 data[i - 1] = (unsigned char)(
2596 (addr >> (((32 - width)/8)*8)) & 0xFF);
2601 warning("Incorrect data length: %d (must be %d)", len, i);
2608 res_hnok(const char *dn)
2610 int pch = PERIOD, ch = *dn++;
2612 while (ch != '\0') {
2615 if (periodchar(ch)) {
2617 } else if (periodchar(pch)) {
2618 if (!borderchar(ch))
2620 } else if (periodchar(nch) || nch == '\0') {
2621 if (!borderchar(ch))
2624 if (!middlechar(ch))
2633 check_search(const char *srch)
2635 int pch = PERIOD, ch = *srch++;
2638 /* 256 char limit re resolv.conf(5) */
2639 if (strlen(srch) > 256)
2642 while (whitechar(ch))
2645 while (ch != '\0') {
2648 if (periodchar(ch) || whitechar(ch)) {
2650 } else if (periodchar(pch)) {
2651 if (!borderchar(ch))
2653 } else if (periodchar(nch) || nch == '\0') {
2654 if (!borderchar(ch))
2657 if (!middlechar(ch))
2660 if (!whitechar(ch)) {
2663 while (whitechar(nch)) {
2672 /* 6 domain limit re resolv.conf(5) */
2678 /* Does buf consist only of dotted decimal ipv4 addrs?
2679 * return how many if so,
2680 * otherwise, return 0
2683 ipv4addrs(char * buf)
2688 while (inet_aton(buf, &jnk) == 1){
2690 while (periodchar(*buf) || digitchar(*buf))
2702 option_as_string(unsigned int code, unsigned char *data, int len)
2704 static char optbuf[32768]; /* XXX */
2706 int opleft = sizeof(optbuf);
2707 unsigned char *dp = data;
2710 error("option_as_string: bad code %d", code);
2712 for (; dp < data + len; dp++) {
2713 if (!isascii(*dp) || !isprint(*dp)) {
2714 if (dp + 1 != data + len || *dp != 0) {
2715 snprintf(op, opleft, "\\%03o", *dp);
2719 } else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
2720 *dp == '`' || *dp == '\\') {
2734 warning("dhcp option too large");
2739 fork_privchld(int fd, int fd2)
2741 struct pollfd pfd[1];
2746 error("cannot fork");
2753 setproctitle("%s [priv]", ifi->name);
2756 dup2(nullfd, STDIN_FILENO);
2757 dup2(nullfd, STDOUT_FILENO);
2758 dup2(nullfd, STDERR_FILENO);
2766 pfd[0].events = POLLIN;
2767 if ((nfds = poll(pfd, 1, INFTIM)) == -1)
2769 error("poll error");
2771 if (nfds == 0 || !(pfd[0].revents & POLLIN))
2774 dispatch_imsg(ifi, fd);