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>
64 #include <net80211/ieee80211_freebsd.h>
66 #ifndef _PATH_VAREMPTY
67 #define _PATH_VAREMPTY "/var/empty"
71 #define hyphenchar(c) ((c) == 0x2d)
72 #define bslashchar(c) ((c) == 0x5c)
73 #define periodchar(c) ((c) == PERIOD)
74 #define asterchar(c) ((c) == 0x2a)
75 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \
76 ((c) >= 0x61 && (c) <= 0x7a))
77 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
78 #define whitechar(c) ((c) == ' ' || (c) == '\t')
80 #define borderchar(c) (alphachar(c) || digitchar(c))
81 #define middlechar(c) (borderchar(c) || hyphenchar(c))
82 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
84 #define CLIENT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin"
87 time_t default_lease_time = 43200; /* 12 hours... */
89 char *path_dhclient_conf = _PATH_DHCLIENT_CONF;
90 char *path_dhclient_db = NULL;
96 char hostname[_POSIX_HOST_NAME_MAX + 1];
98 struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
99 struct in_addr inaddr_any, inaddr_broadcast;
101 char *path_dhclient_pidfile;
102 struct pidfh *pidfile;
105 * ASSERT_STATE() does nothing now; it used to be
106 * assert (state_is == state_shouldbe).
108 #define ASSERT_STATE(state_is, state_shouldbe) {}
110 #define TIME_MAX 2147483647
117 struct interface_info *ifi;
119 int findproto(char *, int);
120 struct sockaddr *get_ifa(char *, int);
121 void routehandler(struct protocol *);
123 int check_option(struct client_lease *l, int option);
124 int check_classless_option(unsigned char *data, int len);
125 int ipv4addrs(char * buf);
126 int res_hnok(const char *dn);
127 int check_search(const char *srch);
128 char *option_as_string(unsigned int code, unsigned char *data, int len);
129 int fork_privchld(int, int);
132 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
133 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
135 static time_t scripttime;
138 findproto(char *cp, int n)
145 for (i = 1; i; i <<= 1) {
147 sa = (struct sockaddr *)cp;
153 if (sa->sa_family == AF_INET)
155 if (sa->sa_family == AF_INET6)
168 get_ifa(char *cp, int n)
175 for (i = 1; i; i <<= 1)
177 sa = (struct sockaddr *)cp;
186 struct iaddr defaddr = { 4 };
192 struct interface_info *ifi = arg;
195 * Clear existing state.
197 if (ifi->client->active != NULL) {
198 script_init("EXPIRE", NULL);
199 script_write_params("old_",
200 ifi->client->active);
201 if (ifi->client->alias)
202 script_write_params("alias_",
206 ifi->client->state = S_INIT;
211 routehandler(struct protocol *p)
213 char msg[2048], *addr;
214 struct rt_msghdr *rtm;
215 struct if_msghdr *ifm;
216 struct ifa_msghdr *ifam;
217 struct if_announcemsghdr *ifan;
218 struct ieee80211_join_event *jev;
219 struct client_lease *l;
220 time_t t = time(NULL);
226 n = read(routefd, &msg, sizeof(msg));
227 rtm = (struct rt_msghdr *)msg;
228 if (n < sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen ||
229 rtm->rtm_version != RTM_VERSION)
232 switch (rtm->rtm_type) {
235 ifam = (struct ifa_msghdr *)rtm;
237 if (ifam->ifam_index != ifi->index)
239 if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET)
241 if (scripttime == 0 || t < scripttime + 10)
244 sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs);
248 if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf))
249 error("king bula sez: len mismatch");
250 memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len);
251 if (addr_eq(a, defaddr))
254 for (l = ifi->client->active; l != NULL; l = l->next)
255 if (addr_eq(a, l->address))
258 if (l == NULL) /* added/deleted addr is not the one we set */
261 addr = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
262 if (rtm->rtm_type == RTM_NEWADDR) {
264 * XXX: If someone other than us adds our address,
265 * should we assume they are taking over from us,
266 * delete the lease record, and exit without modifying
269 warning("My address (%s) was re-added", addr);
271 warning("My address (%s) was deleted, dhclient exiting",
277 ifm = (struct if_msghdr *)rtm;
278 if (ifm->ifm_index != ifi->index)
280 if ((rtm->rtm_flags & RTF_UP) == 0) {
281 warning("Interface %s is down, dhclient exiting",
285 linkstat = interface_link_status(ifi->name);
286 if (linkstat != ifi->linkstat) {
287 debug("%s link state %s -> %s", ifi->name,
288 ifi->linkstat ? "up" : "down",
289 linkstat ? "up" : "down");
290 ifi->linkstat = linkstat;
296 ifan = (struct if_announcemsghdr *)rtm;
297 if (ifan->ifan_what == IFAN_DEPARTURE &&
298 ifan->ifan_index == ifi->index) {
299 warning("Interface %s is gone, dhclient exiting",
305 ifan = (struct if_announcemsghdr *)rtm;
306 if (ifan->ifan_index != ifi->index)
308 switch (ifan->ifan_what) {
309 case RTM_IEEE80211_ASSOC:
310 case RTM_IEEE80211_REASSOC:
312 * Use assoc/reassoc event to kick state machine
313 * in case we roam. Otherwise fall back to the
314 * normal state machine just like a wired network.
316 jev = (struct ieee80211_join_event *) &ifan[1];
317 if (memcmp(curbssid, jev->iev_addr, 6)) {
321 memcpy(curbssid, jev->iev_addr, 6);
331 script_init("FAIL", NULL);
332 if (ifi->client->alias)
333 script_write_params("alias_", ifi->client->alias);
336 pidfile_remove(pidfile);
341 main(int argc, char *argv[])
343 extern char *__progname;
344 int ch, fd, quiet = 0, i = 0;
346 int immediate_daemon = 0;
351 /* Initially, log errors to stderr as well as to syslogd. */
352 openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
353 setlogmask(LOG_UPTO(LOG_DEBUG));
355 while ((ch = getopt(argc, argv, "bc:dl:p:qu")) != -1)
358 immediate_daemon = 1;
361 path_dhclient_conf = optarg;
367 path_dhclient_db = optarg;
370 path_dhclient_pidfile = optarg;
388 if (path_dhclient_pidfile == NULL) {
389 asprintf(&path_dhclient_pidfile,
390 "%sdhclient.%s.pid", _PATH_VARRUN, *argv);
391 if (path_dhclient_pidfile == NULL)
394 pidfile = pidfile_open(path_dhclient_pidfile, 0644, &otherpid);
395 if (pidfile == NULL) {
397 error("dhclient already running, pid: %d.", otherpid);
399 error("dhclient already running.");
400 warning("Cannot open or create pidfile: %m");
403 if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL)
405 if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ)
406 error("Interface name too long");
407 if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s",
408 _PATH_DHCLIENT_DB, ifi->name) == -1)
417 inaddr_broadcast.s_addr = INADDR_BROADCAST;
418 inaddr_any.s_addr = INADDR_ANY;
422 /* The next bit is potentially very time-consuming, so write out
423 the pidfile right away. We will write it out again with the
424 correct pid after daemonizing. */
426 pidfile_write(pidfile);
428 if (!interface_link_status(ifi->name)) {
429 fprintf(stderr, "%s: no link ...", ifi->name);
432 while (!interface_link_status(ifi->name)) {
433 fprintf(stderr, ".");
436 fprintf(stderr, " giving up\n");
441 fprintf(stderr, " got link\n");
445 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
446 error("cannot open %s: %m", _PATH_DEVNULL);
448 if ((pw = getpwnam("_dhcp")) == NULL) {
449 warning("no such user: _dhcp, falling back to \"nobody\"");
450 if ((pw = getpwnam("nobody")) == NULL)
451 error("no such user: nobody");
455 * Obtain hostname before entering capability mode - it won't be
456 * possible then, as reading kern.hostname is not permitted.
458 if (gethostname(hostname, sizeof(hostname)) < 0)
461 priv_script_init("PREINIT", NULL);
462 if (ifi->client->alias)
463 priv_script_write_params("alias_", ifi->client->alias);
466 /* set up the interface */
467 discover_interfaces(ifi);
469 if (pipe(pipe_fd) == -1)
472 fork_privchld(pipe_fd[0], pipe_fd[1]);
481 cap_rights_init(&rights, CAP_READ, CAP_WRITE);
482 if (cap_rights_limit(privfd, &rights) < 0 && errno != ENOSYS)
483 error("can't limit private descriptor: %m");
485 if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
486 error("can't open and lock %s: %m", path_dhclient_db);
487 read_client_leases();
488 rewrite_client_leases();
491 if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
492 add_protocol("AF_ROUTE", routefd, routehandler, ifi);
493 if (shutdown(routefd, SHUT_WR) < 0)
494 error("can't shutdown route socket: %m");
495 cap_rights_init(&rights, CAP_EVENT, CAP_READ);
496 if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS)
497 error("can't limit route socket: %m");
499 if (chroot(_PATH_VAREMPTY) == -1)
501 if (chdir("/") == -1)
502 error("chdir(\"/\")");
504 if (setgroups(1, &pw->pw_gid) ||
505 setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
506 seteuid(pw->pw_uid) || setuid(pw->pw_uid))
507 error("can't drop privileges: %m");
511 setproctitle("%s", ifi->name);
513 if (cap_enter() < 0 && errno != ENOSYS)
514 error("can't enter capability mode: %m");
516 if (immediate_daemon)
519 ifi->client->state = S_INIT;
522 bootp_packet_handler = do_packet;
533 extern char *__progname;
535 fprintf(stderr, "usage: %s [-bdqu] ", __progname);
536 fprintf(stderr, "[-c conffile] [-l leasefile] interface\n");
543 * Each routine is called from the dhclient_state_machine() in one of
545 * -> entering INIT state
546 * -> recvpacket_flag == 0: timeout in this state
547 * -> otherwise: received a packet in this state
549 * Return conditions as handled by dhclient_state_machine():
550 * Returns 1, sendpacket_flag = 1: send packet, reset timer.
551 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone).
552 * Returns 0: finish the nap which was interrupted for no good reason.
554 * Several per-interface variables are used to keep track of the process:
555 * active_lease: the lease that is being used on the interface
556 * (null pointer if not configured yet).
557 * offered_leases: leases corresponding to DHCPOFFER messages that have
558 * been sent to us by DHCP servers.
559 * acked_leases: leases corresponding to DHCPACK messages that have been
560 * sent to us by DHCP servers.
561 * sendpacket: DHCP packet we're trying to send.
562 * destination: IP address to send sendpacket to
563 * In addition, there are several relevant per-lease variables.
564 * T1_expiry, T2_expiry, lease_expiry: lease milestones
565 * In the active lease, these control the process of renewing the lease;
566 * In leases on the acked_leases list, this simply determines when we
567 * can no longer legitimately use the lease.
571 state_reboot(void *ipp)
573 struct interface_info *ip = ipp;
575 /* If we don't remember an active lease, go straight to INIT. */
576 if (!ip->client->active || ip->client->active->is_bootp) {
581 /* We are in the rebooting state. */
582 ip->client->state = S_REBOOTING;
584 /* make_request doesn't initialize xid because it normally comes
585 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER,
586 so pick an xid now. */
587 ip->client->xid = arc4random();
589 /* Make a DHCPREQUEST packet, and set appropriate per-interface
591 make_request(ip, ip->client->active);
592 ip->client->destination = iaddr_broadcast;
593 ip->client->first_sending = cur_time;
594 ip->client->interval = ip->client->config->initial_interval;
596 /* Zap the medium list... */
597 ip->client->medium = NULL;
599 /* Send out the first DHCPREQUEST packet. */
604 * Called when a lease has completely expired and we've
605 * been unable to renew it.
608 state_init(void *ipp)
610 struct interface_info *ip = ipp;
612 ASSERT_STATE(state, S_INIT);
614 /* Make a DHCPDISCOVER packet, and set appropriate per-interface
616 make_discover(ip, ip->client->active);
617 ip->client->xid = ip->client->packet.xid;
618 ip->client->destination = iaddr_broadcast;
619 ip->client->state = S_SELECTING;
620 ip->client->first_sending = cur_time;
621 ip->client->interval = ip->client->config->initial_interval;
623 /* Add an immediate timeout to cause the first DHCPDISCOVER packet
629 * state_selecting is called when one or more DHCPOFFER packets
630 * have been received and a configurable period of time has passed.
633 state_selecting(void *ipp)
635 struct interface_info *ip = ipp;
636 struct client_lease *lp, *next, *picked;
638 ASSERT_STATE(state, S_SELECTING);
640 /* Cancel state_selecting and send_discover timeouts, since either
641 one could have got us here. */
642 cancel_timeout(state_selecting, ip);
643 cancel_timeout(send_discover, ip);
645 /* We have received one or more DHCPOFFER packets. Currently,
646 the only criterion by which we judge leases is whether or
647 not we get a response when we arp for them. */
649 for (lp = ip->client->offered_leases; lp; lp = next) {
652 /* Check to see if we got an ARPREPLY for the address
653 in this particular lease. */
655 script_init("ARPCHECK", lp->medium);
656 script_write_params("check_", lp);
658 /* If the ARPCHECK code detects another
659 machine using the offered address, it exits
660 nonzero. We need to send a DHCPDECLINE and
663 make_decline(ip, lp);
671 free_client_lease(lp);
674 ip->client->offered_leases = NULL;
676 /* If we just tossed all the leases we were offered, go back
679 ip->client->state = S_INIT;
684 /* If it was a BOOTREPLY, we can just take the address right now. */
685 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) {
686 ip->client->new = picked;
688 /* Make up some lease expiry times
689 XXX these should be configurable. */
690 ip->client->new->expiry = cur_time + 12000;
691 ip->client->new->renewal += cur_time + 8000;
692 ip->client->new->rebind += cur_time + 10000;
694 ip->client->state = S_REQUESTING;
696 /* Bind to the address we received. */
701 /* Go to the REQUESTING state. */
702 ip->client->destination = iaddr_broadcast;
703 ip->client->state = S_REQUESTING;
704 ip->client->first_sending = cur_time;
705 ip->client->interval = ip->client->config->initial_interval;
707 /* Make a DHCPREQUEST packet from the lease we picked. */
708 make_request(ip, picked);
709 ip->client->xid = ip->client->packet.xid;
711 /* Toss the lease we picked - we'll get it back in a DHCPACK. */
712 free_client_lease(picked);
714 /* Add an immediate timeout to send the first DHCPREQUEST packet. */
718 /* state_requesting is called when we receive a DHCPACK message after
719 having sent out one or more DHCPREQUEST packets. */
722 dhcpack(struct packet *packet)
724 struct interface_info *ip = packet->interface;
725 struct client_lease *lease;
727 /* If we're not receptive to an offer right now, or if the offer
728 has an unrecognizable transaction id, then just drop it. */
729 if (packet->interface->client->xid != packet->raw->xid ||
730 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
731 (memcmp(packet->interface->hw_address.haddr,
732 packet->raw->chaddr, packet->raw->hlen)))
735 if (ip->client->state != S_REBOOTING &&
736 ip->client->state != S_REQUESTING &&
737 ip->client->state != S_RENEWING &&
738 ip->client->state != S_REBINDING)
741 note("DHCPACK from %s", piaddr(packet->client_addr));
743 lease = packet_to_lease(packet);
745 note("packet_to_lease failed.");
749 ip->client->new = lease;
751 /* Stop resending DHCPREQUEST. */
752 cancel_timeout(send_request, ip);
754 /* Figure out the lease time. */
755 if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data)
756 ip->client->new->expiry = getULong(
757 ip->client->new->options[DHO_DHCP_LEASE_TIME].data);
759 ip->client->new->expiry = default_lease_time;
760 /* A number that looks negative here is really just very large,
761 because the lease expiry offset is unsigned. */
762 if (ip->client->new->expiry < 0)
763 ip->client->new->expiry = TIME_MAX;
764 /* XXX should be fixed by resetting the client state */
765 if (ip->client->new->expiry < 60)
766 ip->client->new->expiry = 60;
768 /* Take the server-provided renewal time if there is one;
769 otherwise figure it out according to the spec. */
770 if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len)
771 ip->client->new->renewal = getULong(
772 ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data);
774 ip->client->new->renewal = ip->client->new->expiry / 2;
776 /* Same deal with the rebind time. */
777 if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len)
778 ip->client->new->rebind = getULong(
779 ip->client->new->options[DHO_DHCP_REBINDING_TIME].data);
781 ip->client->new->rebind = ip->client->new->renewal +
782 ip->client->new->renewal / 2 + ip->client->new->renewal / 4;
784 ip->client->new->expiry += cur_time;
785 /* Lease lengths can never be negative. */
786 if (ip->client->new->expiry < cur_time)
787 ip->client->new->expiry = TIME_MAX;
788 ip->client->new->renewal += cur_time;
789 if (ip->client->new->renewal < cur_time)
790 ip->client->new->renewal = TIME_MAX;
791 ip->client->new->rebind += cur_time;
792 if (ip->client->new->rebind < cur_time)
793 ip->client->new->rebind = TIME_MAX;
799 bind_lease(struct interface_info *ip)
801 /* Remember the medium. */
802 ip->client->new->medium = ip->client->medium;
804 /* Write out the new lease. */
805 write_client_lease(ip, ip->client->new, 0);
807 /* Run the client script with the new parameters. */
808 script_init((ip->client->state == S_REQUESTING ? "BOUND" :
809 (ip->client->state == S_RENEWING ? "RENEW" :
810 (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))),
811 ip->client->new->medium);
812 if (ip->client->active && ip->client->state != S_REBOOTING)
813 script_write_params("old_", ip->client->active);
814 script_write_params("new_", ip->client->new);
815 if (ip->client->alias)
816 script_write_params("alias_", ip->client->alias);
819 /* Replace the old active lease with the new one. */
820 if (ip->client->active)
821 free_client_lease(ip->client->active);
822 ip->client->active = ip->client->new;
823 ip->client->new = NULL;
825 /* Set up a timeout to start the renewal process. */
826 add_timeout(ip->client->active->renewal, state_bound, ip);
828 note("bound to %s -- renewal in %d seconds.",
829 piaddr(ip->client->active->address),
830 (int)(ip->client->active->renewal - cur_time));
831 ip->client->state = S_BOUND;
832 reinitialize_interfaces();
837 * state_bound is called when we've successfully bound to a particular
838 * lease, but the renewal time on that lease has expired. We are
839 * expected to unicast a DHCPREQUEST to the server that gave us our
843 state_bound(void *ipp)
845 struct interface_info *ip = ipp;
847 ASSERT_STATE(state, S_BOUND);
849 /* T1 has expired. */
850 make_request(ip, ip->client->active);
851 ip->client->xid = ip->client->packet.xid;
853 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) {
854 memcpy(ip->client->destination.iabuf, ip->client->active->
855 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4);
856 ip->client->destination.len = 4;
858 ip->client->destination = iaddr_broadcast;
860 ip->client->first_sending = cur_time;
861 ip->client->interval = ip->client->config->initial_interval;
862 ip->client->state = S_RENEWING;
864 /* Send the first packet immediately. */
869 bootp(struct packet *packet)
871 struct iaddrlist *ap;
873 if (packet->raw->op != BOOTREPLY)
876 /* If there's a reject list, make sure this packet's sender isn't
878 for (ap = packet->interface->client->config->reject_list;
880 if (addr_eq(packet->client_addr, ap->addr)) {
881 note("BOOTREPLY from %s rejected.", piaddr(ap->addr));
889 dhcp(struct packet *packet)
891 struct iaddrlist *ap;
892 void (*handler)(struct packet *);
895 switch (packet->packet_type) {
912 /* If there's a reject list, make sure this packet's sender isn't
914 for (ap = packet->interface->client->config->reject_list;
916 if (addr_eq(packet->client_addr, ap->addr)) {
917 note("%s from %s rejected.", type, piaddr(ap->addr));
925 dhcpoffer(struct packet *packet)
927 struct interface_info *ip = packet->interface;
928 struct client_lease *lease, *lp;
930 int arp_timeout_needed, stop_selecting;
931 char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ?
932 "DHCPOFFER" : "BOOTREPLY";
934 /* If we're not receptive to an offer right now, or if the offer
935 has an unrecognizable transaction id, then just drop it. */
936 if (ip->client->state != S_SELECTING ||
937 packet->interface->client->xid != packet->raw->xid ||
938 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
939 (memcmp(packet->interface->hw_address.haddr,
940 packet->raw->chaddr, packet->raw->hlen)))
943 note("%s from %s", name, piaddr(packet->client_addr));
946 /* If this lease doesn't supply the minimum required parameters,
948 for (i = 0; ip->client->config->required_options[i]; i++) {
949 if (!packet->options[ip->client->config->
950 required_options[i]].len) {
951 note("%s isn't satisfactory.", name);
956 /* If we've already seen this lease, don't record it again. */
957 for (lease = ip->client->offered_leases;
958 lease; lease = lease->next) {
959 if (lease->address.len == sizeof(packet->raw->yiaddr) &&
960 !memcmp(lease->address.iabuf,
961 &packet->raw->yiaddr, lease->address.len)) {
962 debug("%s already seen.", name);
967 lease = packet_to_lease(packet);
969 note("packet_to_lease failed.");
973 /* If this lease was acquired through a BOOTREPLY, record that
975 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len)
978 /* Record the medium under which this lease was offered. */
979 lease->medium = ip->client->medium;
981 /* Send out an ARP Request for the offered IP address. */
982 script_init("ARPSEND", lease->medium);
983 script_write_params("check_", lease);
984 /* If the script can't send an ARP request without waiting,
985 we'll be waiting when we do the ARPCHECK, so don't wait now. */
987 arp_timeout_needed = 0;
989 arp_timeout_needed = 2;
991 /* Figure out when we're supposed to stop selecting. */
993 ip->client->first_sending + ip->client->config->select_interval;
995 /* If this is the lease we asked for, put it at the head of the
996 list, and don't mess with the arp request timeout. */
997 if (lease->address.len == ip->client->requested_address.len &&
998 !memcmp(lease->address.iabuf,
999 ip->client->requested_address.iabuf,
1000 ip->client->requested_address.len)) {
1001 lease->next = ip->client->offered_leases;
1002 ip->client->offered_leases = lease;
1004 /* If we already have an offer, and arping for this
1005 offer would take us past the selection timeout,
1006 then don't extend the timeout - just hope for the
1008 if (ip->client->offered_leases &&
1009 (cur_time + arp_timeout_needed) > stop_selecting)
1010 arp_timeout_needed = 0;
1012 /* Put the lease at the end of the list. */
1014 if (!ip->client->offered_leases)
1015 ip->client->offered_leases = lease;
1017 for (lp = ip->client->offered_leases; lp->next;
1024 /* If we're supposed to stop selecting before we've had time
1025 to wait for the ARPREPLY, add some delay to wait for
1027 if (stop_selecting - cur_time < arp_timeout_needed)
1028 stop_selecting = cur_time + arp_timeout_needed;
1030 /* If the selecting interval has expired, go immediately to
1031 state_selecting(). Otherwise, time out into
1032 state_selecting at the select interval. */
1033 if (stop_selecting <= 0)
1034 state_selecting(ip);
1036 add_timeout(stop_selecting, state_selecting, ip);
1037 cancel_timeout(send_discover, ip);
1041 /* Allocate a client_lease structure and initialize it from the parameters
1042 in the specified packet. */
1044 struct client_lease *
1045 packet_to_lease(struct packet *packet)
1047 struct client_lease *lease;
1050 lease = malloc(sizeof(struct client_lease));
1053 warning("dhcpoffer: no memory to record lease.");
1057 memset(lease, 0, sizeof(*lease));
1059 /* Copy the lease options. */
1060 for (i = 0; i < 256; i++) {
1061 if (packet->options[i].len) {
1062 lease->options[i].data =
1063 malloc(packet->options[i].len + 1);
1064 if (!lease->options[i].data) {
1065 warning("dhcpoffer: no memory for option %d", i);
1066 free_client_lease(lease);
1069 memcpy(lease->options[i].data,
1070 packet->options[i].data,
1071 packet->options[i].len);
1072 lease->options[i].len =
1073 packet->options[i].len;
1074 lease->options[i].data[lease->options[i].len] =
1077 if (!check_option(lease,i)) {
1078 /* ignore a bogus lease offer */
1079 warning("Invalid lease option - ignoring offer");
1080 free_client_lease(lease);
1086 lease->address.len = sizeof(packet->raw->yiaddr);
1087 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
1089 lease->nextserver.len = sizeof(packet->raw->siaddr);
1090 memcpy(lease->nextserver.iabuf, &packet->raw->siaddr, lease->nextserver.len);
1092 /* If the server name was filled out, copy it.
1093 Do not attempt to validate the server name as a host name.
1094 RFC 2131 merely states that sname is NUL-terminated (which do
1095 do not assume) and that it is the server's host name. Since
1096 the ISC client and server allow arbitrary characters, we do
1098 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1099 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) &&
1100 packet->raw->sname[0]) {
1101 lease->server_name = malloc(DHCP_SNAME_LEN + 1);
1102 if (!lease->server_name) {
1103 warning("dhcpoffer: no memory for server name.");
1104 free_client_lease(lease);
1107 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN);
1108 lease->server_name[DHCP_SNAME_LEN]='\0';
1111 /* Ditto for the filename. */
1112 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len ||
1113 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) &&
1114 packet->raw->file[0]) {
1115 /* Don't count on the NUL terminator. */
1116 lease->filename = malloc(DHCP_FILE_LEN + 1);
1117 if (!lease->filename) {
1118 warning("dhcpoffer: no memory for filename.");
1119 free_client_lease(lease);
1122 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN);
1123 lease->filename[DHCP_FILE_LEN]='\0';
1129 dhcpnak(struct packet *packet)
1131 struct interface_info *ip = packet->interface;
1133 /* If we're not receptive to an offer right now, or if the offer
1134 has an unrecognizable transaction id, then just drop it. */
1135 if (packet->interface->client->xid != packet->raw->xid ||
1136 (packet->interface->hw_address.hlen != packet->raw->hlen) ||
1137 (memcmp(packet->interface->hw_address.haddr,
1138 packet->raw->chaddr, packet->raw->hlen)))
1141 if (ip->client->state != S_REBOOTING &&
1142 ip->client->state != S_REQUESTING &&
1143 ip->client->state != S_RENEWING &&
1144 ip->client->state != S_REBINDING)
1147 note("DHCPNAK from %s", piaddr(packet->client_addr));
1149 if (!ip->client->active) {
1150 note("DHCPNAK with no active lease.\n");
1154 free_client_lease(ip->client->active);
1155 ip->client->active = NULL;
1157 /* Stop sending DHCPREQUEST packets... */
1158 cancel_timeout(send_request, ip);
1160 ip->client->state = S_INIT;
1164 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another
1165 one after the right interval has expired. If we don't get an offer by
1166 the time we reach the panic interval, call the panic function. */
1169 send_discover(void *ipp)
1171 struct interface_info *ip = ipp;
1172 int interval, increase = 1;
1174 /* Figure out how long it's been since we started transmitting. */
1175 interval = cur_time - ip->client->first_sending;
1177 /* If we're past the panic timeout, call the script and tell it
1178 we haven't found anything for this interface yet. */
1179 if (interval > ip->client->config->timeout) {
1184 /* If we're selecting media, try the whole list before doing
1185 the exponential backoff, but if we've already received an
1186 offer, stop looping, because we obviously have it right. */
1187 if (!ip->client->offered_leases &&
1188 ip->client->config->media) {
1191 if (ip->client->medium) {
1192 ip->client->medium = ip->client->medium->next;
1195 if (!ip->client->medium) {
1197 error("No valid media types for %s!", ip->name);
1198 ip->client->medium = ip->client->config->media;
1202 note("Trying medium \"%s\" %d", ip->client->medium->string,
1204 script_init("MEDIUM", ip->client->medium);
1210 * If we're supposed to increase the interval, do so. If it's
1211 * currently zero (i.e., we haven't sent any packets yet), set
1212 * it to one; otherwise, add to it a random number between zero
1213 * and two times itself. On average, this means that it will
1214 * double with every transmission.
1217 if (!ip->client->interval)
1218 ip->client->interval =
1219 ip->client->config->initial_interval;
1221 ip->client->interval += (arc4random() >> 2) %
1222 (2 * ip->client->interval);
1225 /* Don't backoff past cutoff. */
1226 if (ip->client->interval >
1227 ip->client->config->backoff_cutoff)
1228 ip->client->interval =
1229 ((ip->client->config->backoff_cutoff / 2)
1230 + ((arc4random() >> 2) %
1231 ip->client->config->backoff_cutoff));
1232 } else if (!ip->client->interval)
1233 ip->client->interval =
1234 ip->client->config->initial_interval;
1236 /* If the backoff would take us to the panic timeout, just use that
1238 if (cur_time + ip->client->interval >
1239 ip->client->first_sending + ip->client->config->timeout)
1240 ip->client->interval =
1241 (ip->client->first_sending +
1242 ip->client->config->timeout) - cur_time + 1;
1244 /* Record the number of seconds since we started sending. */
1245 if (interval < 65536)
1246 ip->client->packet.secs = htons(interval);
1248 ip->client->packet.secs = htons(65535);
1249 ip->client->secs = ip->client->packet.secs;
1251 note("DHCPDISCOVER on %s to %s port %d interval %d",
1252 ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT,
1253 (int)ip->client->interval);
1255 /* Send out a packet. */
1256 send_packet_unpriv(privfd, &ip->client->packet,
1257 ip->client->packet_length, inaddr_any, inaddr_broadcast);
1259 add_timeout(cur_time + ip->client->interval, send_discover, ip);
1263 * state_panic gets called if we haven't received any offers in a preset
1264 * amount of time. When this happens, we try to use existing leases
1265 * that haven't yet expired, and failing that, we call the client script
1266 * and hope it can do something.
1269 state_panic(void *ipp)
1271 struct interface_info *ip = ipp;
1272 struct client_lease *loop = ip->client->active;
1273 struct client_lease *lp;
1275 note("No DHCPOFFERS received.");
1277 /* We may not have an active lease, but we may have some
1278 predefined leases that we can try. */
1279 if (!ip->client->active && ip->client->leases)
1282 /* Run through the list of leases and see if one can be used. */
1283 while (ip->client->active) {
1284 if (ip->client->active->expiry > cur_time) {
1285 note("Trying recorded lease %s",
1286 piaddr(ip->client->active->address));
1287 /* Run the client script with the existing
1289 script_init("TIMEOUT",
1290 ip->client->active->medium);
1291 script_write_params("new_", ip->client->active);
1292 if (ip->client->alias)
1293 script_write_params("alias_",
1296 /* If the old lease is still good and doesn't
1297 yet need renewal, go into BOUND state and
1298 timeout at the renewal time. */
1301 ip->client->active->renewal) {
1302 ip->client->state = S_BOUND;
1303 note("bound: renewal in %d seconds.",
1304 (int)(ip->client->active->renewal -
1307 ip->client->active->renewal,
1310 ip->client->state = S_BOUND;
1311 note("bound: immediate renewal.");
1314 reinitialize_interfaces();
1320 /* If there are no other leases, give up. */
1321 if (!ip->client->leases) {
1322 ip->client->leases = ip->client->active;
1323 ip->client->active = NULL;
1328 /* Otherwise, put the active lease at the end of the
1329 lease list, and try another lease.. */
1330 for (lp = ip->client->leases; lp->next; lp = lp->next)
1332 lp->next = ip->client->active;
1334 lp->next->next = NULL;
1335 ip->client->active = ip->client->leases;
1336 ip->client->leases = ip->client->leases->next;
1338 /* If we already tried this lease, we've exhausted the
1339 set of leases, so we might as well give up for
1341 if (ip->client->active == loop)
1344 loop = ip->client->active;
1347 /* No leases were available, or what was available didn't work, so
1348 tell the shell script that we failed to allocate an address,
1349 and try again later. */
1350 note("No working leases in persistent database - sleeping.\n");
1351 script_init("FAIL", NULL);
1352 if (ip->client->alias)
1353 script_write_params("alias_", ip->client->alias);
1355 ip->client->state = S_INIT;
1356 add_timeout(cur_time + ip->client->config->retry_interval, state_init,
1362 send_request(void *ipp)
1364 struct interface_info *ip = ipp;
1365 struct in_addr from, to;
1368 /* Figure out how long it's been since we started transmitting. */
1369 interval = cur_time - ip->client->first_sending;
1371 /* If we're in the INIT-REBOOT or REQUESTING state and we're
1372 past the reboot timeout, go to INIT and see if we can
1373 DISCOVER an address... */
1374 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it
1375 means either that we're on a network with no DHCP server,
1376 or that our server is down. In the latter case, assuming
1377 that there is a backup DHCP server, DHCPDISCOVER will get
1378 us a new address, but we could also have successfully
1379 reused our old address. In the former case, we're hosed
1380 anyway. This is not a win-prone situation. */
1381 if ((ip->client->state == S_REBOOTING ||
1382 ip->client->state == S_REQUESTING) &&
1383 interval > ip->client->config->reboot_timeout) {
1385 ip->client->state = S_INIT;
1386 cancel_timeout(send_request, ip);
1391 /* If we're in the reboot state, make sure the media is set up
1393 if (ip->client->state == S_REBOOTING &&
1394 !ip->client->medium &&
1395 ip->client->active->medium ) {
1396 script_init("MEDIUM", ip->client->active->medium);
1398 /* If the medium we chose won't fly, go to INIT state. */
1402 /* Record the medium. */
1403 ip->client->medium = ip->client->active->medium;
1406 /* If the lease has expired, relinquish the address and go back
1407 to the INIT state. */
1408 if (ip->client->state != S_REQUESTING &&
1409 cur_time > ip->client->active->expiry) {
1410 /* Run the client script with the new parameters. */
1411 script_init("EXPIRE", NULL);
1412 script_write_params("old_", ip->client->active);
1413 if (ip->client->alias)
1414 script_write_params("alias_", ip->client->alias);
1417 /* Now do a preinit on the interface so that we can
1418 discover a new address. */
1419 script_init("PREINIT", NULL);
1420 if (ip->client->alias)
1421 script_write_params("alias_", ip->client->alias);
1424 ip->client->state = S_INIT;
1429 /* Do the exponential backoff... */
1430 if (!ip->client->interval)
1431 ip->client->interval = ip->client->config->initial_interval;
1433 ip->client->interval += ((arc4random() >> 2) %
1434 (2 * ip->client->interval));
1436 /* Don't backoff past cutoff. */
1437 if (ip->client->interval >
1438 ip->client->config->backoff_cutoff)
1439 ip->client->interval =
1440 ((ip->client->config->backoff_cutoff / 2) +
1441 ((arc4random() >> 2) % ip->client->interval));
1443 /* If the backoff would take us to the expiry time, just set the
1444 timeout to the expiry time. */
1445 if (ip->client->state != S_REQUESTING &&
1446 cur_time + ip->client->interval >
1447 ip->client->active->expiry)
1448 ip->client->interval =
1449 ip->client->active->expiry - cur_time + 1;
1451 /* If the lease T2 time has elapsed, or if we're not yet bound,
1452 broadcast the DHCPREQUEST rather than unicasting. */
1453 if (ip->client->state == S_REQUESTING ||
1454 ip->client->state == S_REBOOTING ||
1455 cur_time > ip->client->active->rebind)
1456 to.s_addr = INADDR_BROADCAST;
1458 memcpy(&to.s_addr, ip->client->destination.iabuf,
1461 if (ip->client->state != S_REQUESTING)
1462 memcpy(&from, ip->client->active->address.iabuf,
1465 from.s_addr = INADDR_ANY;
1467 /* Record the number of seconds since we started sending. */
1468 if (ip->client->state == S_REQUESTING)
1469 ip->client->packet.secs = ip->client->secs;
1471 if (interval < 65536)
1472 ip->client->packet.secs = htons(interval);
1474 ip->client->packet.secs = htons(65535);
1477 note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to),
1480 /* Send out a packet. */
1481 send_packet_unpriv(privfd, &ip->client->packet,
1482 ip->client->packet_length, from, to);
1484 add_timeout(cur_time + ip->client->interval, send_request, ip);
1488 send_decline(void *ipp)
1490 struct interface_info *ip = ipp;
1492 note("DHCPDECLINE on %s to %s port %d", ip->name,
1493 inet_ntoa(inaddr_broadcast), REMOTE_PORT);
1495 /* Send out a packet. */
1496 send_packet_unpriv(privfd, &ip->client->packet,
1497 ip->client->packet_length, inaddr_any, inaddr_broadcast);
1501 make_discover(struct interface_info *ip, struct client_lease *lease)
1503 unsigned char discover = DHCPDISCOVER;
1504 struct tree_cache *options[256];
1505 struct tree_cache option_elements[256];
1508 memset(option_elements, 0, sizeof(option_elements));
1509 memset(options, 0, sizeof(options));
1510 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1512 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
1513 i = DHO_DHCP_MESSAGE_TYPE;
1514 options[i] = &option_elements[i];
1515 options[i]->value = &discover;
1516 options[i]->len = sizeof(discover);
1517 options[i]->buf_size = sizeof(discover);
1518 options[i]->timeout = 0xFFFFFFFF;
1520 /* Request the options we want */
1521 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1522 options[i] = &option_elements[i];
1523 options[i]->value = ip->client->config->requested_options;
1524 options[i]->len = ip->client->config->requested_option_count;
1525 options[i]->buf_size =
1526 ip->client->config->requested_option_count;
1527 options[i]->timeout = 0xFFFFFFFF;
1529 /* If we had an address, try to get it again. */
1531 ip->client->requested_address = lease->address;
1532 i = DHO_DHCP_REQUESTED_ADDRESS;
1533 options[i] = &option_elements[i];
1534 options[i]->value = lease->address.iabuf;
1535 options[i]->len = lease->address.len;
1536 options[i]->buf_size = lease->address.len;
1537 options[i]->timeout = 0xFFFFFFFF;
1539 ip->client->requested_address.len = 0;
1541 /* Send any options requested in the config file. */
1542 for (i = 0; i < 256; i++)
1544 ip->client->config->send_options[i].data) {
1545 options[i] = &option_elements[i];
1547 ip->client->config->send_options[i].data;
1549 ip->client->config->send_options[i].len;
1550 options[i]->buf_size =
1551 ip->client->config->send_options[i].len;
1552 options[i]->timeout = 0xFFFFFFFF;
1555 /* send host name if not set via config file. */
1556 if (!options[DHO_HOST_NAME]) {
1557 if (hostname[0] != '\0') {
1559 char* posDot = strchr(hostname, '.');
1561 len = posDot - hostname;
1563 len = strlen(hostname);
1564 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1565 options[DHO_HOST_NAME]->value = hostname;
1566 options[DHO_HOST_NAME]->len = len;
1567 options[DHO_HOST_NAME]->buf_size = len;
1568 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1572 /* set unique client identifier */
1573 char client_ident[sizeof(struct hardware)];
1574 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1575 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1576 ip->hw_address.hlen : sizeof(client_ident)-1;
1577 client_ident[0] = ip->hw_address.htype;
1578 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1579 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1580 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1581 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1582 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1583 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1586 /* Set up the option buffer... */
1587 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1588 options, 0, 0, 0, NULL, 0);
1589 if (ip->client->packet_length < BOOTP_MIN_LEN)
1590 ip->client->packet_length = BOOTP_MIN_LEN;
1592 ip->client->packet.op = BOOTREQUEST;
1593 ip->client->packet.htype = ip->hw_address.htype;
1594 ip->client->packet.hlen = ip->hw_address.hlen;
1595 ip->client->packet.hops = 0;
1596 ip->client->packet.xid = arc4random();
1597 ip->client->packet.secs = 0; /* filled in by send_discover. */
1598 ip->client->packet.flags = 0;
1600 memset(&(ip->client->packet.ciaddr),
1601 0, sizeof(ip->client->packet.ciaddr));
1602 memset(&(ip->client->packet.yiaddr),
1603 0, sizeof(ip->client->packet.yiaddr));
1604 memset(&(ip->client->packet.siaddr),
1605 0, sizeof(ip->client->packet.siaddr));
1606 memset(&(ip->client->packet.giaddr),
1607 0, sizeof(ip->client->packet.giaddr));
1608 memcpy(ip->client->packet.chaddr,
1609 ip->hw_address.haddr, ip->hw_address.hlen);
1614 make_request(struct interface_info *ip, struct client_lease * lease)
1616 unsigned char request = DHCPREQUEST;
1617 struct tree_cache *options[256];
1618 struct tree_cache option_elements[256];
1621 memset(options, 0, sizeof(options));
1622 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1624 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
1625 i = DHO_DHCP_MESSAGE_TYPE;
1626 options[i] = &option_elements[i];
1627 options[i]->value = &request;
1628 options[i]->len = sizeof(request);
1629 options[i]->buf_size = sizeof(request);
1630 options[i]->timeout = 0xFFFFFFFF;
1632 /* Request the options we want */
1633 i = DHO_DHCP_PARAMETER_REQUEST_LIST;
1634 options[i] = &option_elements[i];
1635 options[i]->value = ip->client->config->requested_options;
1636 options[i]->len = ip->client->config->requested_option_count;
1637 options[i]->buf_size =
1638 ip->client->config->requested_option_count;
1639 options[i]->timeout = 0xFFFFFFFF;
1641 /* If we are requesting an address that hasn't yet been assigned
1642 to us, use the DHCP Requested Address option. */
1643 if (ip->client->state == S_REQUESTING) {
1644 /* Send back the server identifier... */
1645 i = DHO_DHCP_SERVER_IDENTIFIER;
1646 options[i] = &option_elements[i];
1647 options[i]->value = lease->options[i].data;
1648 options[i]->len = lease->options[i].len;
1649 options[i]->buf_size = lease->options[i].len;
1650 options[i]->timeout = 0xFFFFFFFF;
1652 if (ip->client->state == S_REQUESTING ||
1653 ip->client->state == S_REBOOTING) {
1654 ip->client->requested_address = lease->address;
1655 i = DHO_DHCP_REQUESTED_ADDRESS;
1656 options[i] = &option_elements[i];
1657 options[i]->value = lease->address.iabuf;
1658 options[i]->len = lease->address.len;
1659 options[i]->buf_size = lease->address.len;
1660 options[i]->timeout = 0xFFFFFFFF;
1662 ip->client->requested_address.len = 0;
1664 /* Send any options requested in the config file. */
1665 for (i = 0; i < 256; i++)
1667 ip->client->config->send_options[i].data) {
1668 options[i] = &option_elements[i];
1670 ip->client->config->send_options[i].data;
1672 ip->client->config->send_options[i].len;
1673 options[i]->buf_size =
1674 ip->client->config->send_options[i].len;
1675 options[i]->timeout = 0xFFFFFFFF;
1678 /* send host name if not set via config file. */
1679 if (!options[DHO_HOST_NAME]) {
1680 if (hostname[0] != '\0') {
1682 char* posDot = strchr(hostname, '.');
1684 len = posDot - hostname;
1686 len = strlen(hostname);
1687 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME];
1688 options[DHO_HOST_NAME]->value = hostname;
1689 options[DHO_HOST_NAME]->len = len;
1690 options[DHO_HOST_NAME]->buf_size = len;
1691 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF;
1695 /* set unique client identifier */
1696 char client_ident[sizeof(struct hardware)];
1697 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
1698 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
1699 ip->hw_address.hlen : sizeof(client_ident)-1;
1700 client_ident[0] = ip->hw_address.htype;
1701 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
1702 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
1703 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
1704 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
1705 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1;
1706 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF;
1709 /* Set up the option buffer... */
1710 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1711 options, 0, 0, 0, NULL, 0);
1712 if (ip->client->packet_length < BOOTP_MIN_LEN)
1713 ip->client->packet_length = BOOTP_MIN_LEN;
1715 ip->client->packet.op = BOOTREQUEST;
1716 ip->client->packet.htype = ip->hw_address.htype;
1717 ip->client->packet.hlen = ip->hw_address.hlen;
1718 ip->client->packet.hops = 0;
1719 ip->client->packet.xid = ip->client->xid;
1720 ip->client->packet.secs = 0; /* Filled in by send_request. */
1722 /* If we own the address we're requesting, put it in ciaddr;
1723 otherwise set ciaddr to zero. */
1724 if (ip->client->state == S_BOUND ||
1725 ip->client->state == S_RENEWING ||
1726 ip->client->state == S_REBINDING) {
1727 memcpy(&ip->client->packet.ciaddr,
1728 lease->address.iabuf, lease->address.len);
1729 ip->client->packet.flags = 0;
1731 memset(&ip->client->packet.ciaddr, 0,
1732 sizeof(ip->client->packet.ciaddr));
1733 ip->client->packet.flags = 0;
1736 memset(&ip->client->packet.yiaddr, 0,
1737 sizeof(ip->client->packet.yiaddr));
1738 memset(&ip->client->packet.siaddr, 0,
1739 sizeof(ip->client->packet.siaddr));
1740 memset(&ip->client->packet.giaddr, 0,
1741 sizeof(ip->client->packet.giaddr));
1742 memcpy(ip->client->packet.chaddr,
1743 ip->hw_address.haddr, ip->hw_address.hlen);
1747 make_decline(struct interface_info *ip, struct client_lease *lease)
1749 struct tree_cache *options[256], message_type_tree;
1750 struct tree_cache requested_address_tree;
1751 struct tree_cache server_id_tree, client_id_tree;
1752 unsigned char decline = DHCPDECLINE;
1755 memset(options, 0, sizeof(options));
1756 memset(&ip->client->packet, 0, sizeof(ip->client->packet));
1758 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
1759 i = DHO_DHCP_MESSAGE_TYPE;
1760 options[i] = &message_type_tree;
1761 options[i]->value = &decline;
1762 options[i]->len = sizeof(decline);
1763 options[i]->buf_size = sizeof(decline);
1764 options[i]->timeout = 0xFFFFFFFF;
1766 /* Send back the server identifier... */
1767 i = DHO_DHCP_SERVER_IDENTIFIER;
1768 options[i] = &server_id_tree;
1769 options[i]->value = lease->options[i].data;
1770 options[i]->len = lease->options[i].len;
1771 options[i]->buf_size = lease->options[i].len;
1772 options[i]->timeout = 0xFFFFFFFF;
1774 /* Send back the address we're declining. */
1775 i = DHO_DHCP_REQUESTED_ADDRESS;
1776 options[i] = &requested_address_tree;
1777 options[i]->value = lease->address.iabuf;
1778 options[i]->len = lease->address.len;
1779 options[i]->buf_size = lease->address.len;
1780 options[i]->timeout = 0xFFFFFFFF;
1782 /* Send the uid if the user supplied one. */
1783 i = DHO_DHCP_CLIENT_IDENTIFIER;
1784 if (ip->client->config->send_options[i].len) {
1785 options[i] = &client_id_tree;
1786 options[i]->value = ip->client->config->send_options[i].data;
1787 options[i]->len = ip->client->config->send_options[i].len;
1788 options[i]->buf_size = ip->client->config->send_options[i].len;
1789 options[i]->timeout = 0xFFFFFFFF;
1793 /* Set up the option buffer... */
1794 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0,
1795 options, 0, 0, 0, NULL, 0);
1796 if (ip->client->packet_length < BOOTP_MIN_LEN)
1797 ip->client->packet_length = BOOTP_MIN_LEN;
1799 ip->client->packet.op = BOOTREQUEST;
1800 ip->client->packet.htype = ip->hw_address.htype;
1801 ip->client->packet.hlen = ip->hw_address.hlen;
1802 ip->client->packet.hops = 0;
1803 ip->client->packet.xid = ip->client->xid;
1804 ip->client->packet.secs = 0; /* Filled in by send_request. */
1805 ip->client->packet.flags = 0;
1807 /* ciaddr must always be zero. */
1808 memset(&ip->client->packet.ciaddr, 0,
1809 sizeof(ip->client->packet.ciaddr));
1810 memset(&ip->client->packet.yiaddr, 0,
1811 sizeof(ip->client->packet.yiaddr));
1812 memset(&ip->client->packet.siaddr, 0,
1813 sizeof(ip->client->packet.siaddr));
1814 memset(&ip->client->packet.giaddr, 0,
1815 sizeof(ip->client->packet.giaddr));
1816 memcpy(ip->client->packet.chaddr,
1817 ip->hw_address.haddr, ip->hw_address.hlen);
1821 free_client_lease(struct client_lease *lease)
1825 if (lease->server_name)
1826 free(lease->server_name);
1827 if (lease->filename)
1828 free(lease->filename);
1829 for (i = 0; i < 256; i++) {
1830 if (lease->options[i].len)
1831 free(lease->options[i].data);
1839 rewrite_client_leases(void)
1841 struct client_lease *lp;
1842 cap_rights_t rights;
1845 leaseFile = fopen(path_dhclient_db, "w");
1847 error("can't create %s: %m", path_dhclient_db);
1848 cap_rights_init(&rights, CAP_FSTAT, CAP_FSYNC, CAP_FTRUNCATE,
1849 CAP_SEEK, CAP_WRITE);
1850 if (cap_rights_limit(fileno(leaseFile), &rights) < 0 &&
1852 error("can't limit lease descriptor: %m");
1859 for (lp = ifi->client->leases; lp; lp = lp->next)
1860 write_client_lease(ifi, lp, 1);
1861 if (ifi->client->active)
1862 write_client_lease(ifi, ifi->client->active, 1);
1865 ftruncate(fileno(leaseFile), ftello(leaseFile));
1866 fsync(fileno(leaseFile));
1870 write_client_lease(struct interface_info *ip, struct client_lease *lease,
1873 static int leases_written;
1878 if (leases_written++ > 20) {
1879 rewrite_client_leases();
1884 /* If the lease came from the config file, we don't need to stash
1885 a copy in the lease database. */
1886 if (lease->is_static)
1889 if (!leaseFile) { /* XXX */
1890 leaseFile = fopen(path_dhclient_db, "w");
1892 error("can't create %s: %m", path_dhclient_db);
1895 fprintf(leaseFile, "lease {\n");
1896 if (lease->is_bootp)
1897 fprintf(leaseFile, " bootp;\n");
1898 fprintf(leaseFile, " interface \"%s\";\n", ip->name);
1899 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
1900 if (lease->nextserver.len == sizeof(inaddr_any) &&
1901 0 != memcmp(lease->nextserver.iabuf, &inaddr_any,
1902 sizeof(inaddr_any)))
1903 fprintf(leaseFile, " next-server %s;\n",
1904 piaddr(lease->nextserver));
1905 if (lease->filename)
1906 fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
1907 if (lease->server_name)
1908 fprintf(leaseFile, " server-name \"%s\";\n",
1909 lease->server_name);
1911 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string);
1912 for (i = 0; i < 256; i++)
1913 if (lease->options[i].len)
1914 fprintf(leaseFile, " option %s %s;\n",
1915 dhcp_options[i].name,
1916 pretty_print_option(i, lease->options[i].data,
1917 lease->options[i].len, 1, 1));
1919 t = gmtime(&lease->renewal);
1920 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n",
1921 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1922 t->tm_hour, t->tm_min, t->tm_sec);
1923 t = gmtime(&lease->rebind);
1924 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n",
1925 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1926 t->tm_hour, t->tm_min, t->tm_sec);
1927 t = gmtime(&lease->expiry);
1928 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n",
1929 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
1930 t->tm_hour, t->tm_min, t->tm_sec);
1931 fprintf(leaseFile, "}\n");
1936 script_init(char *reason, struct string_list *medium)
1938 size_t len, mediumlen = 0;
1939 struct imsg_hdr hdr;
1943 if (medium != NULL && medium->string != NULL)
1944 mediumlen = strlen(medium->string);
1946 hdr.code = IMSG_SCRIPT_INIT;
1947 hdr.len = sizeof(struct imsg_hdr) +
1948 sizeof(size_t) + mediumlen +
1949 sizeof(size_t) + strlen(reason);
1951 if ((buf = buf_open(hdr.len)) == NULL)
1952 error("buf_open: %m");
1955 errs += buf_add(buf, &hdr, sizeof(hdr));
1956 errs += buf_add(buf, &mediumlen, sizeof(mediumlen));
1958 errs += buf_add(buf, medium->string, mediumlen);
1959 len = strlen(reason);
1960 errs += buf_add(buf, &len, sizeof(len));
1961 errs += buf_add(buf, reason, len);
1964 error("buf_add: %m");
1966 if (buf_close(privfd, buf) == -1)
1967 error("buf_close: %m");
1971 priv_script_init(char *reason, char *medium)
1973 struct interface_info *ip = ifi;
1976 ip->client->scriptEnvsize = 100;
1977 if (ip->client->scriptEnv == NULL)
1978 ip->client->scriptEnv =
1979 malloc(ip->client->scriptEnvsize * sizeof(char *));
1980 if (ip->client->scriptEnv == NULL)
1981 error("script_init: no memory for environment");
1983 ip->client->scriptEnv[0] = strdup(CLIENT_PATH);
1984 if (ip->client->scriptEnv[0] == NULL)
1985 error("script_init: no memory for environment");
1987 ip->client->scriptEnv[1] = NULL;
1989 script_set_env(ip->client, "", "interface", ip->name);
1992 script_set_env(ip->client, "", "medium", medium);
1994 script_set_env(ip->client, "", "reason", reason);
1999 priv_script_write_params(char *prefix, struct client_lease *lease)
2001 struct interface_info *ip = ifi;
2002 u_int8_t dbuf[1500], *dp = NULL;
2006 script_set_env(ip->client, prefix, "ip_address",
2007 piaddr(lease->address));
2009 if (ip->client->config->default_actions[DHO_SUBNET_MASK] ==
2011 dp = ip->client->config->defaults[DHO_SUBNET_MASK].data;
2012 len = ip->client->config->defaults[DHO_SUBNET_MASK].len;
2014 dp = lease->options[DHO_SUBNET_MASK].data;
2015 len = lease->options[DHO_SUBNET_MASK].len;
2017 if (len && (len < sizeof(lease->address.iabuf))) {
2018 struct iaddr netmask, subnet, broadcast;
2020 memcpy(netmask.iabuf, dp, len);
2022 subnet = subnet_number(lease->address, netmask);
2024 script_set_env(ip->client, prefix, "network_number",
2026 if (!lease->options[DHO_BROADCAST_ADDRESS].len) {
2027 broadcast = broadcast_addr(subnet, netmask);
2029 script_set_env(ip->client, prefix,
2030 "broadcast_address",
2036 if (lease->filename)
2037 script_set_env(ip->client, prefix, "filename", lease->filename);
2038 if (lease->server_name)
2039 script_set_env(ip->client, prefix, "server_name",
2040 lease->server_name);
2041 for (i = 0; i < 256; i++) {
2044 if (ip->client->config->defaults[i].len) {
2045 if (lease->options[i].len) {
2047 ip->client->config->default_actions[i]) {
2048 case ACTION_DEFAULT:
2049 dp = lease->options[i].data;
2050 len = lease->options[i].len;
2052 case ACTION_SUPERSEDE:
2055 config->defaults[i].data;
2057 config->defaults[i].len;
2059 case ACTION_PREPEND:
2061 config->defaults[i].len +
2062 lease->options[i].len;
2063 if (len >= sizeof(dbuf)) {
2064 warning("no space to %s %s",
2066 dhcp_options[i].name);
2072 config->defaults[i].data,
2074 config->defaults[i].len);
2075 memcpy(dp + ip->client->
2076 config->defaults[i].len,
2077 lease->options[i].data,
2078 lease->options[i].len);
2083 * When we append, we assume that we're
2084 * appending to text. Some MS servers
2085 * include a NUL byte at the end of
2086 * the search string provided.
2089 config->defaults[i].len +
2090 lease->options[i].len;
2091 if (len >= sizeof(dbuf)) {
2092 warning("no space to %s %s",
2094 dhcp_options[i].name);
2098 lease->options[i].data,
2099 lease->options[i].len);
2100 for (dp = dbuf + lease->options[i].len;
2101 dp > dbuf; dp--, len--)
2106 config->defaults[i].data,
2108 config->defaults[i].len);
2114 config->defaults[i].data;
2116 config->defaults[i].len;
2118 } else if (lease->options[i].len) {
2119 len = lease->options[i].len;
2120 dp = lease->options[i].data;
2127 if (dhcp_option_ev_name(name, sizeof(name),
2129 script_set_env(ip->client, prefix, name,
2130 pretty_print_option(i, dp, len, 0, 0));
2133 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry);
2134 script_set_env(ip->client, prefix, "expiry", tbuf);
2138 script_write_params(char *prefix, struct client_lease *lease)
2140 size_t fn_len = 0, sn_len = 0, pr_len = 0;
2141 struct imsg_hdr hdr;
2145 if (lease->filename != NULL)
2146 fn_len = strlen(lease->filename);
2147 if (lease->server_name != NULL)
2148 sn_len = strlen(lease->server_name);
2150 pr_len = strlen(prefix);
2152 hdr.code = IMSG_SCRIPT_WRITE_PARAMS;
2153 hdr.len = sizeof(hdr) + sizeof(struct client_lease) +
2154 sizeof(size_t) + fn_len + sizeof(size_t) + sn_len +
2155 sizeof(size_t) + pr_len;
2157 for (i = 0; i < 256; i++)
2158 hdr.len += sizeof(int) + lease->options[i].len;
2160 scripttime = time(NULL);
2162 if ((buf = buf_open(hdr.len)) == NULL)
2163 error("buf_open: %m");
2166 errs += buf_add(buf, &hdr, sizeof(hdr));
2167 errs += buf_add(buf, lease, sizeof(struct client_lease));
2168 errs += buf_add(buf, &fn_len, sizeof(fn_len));
2169 errs += buf_add(buf, lease->filename, fn_len);
2170 errs += buf_add(buf, &sn_len, sizeof(sn_len));
2171 errs += buf_add(buf, lease->server_name, sn_len);
2172 errs += buf_add(buf, &pr_len, sizeof(pr_len));
2173 errs += buf_add(buf, prefix, pr_len);
2175 for (i = 0; i < 256; i++) {
2176 errs += buf_add(buf, &lease->options[i].len,
2177 sizeof(lease->options[i].len));
2178 errs += buf_add(buf, lease->options[i].data,
2179 lease->options[i].len);
2183 error("buf_add: %m");
2185 if (buf_close(privfd, buf) == -1)
2186 error("buf_close: %m");
2192 struct imsg_hdr hdr;
2196 hdr.code = IMSG_SCRIPT_GO;
2197 hdr.len = sizeof(struct imsg_hdr);
2199 if ((buf = buf_open(hdr.len)) == NULL)
2200 error("buf_open: %m");
2202 if (buf_add(buf, &hdr, sizeof(hdr)))
2203 error("buf_add: %m");
2205 if (buf_close(privfd, buf) == -1)
2206 error("buf_close: %m");
2208 bzero(&hdr, sizeof(hdr));
2209 buf_read(privfd, &hdr, sizeof(hdr));
2210 if (hdr.code != IMSG_SCRIPT_GO_RET)
2211 error("unexpected msg type %u", hdr.code);
2212 if (hdr.len != sizeof(hdr) + sizeof(int))
2213 error("received corrupted message");
2214 buf_read(privfd, &ret, sizeof(ret));
2216 scripttime = time(NULL);
2222 priv_script_go(void)
2224 char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI";
2225 static char client_path[] = CLIENT_PATH;
2226 struct interface_info *ip = ifi;
2227 int pid, wpid, wstatus;
2229 scripttime = time(NULL);
2232 scriptName = ip->client->config->script_name;
2233 envp = ip->client->scriptEnv;
2235 scriptName = top_level_config.script_name;
2237 epp[1] = client_path;
2242 argv[0] = scriptName;
2251 wpid = wait(&wstatus);
2252 } while (wpid != pid && wpid > 0);
2258 execve(scriptName, argv, envp);
2259 error("execve (%s, ...): %m", scriptName);
2263 script_flush_env(ip->client);
2265 return (wstatus & 0xff);
2269 script_set_env(struct client_state *client, const char *prefix,
2270 const char *name, const char *value)
2274 namelen = strlen(name);
2276 for (i = 0; client->scriptEnv[i]; i++)
2277 if (strncmp(client->scriptEnv[i], name, namelen) == 0 &&
2278 client->scriptEnv[i][namelen] == '=')
2281 if (client->scriptEnv[i])
2282 /* Reuse the slot. */
2283 free(client->scriptEnv[i]);
2285 /* New variable. Expand if necessary. */
2286 if (i >= client->scriptEnvsize - 1) {
2287 char **newscriptEnv;
2288 int newscriptEnvsize = client->scriptEnvsize + 50;
2290 newscriptEnv = realloc(client->scriptEnv,
2292 if (newscriptEnv == NULL) {
2293 free(client->scriptEnv);
2294 client->scriptEnv = NULL;
2295 client->scriptEnvsize = 0;
2296 error("script_set_env: no memory for variable");
2298 client->scriptEnv = newscriptEnv;
2299 client->scriptEnvsize = newscriptEnvsize;
2301 /* need to set the NULL pointer at end of array beyond
2303 client->scriptEnv[i + 1] = NULL;
2305 /* Allocate space and format the variable in the appropriate slot. */
2306 client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 +
2308 if (client->scriptEnv[i] == NULL)
2309 error("script_set_env: no memory for variable assignment");
2311 /* No `` or $() command substitution allowed in environment values! */
2312 for (j=0; j < strlen(value); j++)
2316 error("illegal character (%c) in value '%s'", value[j],
2320 snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
2321 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
2325 script_flush_env(struct client_state *client)
2329 for (i = 0; client->scriptEnv[i]; i++) {
2330 free(client->scriptEnv[i]);
2331 client->scriptEnv[i] = NULL;
2333 client->scriptEnvsize = 0;
2337 dhcp_option_ev_name(char *buf, size_t buflen, struct option *option)
2341 for (i = 0; option->name[i]; i++) {
2342 if (i + 1 == buflen)
2344 if (option->name[i] == '-')
2347 buf[i] = option->name[i];
2357 static int state = 0;
2358 cap_rights_t rights;
2360 if (no_daemon || state)
2365 /* Stop logging to stderr... */
2368 if (daemon(1, 0) == -1)
2371 cap_rights_init(&rights);
2373 if (pidfile != NULL) {
2374 pidfile_write(pidfile);
2375 if (cap_rights_limit(pidfile_fileno(pidfile), &rights) < 0 &&
2377 error("can't limit pidfile descriptor: %m");
2381 /* we are chrooted, daemon(3) fails to open /dev/null */
2383 dup2(nullfd, STDIN_FILENO);
2384 dup2(nullfd, STDOUT_FILENO);
2385 dup2(nullfd, STDERR_FILENO);
2390 if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS)
2391 error("can't limit stdin: %m");
2392 cap_rights_init(&rights, CAP_WRITE);
2393 if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS)
2394 error("can't limit stdout: %m");
2395 if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS)
2396 error("can't limit stderr: %m");
2400 check_option(struct client_lease *l, int option)
2405 /* we use this, since this is what gets passed to dhclient-script */
2407 opbuf = pretty_print_option(option, l->options[option].data,
2408 l->options[option].len, 0, 0);
2410 sbuf = option_as_string(option, l->options[option].data,
2411 l->options[option].len);
2414 case DHO_SUBNET_MASK:
2415 case DHO_TIME_SERVERS:
2416 case DHO_NAME_SERVERS:
2418 case DHO_DOMAIN_NAME_SERVERS:
2419 case DHO_LOG_SERVERS:
2420 case DHO_COOKIE_SERVERS:
2421 case DHO_LPR_SERVERS:
2422 case DHO_IMPRESS_SERVERS:
2423 case DHO_RESOURCE_LOCATION_SERVERS:
2424 case DHO_SWAP_SERVER:
2425 case DHO_BROADCAST_ADDRESS:
2426 case DHO_NIS_SERVERS:
2427 case DHO_NTP_SERVERS:
2428 case DHO_NETBIOS_NAME_SERVERS:
2429 case DHO_NETBIOS_DD_SERVER:
2430 case DHO_FONT_SERVERS:
2431 case DHO_DHCP_SERVER_IDENTIFIER:
2432 case DHO_NISPLUS_SERVERS:
2433 case DHO_MOBILE_IP_HOME_AGENT:
2434 case DHO_SMTP_SERVER:
2435 case DHO_POP_SERVER:
2436 case DHO_NNTP_SERVER:
2437 case DHO_WWW_SERVER:
2438 case DHO_FINGER_SERVER:
2439 case DHO_IRC_SERVER:
2440 case DHO_STREETTALK_SERVER:
2441 case DHO_STREETTALK_DA_SERVER:
2442 if (!ipv4addrs(opbuf)) {
2443 warning("Invalid IP address in option: %s", opbuf);
2448 case DHO_NIS_DOMAIN:
2449 case DHO_NISPLUS_DOMAIN:
2450 case DHO_TFTP_SERVER_NAME:
2451 if (!res_hnok(sbuf)) {
2452 warning("Bogus Host Name option %d: %s (%s)", option,
2454 l->options[option].len = 0;
2455 free(l->options[option].data);
2458 case DHO_DOMAIN_NAME:
2459 case DHO_DOMAIN_SEARCH:
2460 if (!res_hnok(sbuf)) {
2461 if (!check_search(sbuf)) {
2462 warning("Bogus domain search list %d: %s (%s)",
2463 option, sbuf, opbuf);
2464 l->options[option].len = 0;
2465 free(l->options[option].data);
2470 case DHO_TIME_OFFSET:
2472 case DHO_MERIT_DUMP:
2474 case DHO_EXTENSIONS_PATH:
2475 case DHO_IP_FORWARDING:
2476 case DHO_NON_LOCAL_SOURCE_ROUTING:
2477 case DHO_POLICY_FILTER:
2478 case DHO_MAX_DGRAM_REASSEMBLY:
2479 case DHO_DEFAULT_IP_TTL:
2480 case DHO_PATH_MTU_AGING_TIMEOUT:
2481 case DHO_PATH_MTU_PLATEAU_TABLE:
2482 case DHO_INTERFACE_MTU:
2483 case DHO_ALL_SUBNETS_LOCAL:
2484 case DHO_PERFORM_MASK_DISCOVERY:
2485 case DHO_MASK_SUPPLIER:
2486 case DHO_ROUTER_DISCOVERY:
2487 case DHO_ROUTER_SOLICITATION_ADDRESS:
2488 case DHO_STATIC_ROUTES:
2489 case DHO_TRAILER_ENCAPSULATION:
2490 case DHO_ARP_CACHE_TIMEOUT:
2491 case DHO_IEEE802_3_ENCAPSULATION:
2492 case DHO_DEFAULT_TCP_TTL:
2493 case DHO_TCP_KEEPALIVE_INTERVAL:
2494 case DHO_TCP_KEEPALIVE_GARBAGE:
2495 case DHO_VENDOR_ENCAPSULATED_OPTIONS:
2496 case DHO_NETBIOS_NODE_TYPE:
2497 case DHO_NETBIOS_SCOPE:
2498 case DHO_X_DISPLAY_MANAGER:
2499 case DHO_DHCP_REQUESTED_ADDRESS:
2500 case DHO_DHCP_LEASE_TIME:
2501 case DHO_DHCP_OPTION_OVERLOAD:
2502 case DHO_DHCP_MESSAGE_TYPE:
2503 case DHO_DHCP_PARAMETER_REQUEST_LIST:
2504 case DHO_DHCP_MESSAGE:
2505 case DHO_DHCP_MAX_MESSAGE_SIZE:
2506 case DHO_DHCP_RENEWAL_TIME:
2507 case DHO_DHCP_REBINDING_TIME:
2508 case DHO_DHCP_CLASS_IDENTIFIER:
2509 case DHO_DHCP_CLIENT_IDENTIFIER:
2510 case DHO_BOOTFILE_NAME:
2511 case DHO_DHCP_USER_CLASS_ID:
2514 case DHO_CLASSLESS_ROUTES:
2515 return (check_classless_option(l->options[option].data,
2516 l->options[option].len));
2518 warning("unknown dhcp option value 0x%x", option);
2519 return (unknown_ok);
2523 /* RFC 3442 The Classless Static Routes option checks */
2525 check_classless_option(unsigned char *data, int len)
2528 unsigned char width;
2529 in_addr_t addr, mask;
2532 warning("Too small length: %d", len);
2540 } else if (width < 9) {
2541 addr = (in_addr_t)(data[i] << 24);
2543 } else if (width < 17) {
2544 addr = (in_addr_t)(data[i] << 24) +
2545 (in_addr_t)(data[i + 1] << 16);
2547 } else if (width < 25) {
2548 addr = (in_addr_t)(data[i] << 24) +
2549 (in_addr_t)(data[i + 1] << 16) +
2550 (in_addr_t)(data[i + 2] << 8);
2552 } else if (width < 33) {
2553 addr = (in_addr_t)(data[i] << 24) +
2554 (in_addr_t)(data[i + 1] << 16) +
2555 (in_addr_t)(data[i + 2] << 8) +
2559 warning("Incorrect subnet width: %d", width);
2562 mask = (in_addr_t)(~0) << (32 - width);
2568 * ... After deriving a subnet number and subnet mask
2569 * from each destination descriptor, the DHCP client
2570 * MUST zero any bits in the subnet number where the
2571 * corresponding bit in the mask is zero...
2573 if ((addr & mask) != addr) {
2575 data[i - 1] = (unsigned char)(
2576 (addr >> (((32 - width)/8)*8)) & 0xFF);
2581 warning("Incorrect data length: %d (must be %d)", len, i);
2588 res_hnok(const char *dn)
2590 int pch = PERIOD, ch = *dn++;
2592 while (ch != '\0') {
2595 if (periodchar(ch)) {
2597 } else if (periodchar(pch)) {
2598 if (!borderchar(ch))
2600 } else if (periodchar(nch) || nch == '\0') {
2601 if (!borderchar(ch))
2604 if (!middlechar(ch))
2613 check_search(const char *srch)
2615 int pch = PERIOD, ch = *srch++;
2618 /* 256 char limit re resolv.conf(5) */
2619 if (strlen(srch) > 256)
2622 while (whitechar(ch))
2625 while (ch != '\0') {
2628 if (periodchar(ch) || whitechar(ch)) {
2630 } else if (periodchar(pch)) {
2631 if (!borderchar(ch))
2633 } else if (periodchar(nch) || nch == '\0') {
2634 if (!borderchar(ch))
2637 if (!middlechar(ch))
2640 if (!whitechar(ch)) {
2643 while (whitechar(nch)) {
2652 /* 6 domain limit re resolv.conf(5) */
2658 /* Does buf consist only of dotted decimal ipv4 addrs?
2659 * return how many if so,
2660 * otherwise, return 0
2663 ipv4addrs(char * buf)
2668 while (inet_aton(buf, &jnk) == 1){
2670 while (periodchar(*buf) || digitchar(*buf))
2682 option_as_string(unsigned int code, unsigned char *data, int len)
2684 static char optbuf[32768]; /* XXX */
2686 int opleft = sizeof(optbuf);
2687 unsigned char *dp = data;
2690 error("option_as_string: bad code %d", code);
2692 for (; dp < data + len; dp++) {
2693 if (!isascii(*dp) || !isprint(*dp)) {
2694 if (dp + 1 != data + len || *dp != 0) {
2695 snprintf(op, opleft, "\\%03o", *dp);
2699 } else if (*dp == '"' || *dp == '\'' || *dp == '$' ||
2700 *dp == '`' || *dp == '\\') {
2714 warning("dhcp option too large");
2719 fork_privchld(int fd, int fd2)
2721 struct pollfd pfd[1];
2726 error("cannot fork");
2733 setproctitle("%s [priv]", ifi->name);
2736 dup2(nullfd, STDIN_FILENO);
2737 dup2(nullfd, STDOUT_FILENO);
2738 dup2(nullfd, STDERR_FILENO);
2746 pfd[0].events = POLLIN;
2747 if ((nfds = poll(pfd, 1, INFTIM)) == -1)
2749 error("poll error");
2751 if (nfds == 0 || !(pfd[0].revents & POLLIN))
2754 dispatch_imsg(ifi, fd);