1 /* $OpenBSD: dhclient.c,v 1.63 2005/02/06 17:10:13 krw Exp $ */ 2 3 /* 4 * Copyright 2004 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 1995, 1996, 1997, 1998, 1999 6 * The Internet Software Consortium. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 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. 20 * 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 33 * SUCH DAMAGE. 34 * 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''. 40 * 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 43 * Stanford. 44 * 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 53 * purpose. 54 */ 55 56 #include <sys/cdefs.h> 57 __FBSDID("$FreeBSD$"); 58 59 #include <sys/capability.h> 60 61 #include "dhcpd.h" 62 #include "privsep.h" 63 64 #include <sys/capability.h> 65 66 #include <net80211/ieee80211_freebsd.h> 67 68 #ifndef _PATH_VAREMPTY 69 #define _PATH_VAREMPTY "/var/empty" 70 #endif 71 72 #define PERIOD 0x2e 73 #define hyphenchar(c) ((c) == 0x2d) 74 #define bslashchar(c) ((c) == 0x5c) 75 #define periodchar(c) ((c) == PERIOD) 76 #define asterchar(c) ((c) == 0x2a) 77 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) || \ 78 ((c) >= 0x61 && (c) <= 0x7a)) 79 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) 80 #define whitechar(c) ((c) == ' ' || (c) == '\t') 81 82 #define borderchar(c) (alphachar(c) || digitchar(c)) 83 #define middlechar(c) (borderchar(c) || hyphenchar(c)) 84 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f) 85 86 #define CLIENT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin" 87 88 time_t cur_time; 89 time_t default_lease_time = 43200; /* 12 hours... */ 90 91 char *path_dhclient_conf = _PATH_DHCLIENT_CONF; 92 char *path_dhclient_db = NULL; 93 94 int log_perror = 1; 95 int privfd; 96 int nullfd = -1; 97 98 char hostname[_POSIX_HOST_NAME_MAX + 1]; 99 100 struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; 101 struct in_addr inaddr_any, inaddr_broadcast; 102 103 char *path_dhclient_pidfile; 104 struct pidfh *pidfile; 105 106 /* 107 * ASSERT_STATE() does nothing now; it used to be 108 * assert (state_is == state_shouldbe). 109 */ 110 #define ASSERT_STATE(state_is, state_shouldbe) {} 111 112 #define TIME_MAX 2147483647 113 114 int log_priority; 115 int no_daemon; 116 int unknown_ok = 1; 117 int routefd; 118 119 struct interface_info *ifi; 120 121 int findproto(char *, int); 122 struct sockaddr *get_ifa(char *, int); 123 void routehandler(struct protocol *); 124 void usage(void); 125 int check_option(struct client_lease *l, int option); 126 int check_classless_option(unsigned char *data, int len); 127 int ipv4addrs(char * buf); 128 int res_hnok(const char *dn); 129 int check_search(const char *srch); 130 char *option_as_string(unsigned int code, unsigned char *data, int len); 131 int fork_privchld(int, int); 132 133 #define ROUNDUP(a) \ 134 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 135 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 136 137 static time_t scripttime; 138 139 int 140 findproto(char *cp, int n) 141 { 142 struct sockaddr *sa; 143 int i; 144 145 if (n == 0) 146 return -1; 147 for (i = 1; i; i <<= 1) { 148 if (i & n) { 149 sa = (struct sockaddr *)cp; 150 switch (i) { 151 case RTA_IFA: 152 case RTA_DST: 153 case RTA_GATEWAY: 154 case RTA_NETMASK: 155 if (sa->sa_family == AF_INET) 156 return AF_INET; 157 if (sa->sa_family == AF_INET6) 158 return AF_INET6; 159 break; 160 case RTA_IFP: 161 break; 162 } 163 ADVANCE(cp, sa); 164 } 165 } 166 return (-1); 167 } 168 169 struct sockaddr * 170 get_ifa(char *cp, int n) 171 { 172 struct sockaddr *sa; 173 int i; 174 175 if (n == 0) 176 return (NULL); 177 for (i = 1; i; i <<= 1) 178 if (i & n) { 179 sa = (struct sockaddr *)cp; 180 if (i == RTA_IFA) 181 return (sa); 182 ADVANCE(cp, sa); 183 } 184 185 return (NULL); 186 } 187 188 struct iaddr defaddr = { 4 }; 189 uint8_t curbssid[6]; 190 191 static void 192 disassoc(void *arg) 193 { 194 struct interface_info *ifi = arg; 195 196 /* 197 * Clear existing state. 198 */ 199 if (ifi->client->active != NULL) { 200 script_init("EXPIRE", NULL); 201 script_write_params("old_", 202 ifi->client->active); 203 if (ifi->client->alias) 204 script_write_params("alias_", 205 ifi->client->alias); 206 script_go(); 207 } 208 ifi->client->state = S_INIT; 209 } 210 211 /* ARGSUSED */ 212 void 213 routehandler(struct protocol *p) 214 { 215 char msg[2048], *addr; 216 struct rt_msghdr *rtm; 217 struct if_msghdr *ifm; 218 struct ifa_msghdr *ifam; 219 struct if_announcemsghdr *ifan; 220 struct ieee80211_join_event *jev; 221 struct client_lease *l; 222 time_t t = time(NULL); 223 struct sockaddr *sa; 224 struct iaddr a; 225 ssize_t n; 226 int linkstat; 227 228 n = read(routefd, &msg, sizeof(msg)); 229 rtm = (struct rt_msghdr *)msg; 230 if (n < sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen || 231 rtm->rtm_version != RTM_VERSION) 232 return; 233 234 switch (rtm->rtm_type) { 235 case RTM_NEWADDR: 236 case RTM_DELADDR: 237 ifam = (struct ifa_msghdr *)rtm; 238 239 if (ifam->ifam_index != ifi->index) 240 break; 241 if (findproto((char *)(ifam + 1), ifam->ifam_addrs) != AF_INET) 242 break; 243 if (scripttime == 0 || t < scripttime + 10) 244 break; 245 246 sa = get_ifa((char *)(ifam + 1), ifam->ifam_addrs); 247 if (sa == NULL) 248 break; 249 250 if ((a.len = sizeof(struct in_addr)) > sizeof(a.iabuf)) 251 error("king bula sez: len mismatch"); 252 memcpy(a.iabuf, &((struct sockaddr_in *)sa)->sin_addr, a.len); 253 if (addr_eq(a, defaddr)) 254 break; 255 256 for (l = ifi->client->active; l != NULL; l = l->next) 257 if (addr_eq(a, l->address)) 258 break; 259 260 if (l == NULL) /* added/deleted addr is not the one we set */ 261 break; 262 263 addr = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr); 264 if (rtm->rtm_type == RTM_NEWADDR) { 265 /* 266 * XXX: If someone other than us adds our address, 267 * should we assume they are taking over from us, 268 * delete the lease record, and exit without modifying 269 * the interface? 270 */ 271 warning("My address (%s) was re-added", addr); 272 } else { 273 warning("My address (%s) was deleted, dhclient exiting", 274 addr); 275 goto die; 276 } 277 break; 278 case RTM_IFINFO: 279 ifm = (struct if_msghdr *)rtm; 280 if (ifm->ifm_index != ifi->index) 281 break; 282 if ((rtm->rtm_flags & RTF_UP) == 0) { 283 warning("Interface %s is down, dhclient exiting", 284 ifi->name); 285 goto die; 286 } 287 linkstat = interface_link_status(ifi->name); 288 if (linkstat != ifi->linkstat) { 289 debug("%s link state %s -> %s", ifi->name, 290 ifi->linkstat ? "up" : "down", 291 linkstat ? "up" : "down"); 292 ifi->linkstat = linkstat; 293 if (linkstat) 294 state_reboot(ifi); 295 } 296 break; 297 case RTM_IFANNOUNCE: 298 ifan = (struct if_announcemsghdr *)rtm; 299 if (ifan->ifan_what == IFAN_DEPARTURE && 300 ifan->ifan_index == ifi->index) { 301 warning("Interface %s is gone, dhclient exiting", 302 ifi->name); 303 goto die; 304 } 305 break; 306 case RTM_IEEE80211: 307 ifan = (struct if_announcemsghdr *)rtm; 308 if (ifan->ifan_index != ifi->index) 309 break; 310 switch (ifan->ifan_what) { 311 case RTM_IEEE80211_ASSOC: 312 case RTM_IEEE80211_REASSOC: 313 /* 314 * Use assoc/reassoc event to kick state machine 315 * in case we roam. Otherwise fall back to the 316 * normal state machine just like a wired network. 317 */ 318 jev = (struct ieee80211_join_event *) &ifan[1]; 319 if (memcmp(curbssid, jev->iev_addr, 6)) { 320 disassoc(ifi); 321 state_reboot(ifi); 322 } 323 memcpy(curbssid, jev->iev_addr, 6); 324 break; 325 } 326 break; 327 default: 328 break; 329 } 330 return; 331 332 die: 333 script_init("FAIL", NULL); 334 if (ifi->client->alias) 335 script_write_params("alias_", ifi->client->alias); 336 script_go(); 337 if (pidfile != NULL) 338 pidfile_remove(pidfile); 339 exit(1); 340 } 341 342 int 343 main(int argc, char *argv[]) 344 { 345 extern char *__progname; 346 int ch, fd, quiet = 0, i = 0; 347 int pipe_fd[2]; 348 int immediate_daemon = 0; 349 struct passwd *pw; 350 pid_t otherpid; 351 cap_rights_t rights; 352 353 /* Initially, log errors to stderr as well as to syslogd. */ 354 openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY); 355 setlogmask(LOG_UPTO(LOG_DEBUG)); 356 357 while ((ch = getopt(argc, argv, "bc:dl:p:qu")) != -1) 358 switch (ch) { 359 case 'b': 360 immediate_daemon = 1; 361 break; 362 case 'c': 363 path_dhclient_conf = optarg; 364 break; 365 case 'd': 366 no_daemon = 1; 367 break; 368 case 'l': 369 path_dhclient_db = optarg; 370 break; 371 case 'p': 372 path_dhclient_pidfile = optarg; 373 break; 374 case 'q': 375 quiet = 1; 376 break; 377 case 'u': 378 unknown_ok = 0; 379 break; 380 default: 381 usage(); 382 } 383 384 argc -= optind; 385 argv += optind; 386 387 if (argc != 1) 388 usage(); 389 390 if (path_dhclient_pidfile == NULL) { 391 asprintf(&path_dhclient_pidfile, 392 "%sdhclient.%s.pid", _PATH_VARRUN, *argv); 393 if (path_dhclient_pidfile == NULL) 394 error("asprintf"); 395 } 396 pidfile = pidfile_open(path_dhclient_pidfile, 0600, &otherpid); 397 if (pidfile == NULL) { 398 if (errno == EEXIST) 399 error("dhclient already running, pid: %d.", otherpid); 400 if (errno == EAGAIN) 401 error("dhclient already running."); 402 warning("Cannot open or create pidfile: %m"); 403 } 404 405 if ((ifi = calloc(1, sizeof(struct interface_info))) == NULL) 406 error("calloc"); 407 if (strlcpy(ifi->name, argv[0], IFNAMSIZ) >= IFNAMSIZ) 408 error("Interface name too long"); 409 if (path_dhclient_db == NULL && asprintf(&path_dhclient_db, "%s.%s", 410 _PATH_DHCLIENT_DB, ifi->name) == -1) 411 error("asprintf"); 412 413 if (quiet) 414 log_perror = 0; 415 416 tzset(); 417 time(&cur_time); 418 419 inaddr_broadcast.s_addr = INADDR_BROADCAST; 420 inaddr_any.s_addr = INADDR_ANY; 421 422 read_client_conf(); 423 424 /* The next bit is potentially very time-consuming, so write out 425 the pidfile right away. We will write it out again with the 426 correct pid after daemonizing. */ 427 if (pidfile != NULL) 428 pidfile_write(pidfile); 429 430 if (!interface_link_status(ifi->name)) { 431 fprintf(stderr, "%s: no link ...", ifi->name); 432 fflush(stderr); 433 sleep(1); 434 while (!interface_link_status(ifi->name)) { 435 fprintf(stderr, "."); 436 fflush(stderr); 437 if (++i > 10) { 438 fprintf(stderr, " giving up\n"); 439 exit(1); 440 } 441 sleep(1); 442 } 443 fprintf(stderr, " got link\n"); 444 } 445 ifi->linkstat = 1; 446 447 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) 448 error("cannot open %s: %m", _PATH_DEVNULL); 449 450 if ((pw = getpwnam("_dhcp")) == NULL) { 451 warning("no such user: _dhcp, falling back to \"nobody\""); 452 if ((pw = getpwnam("nobody")) == NULL) 453 error("no such user: nobody"); 454 } 455 456 /* 457 * Obtain hostname before entering capability mode - it won't be 458 * possible then, as reading kern.hostname is not permitted. 459 */ 460 if (gethostname(hostname, sizeof(hostname)) < 0) 461 hostname[0] = '\0'; 462 463 priv_script_init("PREINIT", NULL); 464 if (ifi->client->alias) 465 priv_script_write_params("alias_", ifi->client->alias); 466 priv_script_go(); 467 468 /* set up the interface */ 469 discover_interfaces(ifi); 470 471 if (pipe(pipe_fd) == -1) 472 error("pipe"); 473 474 fork_privchld(pipe_fd[0], pipe_fd[1]); 475 476 close(ifi->ufdesc); 477 ifi->ufdesc = -1; 478 close(ifi->wfdesc); 479 ifi->wfdesc = -1; 480 481 close(pipe_fd[0]); 482 privfd = pipe_fd[1]; 483 cap_rights_init(&rights, CAP_READ, CAP_WRITE); 484 if (cap_rights_limit(privfd, &rights) < 0 && errno != ENOSYS) 485 error("can't limit private descriptor: %m"); 486 487 if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1) 488 error("can't open and lock %s: %m", path_dhclient_db); 489 read_client_leases(); 490 rewrite_client_leases(); 491 close(fd); 492 493 if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1) 494 add_protocol("AF_ROUTE", routefd, routehandler, ifi); 495 if (shutdown(routefd, SHUT_WR) < 0) 496 error("can't shutdown route socket: %m"); 497 cap_rights_init(&rights, CAP_POLL_EVENT, CAP_READ); 498 if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS) 499 error("can't limit route socket: %m"); 500 501 if (chroot(_PATH_VAREMPTY) == -1) 502 error("chroot"); 503 if (chdir("/") == -1) 504 error("chdir(\"/\")"); 505 506 if (setgroups(1, &pw->pw_gid) || 507 setegid(pw->pw_gid) || setgid(pw->pw_gid) || 508 seteuid(pw->pw_uid) || setuid(pw->pw_uid)) 509 error("can't drop privileges: %m"); 510 511 endpwent(); 512 513 setproctitle("%s", ifi->name); 514 515 if (cap_enter() < 0 && errno != ENOSYS) 516 error("can't enter capability mode: %m"); 517 518 if (immediate_daemon) 519 go_daemon(); 520 521 ifi->client->state = S_INIT; 522 state_reboot(ifi); 523 524 bootp_packet_handler = do_packet; 525 526 dispatch(); 527 528 /* not reached */ 529 return (0); 530 } 531 532 void 533 usage(void) 534 { 535 extern char *__progname; 536 537 fprintf(stderr, "usage: %s [-bdqu] ", __progname); 538 fprintf(stderr, "[-c conffile] [-l leasefile] interface\n"); 539 exit(1); 540 } 541 542 /* 543 * Individual States: 544 * 545 * Each routine is called from the dhclient_state_machine() in one of 546 * these conditions: 547 * -> entering INIT state 548 * -> recvpacket_flag == 0: timeout in this state 549 * -> otherwise: received a packet in this state 550 * 551 * Return conditions as handled by dhclient_state_machine(): 552 * Returns 1, sendpacket_flag = 1: send packet, reset timer. 553 * Returns 1, sendpacket_flag = 0: just reset the timer (wait for a milestone). 554 * Returns 0: finish the nap which was interrupted for no good reason. 555 * 556 * Several per-interface variables are used to keep track of the process: 557 * active_lease: the lease that is being used on the interface 558 * (null pointer if not configured yet). 559 * offered_leases: leases corresponding to DHCPOFFER messages that have 560 * been sent to us by DHCP servers. 561 * acked_leases: leases corresponding to DHCPACK messages that have been 562 * sent to us by DHCP servers. 563 * sendpacket: DHCP packet we're trying to send. 564 * destination: IP address to send sendpacket to 565 * In addition, there are several relevant per-lease variables. 566 * T1_expiry, T2_expiry, lease_expiry: lease milestones 567 * In the active lease, these control the process of renewing the lease; 568 * In leases on the acked_leases list, this simply determines when we 569 * can no longer legitimately use the lease. 570 */ 571 572 void 573 state_reboot(void *ipp) 574 { 575 struct interface_info *ip = ipp; 576 577 /* If we don't remember an active lease, go straight to INIT. */ 578 if (!ip->client->active || ip->client->active->is_bootp) { 579 state_init(ip); 580 return; 581 } 582 583 /* We are in the rebooting state. */ 584 ip->client->state = S_REBOOTING; 585 586 /* make_request doesn't initialize xid because it normally comes 587 from the DHCPDISCOVER, but we haven't sent a DHCPDISCOVER, 588 so pick an xid now. */ 589 ip->client->xid = arc4random(); 590 591 /* Make a DHCPREQUEST packet, and set appropriate per-interface 592 flags. */ 593 make_request(ip, ip->client->active); 594 ip->client->destination = iaddr_broadcast; 595 ip->client->first_sending = cur_time; 596 ip->client->interval = ip->client->config->initial_interval; 597 598 /* Zap the medium list... */ 599 ip->client->medium = NULL; 600 601 /* Send out the first DHCPREQUEST packet. */ 602 send_request(ip); 603 } 604 605 /* 606 * Called when a lease has completely expired and we've 607 * been unable to renew it. 608 */ 609 void 610 state_init(void *ipp) 611 { 612 struct interface_info *ip = ipp; 613 614 ASSERT_STATE(state, S_INIT); 615 616 /* Make a DHCPDISCOVER packet, and set appropriate per-interface 617 flags. */ 618 make_discover(ip, ip->client->active); 619 ip->client->xid = ip->client->packet.xid; 620 ip->client->destination = iaddr_broadcast; 621 ip->client->state = S_SELECTING; 622 ip->client->first_sending = cur_time; 623 ip->client->interval = ip->client->config->initial_interval; 624 625 /* Add an immediate timeout to cause the first DHCPDISCOVER packet 626 to go out. */ 627 send_discover(ip); 628 } 629 630 /* 631 * state_selecting is called when one or more DHCPOFFER packets 632 * have been received and a configurable period of time has passed. 633 */ 634 void 635 state_selecting(void *ipp) 636 { 637 struct interface_info *ip = ipp; 638 struct client_lease *lp, *next, *picked; 639 640 ASSERT_STATE(state, S_SELECTING); 641 642 /* Cancel state_selecting and send_discover timeouts, since either 643 one could have got us here. */ 644 cancel_timeout(state_selecting, ip); 645 cancel_timeout(send_discover, ip); 646 647 /* We have received one or more DHCPOFFER packets. Currently, 648 the only criterion by which we judge leases is whether or 649 not we get a response when we arp for them. */ 650 picked = NULL; 651 for (lp = ip->client->offered_leases; lp; lp = next) { 652 next = lp->next; 653 654 /* Check to see if we got an ARPREPLY for the address 655 in this particular lease. */ 656 if (!picked) { 657 script_init("ARPCHECK", lp->medium); 658 script_write_params("check_", lp); 659 660 /* If the ARPCHECK code detects another 661 machine using the offered address, it exits 662 nonzero. We need to send a DHCPDECLINE and 663 toss the lease. */ 664 if (script_go()) { 665 make_decline(ip, lp); 666 send_decline(ip); 667 goto freeit; 668 } 669 picked = lp; 670 picked->next = NULL; 671 } else { 672 freeit: 673 free_client_lease(lp); 674 } 675 } 676 ip->client->offered_leases = NULL; 677 678 /* If we just tossed all the leases we were offered, go back 679 to square one. */ 680 if (!picked) { 681 ip->client->state = S_INIT; 682 state_init(ip); 683 return; 684 } 685 686 /* If it was a BOOTREPLY, we can just take the address right now. */ 687 if (!picked->options[DHO_DHCP_MESSAGE_TYPE].len) { 688 ip->client->new = picked; 689 690 /* Make up some lease expiry times 691 XXX these should be configurable. */ 692 ip->client->new->expiry = cur_time + 12000; 693 ip->client->new->renewal += cur_time + 8000; 694 ip->client->new->rebind += cur_time + 10000; 695 696 ip->client->state = S_REQUESTING; 697 698 /* Bind to the address we received. */ 699 bind_lease(ip); 700 return; 701 } 702 703 /* Go to the REQUESTING state. */ 704 ip->client->destination = iaddr_broadcast; 705 ip->client->state = S_REQUESTING; 706 ip->client->first_sending = cur_time; 707 ip->client->interval = ip->client->config->initial_interval; 708 709 /* Make a DHCPREQUEST packet from the lease we picked. */ 710 make_request(ip, picked); 711 ip->client->xid = ip->client->packet.xid; 712 713 /* Toss the lease we picked - we'll get it back in a DHCPACK. */ 714 free_client_lease(picked); 715 716 /* Add an immediate timeout to send the first DHCPREQUEST packet. */ 717 send_request(ip); 718 } 719 720 /* state_requesting is called when we receive a DHCPACK message after 721 having sent out one or more DHCPREQUEST packets. */ 722 723 void 724 dhcpack(struct packet *packet) 725 { 726 struct interface_info *ip = packet->interface; 727 struct client_lease *lease; 728 729 /* If we're not receptive to an offer right now, or if the offer 730 has an unrecognizable transaction id, then just drop it. */ 731 if (packet->interface->client->xid != packet->raw->xid || 732 (packet->interface->hw_address.hlen != packet->raw->hlen) || 733 (memcmp(packet->interface->hw_address.haddr, 734 packet->raw->chaddr, packet->raw->hlen))) 735 return; 736 737 if (ip->client->state != S_REBOOTING && 738 ip->client->state != S_REQUESTING && 739 ip->client->state != S_RENEWING && 740 ip->client->state != S_REBINDING) 741 return; 742 743 note("DHCPACK from %s", piaddr(packet->client_addr)); 744 745 lease = packet_to_lease(packet); 746 if (!lease) { 747 note("packet_to_lease failed."); 748 return; 749 } 750 751 ip->client->new = lease; 752 753 /* Stop resending DHCPREQUEST. */ 754 cancel_timeout(send_request, ip); 755 756 /* Figure out the lease time. */ 757 if (ip->client->new->options[DHO_DHCP_LEASE_TIME].data) 758 ip->client->new->expiry = getULong( 759 ip->client->new->options[DHO_DHCP_LEASE_TIME].data); 760 else 761 ip->client->new->expiry = default_lease_time; 762 /* A number that looks negative here is really just very large, 763 because the lease expiry offset is unsigned. */ 764 if (ip->client->new->expiry < 0) 765 ip->client->new->expiry = TIME_MAX; 766 /* XXX should be fixed by resetting the client state */ 767 if (ip->client->new->expiry < 60) 768 ip->client->new->expiry = 60; 769 770 /* Take the server-provided renewal time if there is one; 771 otherwise figure it out according to the spec. */ 772 if (ip->client->new->options[DHO_DHCP_RENEWAL_TIME].len) 773 ip->client->new->renewal = getULong( 774 ip->client->new->options[DHO_DHCP_RENEWAL_TIME].data); 775 else 776 ip->client->new->renewal = ip->client->new->expiry / 2; 777 778 /* Same deal with the rebind time. */ 779 if (ip->client->new->options[DHO_DHCP_REBINDING_TIME].len) 780 ip->client->new->rebind = getULong( 781 ip->client->new->options[DHO_DHCP_REBINDING_TIME].data); 782 else 783 ip->client->new->rebind = ip->client->new->renewal + 784 ip->client->new->renewal / 2 + ip->client->new->renewal / 4; 785 786 ip->client->new->expiry += cur_time; 787 /* Lease lengths can never be negative. */ 788 if (ip->client->new->expiry < cur_time) 789 ip->client->new->expiry = TIME_MAX; 790 ip->client->new->renewal += cur_time; 791 if (ip->client->new->renewal < cur_time) 792 ip->client->new->renewal = TIME_MAX; 793 ip->client->new->rebind += cur_time; 794 if (ip->client->new->rebind < cur_time) 795 ip->client->new->rebind = TIME_MAX; 796 797 bind_lease(ip); 798 } 799 800 void 801 bind_lease(struct interface_info *ip) 802 { 803 /* Remember the medium. */ 804 ip->client->new->medium = ip->client->medium; 805 806 /* Write out the new lease. */ 807 write_client_lease(ip, ip->client->new, 0); 808 809 /* Run the client script with the new parameters. */ 810 script_init((ip->client->state == S_REQUESTING ? "BOUND" : 811 (ip->client->state == S_RENEWING ? "RENEW" : 812 (ip->client->state == S_REBOOTING ? "REBOOT" : "REBIND"))), 813 ip->client->new->medium); 814 if (ip->client->active && ip->client->state != S_REBOOTING) 815 script_write_params("old_", ip->client->active); 816 script_write_params("new_", ip->client->new); 817 if (ip->client->alias) 818 script_write_params("alias_", ip->client->alias); 819 script_go(); 820 821 /* Replace the old active lease with the new one. */ 822 if (ip->client->active) 823 free_client_lease(ip->client->active); 824 ip->client->active = ip->client->new; 825 ip->client->new = NULL; 826 827 /* Set up a timeout to start the renewal process. */ 828 add_timeout(ip->client->active->renewal, state_bound, ip); 829 830 note("bound to %s -- renewal in %d seconds.", 831 piaddr(ip->client->active->address), 832 (int)(ip->client->active->renewal - cur_time)); 833 ip->client->state = S_BOUND; 834 reinitialize_interfaces(); 835 go_daemon(); 836 } 837 838 /* 839 * state_bound is called when we've successfully bound to a particular 840 * lease, but the renewal time on that lease has expired. We are 841 * expected to unicast a DHCPREQUEST to the server that gave us our 842 * original lease. 843 */ 844 void 845 state_bound(void *ipp) 846 { 847 struct interface_info *ip = ipp; 848 849 ASSERT_STATE(state, S_BOUND); 850 851 /* T1 has expired. */ 852 make_request(ip, ip->client->active); 853 ip->client->xid = ip->client->packet.xid; 854 855 if (ip->client->active->options[DHO_DHCP_SERVER_IDENTIFIER].len == 4) { 856 memcpy(ip->client->destination.iabuf, ip->client->active-> 857 options[DHO_DHCP_SERVER_IDENTIFIER].data, 4); 858 ip->client->destination.len = 4; 859 } else 860 ip->client->destination = iaddr_broadcast; 861 862 ip->client->first_sending = cur_time; 863 ip->client->interval = ip->client->config->initial_interval; 864 ip->client->state = S_RENEWING; 865 866 /* Send the first packet immediately. */ 867 send_request(ip); 868 } 869 870 void 871 bootp(struct packet *packet) 872 { 873 struct iaddrlist *ap; 874 875 if (packet->raw->op != BOOTREPLY) 876 return; 877 878 /* If there's a reject list, make sure this packet's sender isn't 879 on it. */ 880 for (ap = packet->interface->client->config->reject_list; 881 ap; ap = ap->next) { 882 if (addr_eq(packet->client_addr, ap->addr)) { 883 note("BOOTREPLY from %s rejected.", piaddr(ap->addr)); 884 return; 885 } 886 } 887 dhcpoffer(packet); 888 } 889 890 void 891 dhcp(struct packet *packet) 892 { 893 struct iaddrlist *ap; 894 void (*handler)(struct packet *); 895 char *type; 896 897 switch (packet->packet_type) { 898 case DHCPOFFER: 899 handler = dhcpoffer; 900 type = "DHCPOFFER"; 901 break; 902 case DHCPNAK: 903 handler = dhcpnak; 904 type = "DHCPNACK"; 905 break; 906 case DHCPACK: 907 handler = dhcpack; 908 type = "DHCPACK"; 909 break; 910 default: 911 return; 912 } 913 914 /* If there's a reject list, make sure this packet's sender isn't 915 on it. */ 916 for (ap = packet->interface->client->config->reject_list; 917 ap; ap = ap->next) { 918 if (addr_eq(packet->client_addr, ap->addr)) { 919 note("%s from %s rejected.", type, piaddr(ap->addr)); 920 return; 921 } 922 } 923 (*handler)(packet); 924 } 925 926 void 927 dhcpoffer(struct packet *packet) 928 { 929 struct interface_info *ip = packet->interface; 930 struct client_lease *lease, *lp; 931 int i; 932 int arp_timeout_needed, stop_selecting; 933 char *name = packet->options[DHO_DHCP_MESSAGE_TYPE].len ? 934 "DHCPOFFER" : "BOOTREPLY"; 935 936 /* If we're not receptive to an offer right now, or if the offer 937 has an unrecognizable transaction id, then just drop it. */ 938 if (ip->client->state != S_SELECTING || 939 packet->interface->client->xid != packet->raw->xid || 940 (packet->interface->hw_address.hlen != packet->raw->hlen) || 941 (memcmp(packet->interface->hw_address.haddr, 942 packet->raw->chaddr, packet->raw->hlen))) 943 return; 944 945 note("%s from %s", name, piaddr(packet->client_addr)); 946 947 948 /* If this lease doesn't supply the minimum required parameters, 949 blow it off. */ 950 for (i = 0; ip->client->config->required_options[i]; i++) { 951 if (!packet->options[ip->client->config-> 952 required_options[i]].len) { 953 note("%s isn't satisfactory.", name); 954 return; 955 } 956 } 957 958 /* If we've already seen this lease, don't record it again. */ 959 for (lease = ip->client->offered_leases; 960 lease; lease = lease->next) { 961 if (lease->address.len == sizeof(packet->raw->yiaddr) && 962 !memcmp(lease->address.iabuf, 963 &packet->raw->yiaddr, lease->address.len)) { 964 debug("%s already seen.", name); 965 return; 966 } 967 } 968 969 lease = packet_to_lease(packet); 970 if (!lease) { 971 note("packet_to_lease failed."); 972 return; 973 } 974 975 /* If this lease was acquired through a BOOTREPLY, record that 976 fact. */ 977 if (!packet->options[DHO_DHCP_MESSAGE_TYPE].len) 978 lease->is_bootp = 1; 979 980 /* Record the medium under which this lease was offered. */ 981 lease->medium = ip->client->medium; 982 983 /* Send out an ARP Request for the offered IP address. */ 984 script_init("ARPSEND", lease->medium); 985 script_write_params("check_", lease); 986 /* If the script can't send an ARP request without waiting, 987 we'll be waiting when we do the ARPCHECK, so don't wait now. */ 988 if (script_go()) 989 arp_timeout_needed = 0; 990 else 991 arp_timeout_needed = 2; 992 993 /* Figure out when we're supposed to stop selecting. */ 994 stop_selecting = 995 ip->client->first_sending + ip->client->config->select_interval; 996 997 /* If this is the lease we asked for, put it at the head of the 998 list, and don't mess with the arp request timeout. */ 999 if (lease->address.len == ip->client->requested_address.len && 1000 !memcmp(lease->address.iabuf, 1001 ip->client->requested_address.iabuf, 1002 ip->client->requested_address.len)) { 1003 lease->next = ip->client->offered_leases; 1004 ip->client->offered_leases = lease; 1005 } else { 1006 /* If we already have an offer, and arping for this 1007 offer would take us past the selection timeout, 1008 then don't extend the timeout - just hope for the 1009 best. */ 1010 if (ip->client->offered_leases && 1011 (cur_time + arp_timeout_needed) > stop_selecting) 1012 arp_timeout_needed = 0; 1013 1014 /* Put the lease at the end of the list. */ 1015 lease->next = NULL; 1016 if (!ip->client->offered_leases) 1017 ip->client->offered_leases = lease; 1018 else { 1019 for (lp = ip->client->offered_leases; lp->next; 1020 lp = lp->next) 1021 ; /* nothing */ 1022 lp->next = lease; 1023 } 1024 } 1025 1026 /* If we're supposed to stop selecting before we've had time 1027 to wait for the ARPREPLY, add some delay to wait for 1028 the ARPREPLY. */ 1029 if (stop_selecting - cur_time < arp_timeout_needed) 1030 stop_selecting = cur_time + arp_timeout_needed; 1031 1032 /* If the selecting interval has expired, go immediately to 1033 state_selecting(). Otherwise, time out into 1034 state_selecting at the select interval. */ 1035 if (stop_selecting <= 0) 1036 state_selecting(ip); 1037 else { 1038 add_timeout(stop_selecting, state_selecting, ip); 1039 cancel_timeout(send_discover, ip); 1040 } 1041 } 1042 1043 /* Allocate a client_lease structure and initialize it from the parameters 1044 in the specified packet. */ 1045 1046 struct client_lease * 1047 packet_to_lease(struct packet *packet) 1048 { 1049 struct client_lease *lease; 1050 int i; 1051 1052 lease = malloc(sizeof(struct client_lease)); 1053 1054 if (!lease) { 1055 warning("dhcpoffer: no memory to record lease."); 1056 return (NULL); 1057 } 1058 1059 memset(lease, 0, sizeof(*lease)); 1060 1061 /* Copy the lease options. */ 1062 for (i = 0; i < 256; i++) { 1063 if (packet->options[i].len) { 1064 lease->options[i].data = 1065 malloc(packet->options[i].len + 1); 1066 if (!lease->options[i].data) { 1067 warning("dhcpoffer: no memory for option %d", i); 1068 free_client_lease(lease); 1069 return (NULL); 1070 } else { 1071 memcpy(lease->options[i].data, 1072 packet->options[i].data, 1073 packet->options[i].len); 1074 lease->options[i].len = 1075 packet->options[i].len; 1076 lease->options[i].data[lease->options[i].len] = 1077 0; 1078 } 1079 if (!check_option(lease,i)) { 1080 /* ignore a bogus lease offer */ 1081 warning("Invalid lease option - ignoring offer"); 1082 free_client_lease(lease); 1083 return (NULL); 1084 } 1085 } 1086 } 1087 1088 lease->address.len = sizeof(packet->raw->yiaddr); 1089 memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len); 1090 1091 lease->nextserver.len = sizeof(packet->raw->siaddr); 1092 memcpy(lease->nextserver.iabuf, &packet->raw->siaddr, lease->nextserver.len); 1093 1094 /* If the server name was filled out, copy it. 1095 Do not attempt to validate the server name as a host name. 1096 RFC 2131 merely states that sname is NUL-terminated (which do 1097 do not assume) and that it is the server's host name. Since 1098 the ISC client and server allow arbitrary characters, we do 1099 as well. */ 1100 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len || 1101 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2)) && 1102 packet->raw->sname[0]) { 1103 lease->server_name = malloc(DHCP_SNAME_LEN + 1); 1104 if (!lease->server_name) { 1105 warning("dhcpoffer: no memory for server name."); 1106 free_client_lease(lease); 1107 return (NULL); 1108 } 1109 memcpy(lease->server_name, packet->raw->sname, DHCP_SNAME_LEN); 1110 lease->server_name[DHCP_SNAME_LEN]='\0'; 1111 } 1112 1113 /* Ditto for the filename. */ 1114 if ((!packet->options[DHO_DHCP_OPTION_OVERLOAD].len || 1115 !(packet->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1)) && 1116 packet->raw->file[0]) { 1117 /* Don't count on the NUL terminator. */ 1118 lease->filename = malloc(DHCP_FILE_LEN + 1); 1119 if (!lease->filename) { 1120 warning("dhcpoffer: no memory for filename."); 1121 free_client_lease(lease); 1122 return (NULL); 1123 } 1124 memcpy(lease->filename, packet->raw->file, DHCP_FILE_LEN); 1125 lease->filename[DHCP_FILE_LEN]='\0'; 1126 } 1127 return lease; 1128 } 1129 1130 void 1131 dhcpnak(struct packet *packet) 1132 { 1133 struct interface_info *ip = packet->interface; 1134 1135 /* If we're not receptive to an offer right now, or if the offer 1136 has an unrecognizable transaction id, then just drop it. */ 1137 if (packet->interface->client->xid != packet->raw->xid || 1138 (packet->interface->hw_address.hlen != packet->raw->hlen) || 1139 (memcmp(packet->interface->hw_address.haddr, 1140 packet->raw->chaddr, packet->raw->hlen))) 1141 return; 1142 1143 if (ip->client->state != S_REBOOTING && 1144 ip->client->state != S_REQUESTING && 1145 ip->client->state != S_RENEWING && 1146 ip->client->state != S_REBINDING) 1147 return; 1148 1149 note("DHCPNAK from %s", piaddr(packet->client_addr)); 1150 1151 if (!ip->client->active) { 1152 note("DHCPNAK with no active lease.\n"); 1153 return; 1154 } 1155 1156 free_client_lease(ip->client->active); 1157 ip->client->active = NULL; 1158 1159 /* Stop sending DHCPREQUEST packets... */ 1160 cancel_timeout(send_request, ip); 1161 1162 ip->client->state = S_INIT; 1163 state_init(ip); 1164 } 1165 1166 /* Send out a DHCPDISCOVER packet, and set a timeout to send out another 1167 one after the right interval has expired. If we don't get an offer by 1168 the time we reach the panic interval, call the panic function. */ 1169 1170 void 1171 send_discover(void *ipp) 1172 { 1173 struct interface_info *ip = ipp; 1174 int interval, increase = 1; 1175 1176 /* Figure out how long it's been since we started transmitting. */ 1177 interval = cur_time - ip->client->first_sending; 1178 1179 /* If we're past the panic timeout, call the script and tell it 1180 we haven't found anything for this interface yet. */ 1181 if (interval > ip->client->config->timeout) { 1182 state_panic(ip); 1183 return; 1184 } 1185 1186 /* If we're selecting media, try the whole list before doing 1187 the exponential backoff, but if we've already received an 1188 offer, stop looping, because we obviously have it right. */ 1189 if (!ip->client->offered_leases && 1190 ip->client->config->media) { 1191 int fail = 0; 1192 again: 1193 if (ip->client->medium) { 1194 ip->client->medium = ip->client->medium->next; 1195 increase = 0; 1196 } 1197 if (!ip->client->medium) { 1198 if (fail) 1199 error("No valid media types for %s!", ip->name); 1200 ip->client->medium = ip->client->config->media; 1201 increase = 1; 1202 } 1203 1204 note("Trying medium \"%s\" %d", ip->client->medium->string, 1205 increase); 1206 script_init("MEDIUM", ip->client->medium); 1207 if (script_go()) 1208 goto again; 1209 } 1210 1211 /* 1212 * If we're supposed to increase the interval, do so. If it's 1213 * currently zero (i.e., we haven't sent any packets yet), set 1214 * it to one; otherwise, add to it a random number between zero 1215 * and two times itself. On average, this means that it will 1216 * double with every transmission. 1217 */ 1218 if (increase) { 1219 if (!ip->client->interval) 1220 ip->client->interval = 1221 ip->client->config->initial_interval; 1222 else { 1223 ip->client->interval += (arc4random() >> 2) % 1224 (2 * ip->client->interval); 1225 } 1226 1227 /* Don't backoff past cutoff. */ 1228 if (ip->client->interval > 1229 ip->client->config->backoff_cutoff) 1230 ip->client->interval = 1231 ((ip->client->config->backoff_cutoff / 2) 1232 + ((arc4random() >> 2) % 1233 ip->client->config->backoff_cutoff)); 1234 } else if (!ip->client->interval) 1235 ip->client->interval = 1236 ip->client->config->initial_interval; 1237 1238 /* If the backoff would take us to the panic timeout, just use that 1239 as the interval. */ 1240 if (cur_time + ip->client->interval > 1241 ip->client->first_sending + ip->client->config->timeout) 1242 ip->client->interval = 1243 (ip->client->first_sending + 1244 ip->client->config->timeout) - cur_time + 1; 1245 1246 /* Record the number of seconds since we started sending. */ 1247 if (interval < 65536) 1248 ip->client->packet.secs = htons(interval); 1249 else 1250 ip->client->packet.secs = htons(65535); 1251 ip->client->secs = ip->client->packet.secs; 1252 1253 note("DHCPDISCOVER on %s to %s port %d interval %d", 1254 ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT, 1255 (int)ip->client->interval); 1256 1257 /* Send out a packet. */ 1258 send_packet_unpriv(privfd, &ip->client->packet, 1259 ip->client->packet_length, inaddr_any, inaddr_broadcast); 1260 1261 add_timeout(cur_time + ip->client->interval, send_discover, ip); 1262 } 1263 1264 /* 1265 * state_panic gets called if we haven't received any offers in a preset 1266 * amount of time. When this happens, we try to use existing leases 1267 * that haven't yet expired, and failing that, we call the client script 1268 * and hope it can do something. 1269 */ 1270 void 1271 state_panic(void *ipp) 1272 { 1273 struct interface_info *ip = ipp; 1274 struct client_lease *loop = ip->client->active; 1275 struct client_lease *lp; 1276 1277 note("No DHCPOFFERS received."); 1278 1279 /* We may not have an active lease, but we may have some 1280 predefined leases that we can try. */ 1281 if (!ip->client->active && ip->client->leases) 1282 goto activate_next; 1283 1284 /* Run through the list of leases and see if one can be used. */ 1285 while (ip->client->active) { 1286 if (ip->client->active->expiry > cur_time) { 1287 note("Trying recorded lease %s", 1288 piaddr(ip->client->active->address)); 1289 /* Run the client script with the existing 1290 parameters. */ 1291 script_init("TIMEOUT", 1292 ip->client->active->medium); 1293 script_write_params("new_", ip->client->active); 1294 if (ip->client->alias) 1295 script_write_params("alias_", 1296 ip->client->alias); 1297 1298 /* If the old lease is still good and doesn't 1299 yet need renewal, go into BOUND state and 1300 timeout at the renewal time. */ 1301 if (!script_go()) { 1302 if (cur_time < 1303 ip->client->active->renewal) { 1304 ip->client->state = S_BOUND; 1305 note("bound: renewal in %d seconds.", 1306 (int)(ip->client->active->renewal - 1307 cur_time)); 1308 add_timeout( 1309 ip->client->active->renewal, 1310 state_bound, ip); 1311 } else { 1312 ip->client->state = S_BOUND; 1313 note("bound: immediate renewal."); 1314 state_bound(ip); 1315 } 1316 reinitialize_interfaces(); 1317 go_daemon(); 1318 return; 1319 } 1320 } 1321 1322 /* If there are no other leases, give up. */ 1323 if (!ip->client->leases) { 1324 ip->client->leases = ip->client->active; 1325 ip->client->active = NULL; 1326 break; 1327 } 1328 1329 activate_next: 1330 /* Otherwise, put the active lease at the end of the 1331 lease list, and try another lease.. */ 1332 for (lp = ip->client->leases; lp->next; lp = lp->next) 1333 ; 1334 lp->next = ip->client->active; 1335 if (lp->next) 1336 lp->next->next = NULL; 1337 ip->client->active = ip->client->leases; 1338 ip->client->leases = ip->client->leases->next; 1339 1340 /* If we already tried this lease, we've exhausted the 1341 set of leases, so we might as well give up for 1342 now. */ 1343 if (ip->client->active == loop) 1344 break; 1345 else if (!loop) 1346 loop = ip->client->active; 1347 } 1348 1349 /* No leases were available, or what was available didn't work, so 1350 tell the shell script that we failed to allocate an address, 1351 and try again later. */ 1352 note("No working leases in persistent database - sleeping.\n"); 1353 script_init("FAIL", NULL); 1354 if (ip->client->alias) 1355 script_write_params("alias_", ip->client->alias); 1356 script_go(); 1357 ip->client->state = S_INIT; 1358 add_timeout(cur_time + ip->client->config->retry_interval, state_init, 1359 ip); 1360 go_daemon(); 1361 } 1362 1363 void 1364 send_request(void *ipp) 1365 { 1366 struct interface_info *ip = ipp; 1367 struct in_addr from, to; 1368 int interval; 1369 1370 /* Figure out how long it's been since we started transmitting. */ 1371 interval = cur_time - ip->client->first_sending; 1372 1373 /* If we're in the INIT-REBOOT or REQUESTING state and we're 1374 past the reboot timeout, go to INIT and see if we can 1375 DISCOVER an address... */ 1376 /* XXX In the INIT-REBOOT state, if we don't get an ACK, it 1377 means either that we're on a network with no DHCP server, 1378 or that our server is down. In the latter case, assuming 1379 that there is a backup DHCP server, DHCPDISCOVER will get 1380 us a new address, but we could also have successfully 1381 reused our old address. In the former case, we're hosed 1382 anyway. This is not a win-prone situation. */ 1383 if ((ip->client->state == S_REBOOTING || 1384 ip->client->state == S_REQUESTING) && 1385 interval > ip->client->config->reboot_timeout) { 1386 cancel: 1387 ip->client->state = S_INIT; 1388 cancel_timeout(send_request, ip); 1389 state_init(ip); 1390 return; 1391 } 1392 1393 /* If we're in the reboot state, make sure the media is set up 1394 correctly. */ 1395 if (ip->client->state == S_REBOOTING && 1396 !ip->client->medium && 1397 ip->client->active->medium ) { 1398 script_init("MEDIUM", ip->client->active->medium); 1399 1400 /* If the medium we chose won't fly, go to INIT state. */ 1401 if (script_go()) 1402 goto cancel; 1403 1404 /* Record the medium. */ 1405 ip->client->medium = ip->client->active->medium; 1406 } 1407 1408 /* If the lease has expired, relinquish the address and go back 1409 to the INIT state. */ 1410 if (ip->client->state != S_REQUESTING && 1411 cur_time > ip->client->active->expiry) { 1412 /* Run the client script with the new parameters. */ 1413 script_init("EXPIRE", NULL); 1414 script_write_params("old_", ip->client->active); 1415 if (ip->client->alias) 1416 script_write_params("alias_", ip->client->alias); 1417 script_go(); 1418 1419 /* Now do a preinit on the interface so that we can 1420 discover a new address. */ 1421 script_init("PREINIT", NULL); 1422 if (ip->client->alias) 1423 script_write_params("alias_", ip->client->alias); 1424 script_go(); 1425 1426 ip->client->state = S_INIT; 1427 state_init(ip); 1428 return; 1429 } 1430 1431 /* Do the exponential backoff... */ 1432 if (!ip->client->interval) 1433 ip->client->interval = ip->client->config->initial_interval; 1434 else 1435 ip->client->interval += ((arc4random() >> 2) % 1436 (2 * ip->client->interval)); 1437 1438 /* Don't backoff past cutoff. */ 1439 if (ip->client->interval > 1440 ip->client->config->backoff_cutoff) 1441 ip->client->interval = 1442 ((ip->client->config->backoff_cutoff / 2) + 1443 ((arc4random() >> 2) % ip->client->interval)); 1444 1445 /* If the backoff would take us to the expiry time, just set the 1446 timeout to the expiry time. */ 1447 if (ip->client->state != S_REQUESTING && 1448 cur_time + ip->client->interval > 1449 ip->client->active->expiry) 1450 ip->client->interval = 1451 ip->client->active->expiry - cur_time + 1; 1452 1453 /* If the lease T2 time has elapsed, or if we're not yet bound, 1454 broadcast the DHCPREQUEST rather than unicasting. */ 1455 if (ip->client->state == S_REQUESTING || 1456 ip->client->state == S_REBOOTING || 1457 cur_time > ip->client->active->rebind) 1458 to.s_addr = INADDR_BROADCAST; 1459 else 1460 memcpy(&to.s_addr, ip->client->destination.iabuf, 1461 sizeof(to.s_addr)); 1462 1463 if (ip->client->state != S_REQUESTING) 1464 memcpy(&from, ip->client->active->address.iabuf, 1465 sizeof(from)); 1466 else 1467 from.s_addr = INADDR_ANY; 1468 1469 /* Record the number of seconds since we started sending. */ 1470 if (ip->client->state == S_REQUESTING) 1471 ip->client->packet.secs = ip->client->secs; 1472 else { 1473 if (interval < 65536) 1474 ip->client->packet.secs = htons(interval); 1475 else 1476 ip->client->packet.secs = htons(65535); 1477 } 1478 1479 note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to), 1480 REMOTE_PORT); 1481 1482 /* Send out a packet. */ 1483 send_packet_unpriv(privfd, &ip->client->packet, 1484 ip->client->packet_length, from, to); 1485 1486 add_timeout(cur_time + ip->client->interval, send_request, ip); 1487 } 1488 1489 void 1490 send_decline(void *ipp) 1491 { 1492 struct interface_info *ip = ipp; 1493 1494 note("DHCPDECLINE on %s to %s port %d", ip->name, 1495 inet_ntoa(inaddr_broadcast), REMOTE_PORT); 1496 1497 /* Send out a packet. */ 1498 send_packet_unpriv(privfd, &ip->client->packet, 1499 ip->client->packet_length, inaddr_any, inaddr_broadcast); 1500 } 1501 1502 void 1503 make_discover(struct interface_info *ip, struct client_lease *lease) 1504 { 1505 unsigned char discover = DHCPDISCOVER; 1506 struct tree_cache *options[256]; 1507 struct tree_cache option_elements[256]; 1508 int i; 1509 1510 memset(option_elements, 0, sizeof(option_elements)); 1511 memset(options, 0, sizeof(options)); 1512 memset(&ip->client->packet, 0, sizeof(ip->client->packet)); 1513 1514 /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */ 1515 i = DHO_DHCP_MESSAGE_TYPE; 1516 options[i] = &option_elements[i]; 1517 options[i]->value = &discover; 1518 options[i]->len = sizeof(discover); 1519 options[i]->buf_size = sizeof(discover); 1520 options[i]->timeout = 0xFFFFFFFF; 1521 1522 /* Request the options we want */ 1523 i = DHO_DHCP_PARAMETER_REQUEST_LIST; 1524 options[i] = &option_elements[i]; 1525 options[i]->value = ip->client->config->requested_options; 1526 options[i]->len = ip->client->config->requested_option_count; 1527 options[i]->buf_size = 1528 ip->client->config->requested_option_count; 1529 options[i]->timeout = 0xFFFFFFFF; 1530 1531 /* If we had an address, try to get it again. */ 1532 if (lease) { 1533 ip->client->requested_address = lease->address; 1534 i = DHO_DHCP_REQUESTED_ADDRESS; 1535 options[i] = &option_elements[i]; 1536 options[i]->value = lease->address.iabuf; 1537 options[i]->len = lease->address.len; 1538 options[i]->buf_size = lease->address.len; 1539 options[i]->timeout = 0xFFFFFFFF; 1540 } else 1541 ip->client->requested_address.len = 0; 1542 1543 /* Send any options requested in the config file. */ 1544 for (i = 0; i < 256; i++) 1545 if (!options[i] && 1546 ip->client->config->send_options[i].data) { 1547 options[i] = &option_elements[i]; 1548 options[i]->value = 1549 ip->client->config->send_options[i].data; 1550 options[i]->len = 1551 ip->client->config->send_options[i].len; 1552 options[i]->buf_size = 1553 ip->client->config->send_options[i].len; 1554 options[i]->timeout = 0xFFFFFFFF; 1555 } 1556 1557 /* send host name if not set via config file. */ 1558 if (!options[DHO_HOST_NAME]) { 1559 if (hostname[0] != '\0') { 1560 size_t len; 1561 char* posDot = strchr(hostname, '.'); 1562 if (posDot != NULL) 1563 len = posDot - hostname; 1564 else 1565 len = strlen(hostname); 1566 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME]; 1567 options[DHO_HOST_NAME]->value = hostname; 1568 options[DHO_HOST_NAME]->len = len; 1569 options[DHO_HOST_NAME]->buf_size = len; 1570 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF; 1571 } 1572 } 1573 1574 /* set unique client identifier */ 1575 char client_ident[sizeof(struct hardware)]; 1576 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) { 1577 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ? 1578 ip->hw_address.hlen : sizeof(client_ident)-1; 1579 client_ident[0] = ip->hw_address.htype; 1580 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); 1581 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER]; 1582 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident; 1583 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1; 1584 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1; 1585 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF; 1586 } 1587 1588 /* Set up the option buffer... */ 1589 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, 1590 options, 0, 0, 0, NULL, 0); 1591 if (ip->client->packet_length < BOOTP_MIN_LEN) 1592 ip->client->packet_length = BOOTP_MIN_LEN; 1593 1594 ip->client->packet.op = BOOTREQUEST; 1595 ip->client->packet.htype = ip->hw_address.htype; 1596 ip->client->packet.hlen = ip->hw_address.hlen; 1597 ip->client->packet.hops = 0; 1598 ip->client->packet.xid = arc4random(); 1599 ip->client->packet.secs = 0; /* filled in by send_discover. */ 1600 ip->client->packet.flags = 0; 1601 1602 memset(&(ip->client->packet.ciaddr), 1603 0, sizeof(ip->client->packet.ciaddr)); 1604 memset(&(ip->client->packet.yiaddr), 1605 0, sizeof(ip->client->packet.yiaddr)); 1606 memset(&(ip->client->packet.siaddr), 1607 0, sizeof(ip->client->packet.siaddr)); 1608 memset(&(ip->client->packet.giaddr), 1609 0, sizeof(ip->client->packet.giaddr)); 1610 memcpy(ip->client->packet.chaddr, 1611 ip->hw_address.haddr, ip->hw_address.hlen); 1612 } 1613 1614 1615 void 1616 make_request(struct interface_info *ip, struct client_lease * lease) 1617 { 1618 unsigned char request = DHCPREQUEST; 1619 struct tree_cache *options[256]; 1620 struct tree_cache option_elements[256]; 1621 int i; 1622 1623 memset(options, 0, sizeof(options)); 1624 memset(&ip->client->packet, 0, sizeof(ip->client->packet)); 1625 1626 /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */ 1627 i = DHO_DHCP_MESSAGE_TYPE; 1628 options[i] = &option_elements[i]; 1629 options[i]->value = &request; 1630 options[i]->len = sizeof(request); 1631 options[i]->buf_size = sizeof(request); 1632 options[i]->timeout = 0xFFFFFFFF; 1633 1634 /* Request the options we want */ 1635 i = DHO_DHCP_PARAMETER_REQUEST_LIST; 1636 options[i] = &option_elements[i]; 1637 options[i]->value = ip->client->config->requested_options; 1638 options[i]->len = ip->client->config->requested_option_count; 1639 options[i]->buf_size = 1640 ip->client->config->requested_option_count; 1641 options[i]->timeout = 0xFFFFFFFF; 1642 1643 /* If we are requesting an address that hasn't yet been assigned 1644 to us, use the DHCP Requested Address option. */ 1645 if (ip->client->state == S_REQUESTING) { 1646 /* Send back the server identifier... */ 1647 i = DHO_DHCP_SERVER_IDENTIFIER; 1648 options[i] = &option_elements[i]; 1649 options[i]->value = lease->options[i].data; 1650 options[i]->len = lease->options[i].len; 1651 options[i]->buf_size = lease->options[i].len; 1652 options[i]->timeout = 0xFFFFFFFF; 1653 } 1654 if (ip->client->state == S_REQUESTING || 1655 ip->client->state == S_REBOOTING) { 1656 ip->client->requested_address = lease->address; 1657 i = DHO_DHCP_REQUESTED_ADDRESS; 1658 options[i] = &option_elements[i]; 1659 options[i]->value = lease->address.iabuf; 1660 options[i]->len = lease->address.len; 1661 options[i]->buf_size = lease->address.len; 1662 options[i]->timeout = 0xFFFFFFFF; 1663 } else 1664 ip->client->requested_address.len = 0; 1665 1666 /* Send any options requested in the config file. */ 1667 for (i = 0; i < 256; i++) 1668 if (!options[i] && 1669 ip->client->config->send_options[i].data) { 1670 options[i] = &option_elements[i]; 1671 options[i]->value = 1672 ip->client->config->send_options[i].data; 1673 options[i]->len = 1674 ip->client->config->send_options[i].len; 1675 options[i]->buf_size = 1676 ip->client->config->send_options[i].len; 1677 options[i]->timeout = 0xFFFFFFFF; 1678 } 1679 1680 /* send host name if not set via config file. */ 1681 if (!options[DHO_HOST_NAME]) { 1682 if (hostname[0] != '\0') { 1683 size_t len; 1684 char* posDot = strchr(hostname, '.'); 1685 if (posDot != NULL) 1686 len = posDot - hostname; 1687 else 1688 len = strlen(hostname); 1689 options[DHO_HOST_NAME] = &option_elements[DHO_HOST_NAME]; 1690 options[DHO_HOST_NAME]->value = hostname; 1691 options[DHO_HOST_NAME]->len = len; 1692 options[DHO_HOST_NAME]->buf_size = len; 1693 options[DHO_HOST_NAME]->timeout = 0xFFFFFFFF; 1694 } 1695 } 1696 1697 /* set unique client identifier */ 1698 char client_ident[sizeof(struct hardware)]; 1699 if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) { 1700 int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ? 1701 ip->hw_address.hlen : sizeof(client_ident)-1; 1702 client_ident[0] = ip->hw_address.htype; 1703 memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); 1704 options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER]; 1705 options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident; 1706 options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1; 1707 options[DHO_DHCP_CLIENT_IDENTIFIER]->buf_size = hwlen+1; 1708 options[DHO_DHCP_CLIENT_IDENTIFIER]->timeout = 0xFFFFFFFF; 1709 } 1710 1711 /* Set up the option buffer... */ 1712 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, 1713 options, 0, 0, 0, NULL, 0); 1714 if (ip->client->packet_length < BOOTP_MIN_LEN) 1715 ip->client->packet_length = BOOTP_MIN_LEN; 1716 1717 ip->client->packet.op = BOOTREQUEST; 1718 ip->client->packet.htype = ip->hw_address.htype; 1719 ip->client->packet.hlen = ip->hw_address.hlen; 1720 ip->client->packet.hops = 0; 1721 ip->client->packet.xid = ip->client->xid; 1722 ip->client->packet.secs = 0; /* Filled in by send_request. */ 1723 1724 /* If we own the address we're requesting, put it in ciaddr; 1725 otherwise set ciaddr to zero. */ 1726 if (ip->client->state == S_BOUND || 1727 ip->client->state == S_RENEWING || 1728 ip->client->state == S_REBINDING) { 1729 memcpy(&ip->client->packet.ciaddr, 1730 lease->address.iabuf, lease->address.len); 1731 ip->client->packet.flags = 0; 1732 } else { 1733 memset(&ip->client->packet.ciaddr, 0, 1734 sizeof(ip->client->packet.ciaddr)); 1735 ip->client->packet.flags = 0; 1736 } 1737 1738 memset(&ip->client->packet.yiaddr, 0, 1739 sizeof(ip->client->packet.yiaddr)); 1740 memset(&ip->client->packet.siaddr, 0, 1741 sizeof(ip->client->packet.siaddr)); 1742 memset(&ip->client->packet.giaddr, 0, 1743 sizeof(ip->client->packet.giaddr)); 1744 memcpy(ip->client->packet.chaddr, 1745 ip->hw_address.haddr, ip->hw_address.hlen); 1746 } 1747 1748 void 1749 make_decline(struct interface_info *ip, struct client_lease *lease) 1750 { 1751 struct tree_cache *options[256], message_type_tree; 1752 struct tree_cache requested_address_tree; 1753 struct tree_cache server_id_tree, client_id_tree; 1754 unsigned char decline = DHCPDECLINE; 1755 int i; 1756 1757 memset(options, 0, sizeof(options)); 1758 memset(&ip->client->packet, 0, sizeof(ip->client->packet)); 1759 1760 /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */ 1761 i = DHO_DHCP_MESSAGE_TYPE; 1762 options[i] = &message_type_tree; 1763 options[i]->value = &decline; 1764 options[i]->len = sizeof(decline); 1765 options[i]->buf_size = sizeof(decline); 1766 options[i]->timeout = 0xFFFFFFFF; 1767 1768 /* Send back the server identifier... */ 1769 i = DHO_DHCP_SERVER_IDENTIFIER; 1770 options[i] = &server_id_tree; 1771 options[i]->value = lease->options[i].data; 1772 options[i]->len = lease->options[i].len; 1773 options[i]->buf_size = lease->options[i].len; 1774 options[i]->timeout = 0xFFFFFFFF; 1775 1776 /* Send back the address we're declining. */ 1777 i = DHO_DHCP_REQUESTED_ADDRESS; 1778 options[i] = &requested_address_tree; 1779 options[i]->value = lease->address.iabuf; 1780 options[i]->len = lease->address.len; 1781 options[i]->buf_size = lease->address.len; 1782 options[i]->timeout = 0xFFFFFFFF; 1783 1784 /* Send the uid if the user supplied one. */ 1785 i = DHO_DHCP_CLIENT_IDENTIFIER; 1786 if (ip->client->config->send_options[i].len) { 1787 options[i] = &client_id_tree; 1788 options[i]->value = ip->client->config->send_options[i].data; 1789 options[i]->len = ip->client->config->send_options[i].len; 1790 options[i]->buf_size = ip->client->config->send_options[i].len; 1791 options[i]->timeout = 0xFFFFFFFF; 1792 } 1793 1794 1795 /* Set up the option buffer... */ 1796 ip->client->packet_length = cons_options(NULL, &ip->client->packet, 0, 1797 options, 0, 0, 0, NULL, 0); 1798 if (ip->client->packet_length < BOOTP_MIN_LEN) 1799 ip->client->packet_length = BOOTP_MIN_LEN; 1800 1801 ip->client->packet.op = BOOTREQUEST; 1802 ip->client->packet.htype = ip->hw_address.htype; 1803 ip->client->packet.hlen = ip->hw_address.hlen; 1804 ip->client->packet.hops = 0; 1805 ip->client->packet.xid = ip->client->xid; 1806 ip->client->packet.secs = 0; /* Filled in by send_request. */ 1807 ip->client->packet.flags = 0; 1808 1809 /* ciaddr must always be zero. */ 1810 memset(&ip->client->packet.ciaddr, 0, 1811 sizeof(ip->client->packet.ciaddr)); 1812 memset(&ip->client->packet.yiaddr, 0, 1813 sizeof(ip->client->packet.yiaddr)); 1814 memset(&ip->client->packet.siaddr, 0, 1815 sizeof(ip->client->packet.siaddr)); 1816 memset(&ip->client->packet.giaddr, 0, 1817 sizeof(ip->client->packet.giaddr)); 1818 memcpy(ip->client->packet.chaddr, 1819 ip->hw_address.haddr, ip->hw_address.hlen); 1820 } 1821 1822 void 1823 free_client_lease(struct client_lease *lease) 1824 { 1825 int i; 1826 1827 if (lease->server_name) 1828 free(lease->server_name); 1829 if (lease->filename) 1830 free(lease->filename); 1831 for (i = 0; i < 256; i++) { 1832 if (lease->options[i].len) 1833 free(lease->options[i].data); 1834 } 1835 free(lease); 1836 } 1837 1838 FILE *leaseFile; 1839 1840 void 1841 rewrite_client_leases(void) 1842 { 1843 struct client_lease *lp; 1844 cap_rights_t rights; 1845 1846 if (!leaseFile) { 1847 leaseFile = fopen(path_dhclient_db, "w"); 1848 if (!leaseFile) 1849 error("can't create %s: %m", path_dhclient_db); 1850 cap_rights_init(&rights, CAP_FSTAT, CAP_FSYNC, CAP_FTRUNCATE, 1851 CAP_SEEK, CAP_WRITE); 1852 if (cap_rights_limit(fileno(leaseFile), &rights) < 0 && 1853 errno != ENOSYS) { 1854 error("can't limit lease descriptor: %m"); 1855 } 1856 } else { 1857 fflush(leaseFile); 1858 rewind(leaseFile); 1859 } 1860 1861 for (lp = ifi->client->leases; lp; lp = lp->next) 1862 write_client_lease(ifi, lp, 1); 1863 if (ifi->client->active) 1864 write_client_lease(ifi, ifi->client->active, 1); 1865 1866 fflush(leaseFile); 1867 ftruncate(fileno(leaseFile), ftello(leaseFile)); 1868 fsync(fileno(leaseFile)); 1869 } 1870 1871 void 1872 write_client_lease(struct interface_info *ip, struct client_lease *lease, 1873 int rewrite) 1874 { 1875 static int leases_written; 1876 struct tm *t; 1877 int i; 1878 1879 if (!rewrite) { 1880 if (leases_written++ > 20) { 1881 rewrite_client_leases(); 1882 leases_written = 0; 1883 } 1884 } 1885 1886 /* If the lease came from the config file, we don't need to stash 1887 a copy in the lease database. */ 1888 if (lease->is_static) 1889 return; 1890 1891 if (!leaseFile) { /* XXX */ 1892 leaseFile = fopen(path_dhclient_db, "w"); 1893 if (!leaseFile) 1894 error("can't create %s: %m", path_dhclient_db); 1895 } 1896 1897 fprintf(leaseFile, "lease {\n"); 1898 if (lease->is_bootp) 1899 fprintf(leaseFile, " bootp;\n"); 1900 fprintf(leaseFile, " interface \"%s\";\n", ip->name); 1901 fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address)); 1902 if (lease->nextserver.len == sizeof(inaddr_any) && 1903 0 != memcmp(lease->nextserver.iabuf, &inaddr_any, 1904 sizeof(inaddr_any))) 1905 fprintf(leaseFile, " next-server %s;\n", 1906 piaddr(lease->nextserver)); 1907 if (lease->filename) 1908 fprintf(leaseFile, " filename \"%s\";\n", lease->filename); 1909 if (lease->server_name) 1910 fprintf(leaseFile, " server-name \"%s\";\n", 1911 lease->server_name); 1912 if (lease->medium) 1913 fprintf(leaseFile, " medium \"%s\";\n", lease->medium->string); 1914 for (i = 0; i < 256; i++) 1915 if (lease->options[i].len) 1916 fprintf(leaseFile, " option %s %s;\n", 1917 dhcp_options[i].name, 1918 pretty_print_option(i, lease->options[i].data, 1919 lease->options[i].len, 1, 1)); 1920 1921 t = gmtime(&lease->renewal); 1922 fprintf(leaseFile, " renew %d %d/%d/%d %02d:%02d:%02d;\n", 1923 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1924 t->tm_hour, t->tm_min, t->tm_sec); 1925 t = gmtime(&lease->rebind); 1926 fprintf(leaseFile, " rebind %d %d/%d/%d %02d:%02d:%02d;\n", 1927 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1928 t->tm_hour, t->tm_min, t->tm_sec); 1929 t = gmtime(&lease->expiry); 1930 fprintf(leaseFile, " expire %d %d/%d/%d %02d:%02d:%02d;\n", 1931 t->tm_wday, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1932 t->tm_hour, t->tm_min, t->tm_sec); 1933 fprintf(leaseFile, "}\n"); 1934 fflush(leaseFile); 1935 } 1936 1937 void 1938 script_init(char *reason, struct string_list *medium) 1939 { 1940 size_t len, mediumlen = 0; 1941 struct imsg_hdr hdr; 1942 struct buf *buf; 1943 int errs; 1944 1945 if (medium != NULL && medium->string != NULL) 1946 mediumlen = strlen(medium->string); 1947 1948 hdr.code = IMSG_SCRIPT_INIT; 1949 hdr.len = sizeof(struct imsg_hdr) + 1950 sizeof(size_t) + mediumlen + 1951 sizeof(size_t) + strlen(reason); 1952 1953 if ((buf = buf_open(hdr.len)) == NULL) 1954 error("buf_open: %m"); 1955 1956 errs = 0; 1957 errs += buf_add(buf, &hdr, sizeof(hdr)); 1958 errs += buf_add(buf, &mediumlen, sizeof(mediumlen)); 1959 if (mediumlen > 0) 1960 errs += buf_add(buf, medium->string, mediumlen); 1961 len = strlen(reason); 1962 errs += buf_add(buf, &len, sizeof(len)); 1963 errs += buf_add(buf, reason, len); 1964 1965 if (errs) 1966 error("buf_add: %m"); 1967 1968 if (buf_close(privfd, buf) == -1) 1969 error("buf_close: %m"); 1970 } 1971 1972 void 1973 priv_script_init(char *reason, char *medium) 1974 { 1975 struct interface_info *ip = ifi; 1976 1977 if (ip) { 1978 ip->client->scriptEnvsize = 100; 1979 if (ip->client->scriptEnv == NULL) 1980 ip->client->scriptEnv = 1981 malloc(ip->client->scriptEnvsize * sizeof(char *)); 1982 if (ip->client->scriptEnv == NULL) 1983 error("script_init: no memory for environment"); 1984 1985 ip->client->scriptEnv[0] = strdup(CLIENT_PATH); 1986 if (ip->client->scriptEnv[0] == NULL) 1987 error("script_init: no memory for environment"); 1988 1989 ip->client->scriptEnv[1] = NULL; 1990 1991 script_set_env(ip->client, "", "interface", ip->name); 1992 1993 if (medium) 1994 script_set_env(ip->client, "", "medium", medium); 1995 1996 script_set_env(ip->client, "", "reason", reason); 1997 } 1998 } 1999 2000 void 2001 priv_script_write_params(char *prefix, struct client_lease *lease) 2002 { 2003 struct interface_info *ip = ifi; 2004 u_int8_t dbuf[1500], *dp = NULL; 2005 int i, len; 2006 char tbuf[128]; 2007 2008 script_set_env(ip->client, prefix, "ip_address", 2009 piaddr(lease->address)); 2010 2011 if (ip->client->config->default_actions[DHO_SUBNET_MASK] == 2012 ACTION_SUPERSEDE) { 2013 dp = ip->client->config->defaults[DHO_SUBNET_MASK].data; 2014 len = ip->client->config->defaults[DHO_SUBNET_MASK].len; 2015 } else { 2016 dp = lease->options[DHO_SUBNET_MASK].data; 2017 len = lease->options[DHO_SUBNET_MASK].len; 2018 } 2019 if (len && (len < sizeof(lease->address.iabuf))) { 2020 struct iaddr netmask, subnet, broadcast; 2021 2022 memcpy(netmask.iabuf, dp, len); 2023 netmask.len = len; 2024 subnet = subnet_number(lease->address, netmask); 2025 if (subnet.len) { 2026 script_set_env(ip->client, prefix, "network_number", 2027 piaddr(subnet)); 2028 if (!lease->options[DHO_BROADCAST_ADDRESS].len) { 2029 broadcast = broadcast_addr(subnet, netmask); 2030 if (broadcast.len) 2031 script_set_env(ip->client, prefix, 2032 "broadcast_address", 2033 piaddr(broadcast)); 2034 } 2035 } 2036 } 2037 2038 if (lease->filename) 2039 script_set_env(ip->client, prefix, "filename", lease->filename); 2040 if (lease->server_name) 2041 script_set_env(ip->client, prefix, "server_name", 2042 lease->server_name); 2043 for (i = 0; i < 256; i++) { 2044 len = 0; 2045 2046 if (ip->client->config->defaults[i].len) { 2047 if (lease->options[i].len) { 2048 switch ( 2049 ip->client->config->default_actions[i]) { 2050 case ACTION_DEFAULT: 2051 dp = lease->options[i].data; 2052 len = lease->options[i].len; 2053 break; 2054 case ACTION_SUPERSEDE: 2055 supersede: 2056 dp = ip->client-> 2057 config->defaults[i].data; 2058 len = ip->client-> 2059 config->defaults[i].len; 2060 break; 2061 case ACTION_PREPEND: 2062 len = ip->client-> 2063 config->defaults[i].len + 2064 lease->options[i].len; 2065 if (len >= sizeof(dbuf)) { 2066 warning("no space to %s %s", 2067 "prepend option", 2068 dhcp_options[i].name); 2069 goto supersede; 2070 } 2071 dp = dbuf; 2072 memcpy(dp, 2073 ip->client-> 2074 config->defaults[i].data, 2075 ip->client-> 2076 config->defaults[i].len); 2077 memcpy(dp + ip->client-> 2078 config->defaults[i].len, 2079 lease->options[i].data, 2080 lease->options[i].len); 2081 dp[len] = '\0'; 2082 break; 2083 case ACTION_APPEND: 2084 /* 2085 * When we append, we assume that we're 2086 * appending to text. Some MS servers 2087 * include a NUL byte at the end of 2088 * the search string provided. 2089 */ 2090 len = ip->client-> 2091 config->defaults[i].len + 2092 lease->options[i].len; 2093 if (len >= sizeof(dbuf)) { 2094 warning("no space to %s %s", 2095 "append option", 2096 dhcp_options[i].name); 2097 goto supersede; 2098 } 2099 memcpy(dbuf, 2100 lease->options[i].data, 2101 lease->options[i].len); 2102 for (dp = dbuf + lease->options[i].len; 2103 dp > dbuf; dp--, len--) 2104 if (dp[-1] != '\0') 2105 break; 2106 memcpy(dp, 2107 ip->client-> 2108 config->defaults[i].data, 2109 ip->client-> 2110 config->defaults[i].len); 2111 dp = dbuf; 2112 dp[len] = '\0'; 2113 } 2114 } else { 2115 dp = ip->client-> 2116 config->defaults[i].data; 2117 len = ip->client-> 2118 config->defaults[i].len; 2119 } 2120 } else if (lease->options[i].len) { 2121 len = lease->options[i].len; 2122 dp = lease->options[i].data; 2123 } else { 2124 len = 0; 2125 } 2126 if (len) { 2127 char name[256]; 2128 2129 if (dhcp_option_ev_name(name, sizeof(name), 2130 &dhcp_options[i])) 2131 script_set_env(ip->client, prefix, name, 2132 pretty_print_option(i, dp, len, 0, 0)); 2133 } 2134 } 2135 snprintf(tbuf, sizeof(tbuf), "%d", (int)lease->expiry); 2136 script_set_env(ip->client, prefix, "expiry", tbuf); 2137 } 2138 2139 void 2140 script_write_params(char *prefix, struct client_lease *lease) 2141 { 2142 size_t fn_len = 0, sn_len = 0, pr_len = 0; 2143 struct imsg_hdr hdr; 2144 struct buf *buf; 2145 int errs, i; 2146 2147 if (lease->filename != NULL) 2148 fn_len = strlen(lease->filename); 2149 if (lease->server_name != NULL) 2150 sn_len = strlen(lease->server_name); 2151 if (prefix != NULL) 2152 pr_len = strlen(prefix); 2153 2154 hdr.code = IMSG_SCRIPT_WRITE_PARAMS; 2155 hdr.len = sizeof(hdr) + sizeof(struct client_lease) + 2156 sizeof(size_t) + fn_len + sizeof(size_t) + sn_len + 2157 sizeof(size_t) + pr_len; 2158 2159 for (i = 0; i < 256; i++) 2160 hdr.len += sizeof(int) + lease->options[i].len; 2161 2162 scripttime = time(NULL); 2163 2164 if ((buf = buf_open(hdr.len)) == NULL) 2165 error("buf_open: %m"); 2166 2167 errs = 0; 2168 errs += buf_add(buf, &hdr, sizeof(hdr)); 2169 errs += buf_add(buf, lease, sizeof(struct client_lease)); 2170 errs += buf_add(buf, &fn_len, sizeof(fn_len)); 2171 errs += buf_add(buf, lease->filename, fn_len); 2172 errs += buf_add(buf, &sn_len, sizeof(sn_len)); 2173 errs += buf_add(buf, lease->server_name, sn_len); 2174 errs += buf_add(buf, &pr_len, sizeof(pr_len)); 2175 errs += buf_add(buf, prefix, pr_len); 2176 2177 for (i = 0; i < 256; i++) { 2178 errs += buf_add(buf, &lease->options[i].len, 2179 sizeof(lease->options[i].len)); 2180 errs += buf_add(buf, lease->options[i].data, 2181 lease->options[i].len); 2182 } 2183 2184 if (errs) 2185 error("buf_add: %m"); 2186 2187 if (buf_close(privfd, buf) == -1) 2188 error("buf_close: %m"); 2189 } 2190 2191 int 2192 script_go(void) 2193 { 2194 struct imsg_hdr hdr; 2195 struct buf *buf; 2196 int ret; 2197 2198 hdr.code = IMSG_SCRIPT_GO; 2199 hdr.len = sizeof(struct imsg_hdr); 2200 2201 if ((buf = buf_open(hdr.len)) == NULL) 2202 error("buf_open: %m"); 2203 2204 if (buf_add(buf, &hdr, sizeof(hdr))) 2205 error("buf_add: %m"); 2206 2207 if (buf_close(privfd, buf) == -1) 2208 error("buf_close: %m"); 2209 2210 bzero(&hdr, sizeof(hdr)); 2211 buf_read(privfd, &hdr, sizeof(hdr)); 2212 if (hdr.code != IMSG_SCRIPT_GO_RET) 2213 error("unexpected msg type %u", hdr.code); 2214 if (hdr.len != sizeof(hdr) + sizeof(int)) 2215 error("received corrupted message"); 2216 buf_read(privfd, &ret, sizeof(ret)); 2217 2218 scripttime = time(NULL); 2219 2220 return (ret); 2221 } 2222 2223 int 2224 priv_script_go(void) 2225 { 2226 char *scriptName, *argv[2], **envp, *epp[3], reason[] = "REASON=NBI"; 2227 static char client_path[] = CLIENT_PATH; 2228 struct interface_info *ip = ifi; 2229 int pid, wpid, wstatus; 2230 2231 scripttime = time(NULL); 2232 2233 if (ip) { 2234 scriptName = ip->client->config->script_name; 2235 envp = ip->client->scriptEnv; 2236 } else { 2237 scriptName = top_level_config.script_name; 2238 epp[0] = reason; 2239 epp[1] = client_path; 2240 epp[2] = NULL; 2241 envp = epp; 2242 } 2243 2244 argv[0] = scriptName; 2245 argv[1] = NULL; 2246 2247 pid = fork(); 2248 if (pid < 0) { 2249 error("fork: %m"); 2250 wstatus = 0; 2251 } else if (pid) { 2252 do { 2253 wpid = wait(&wstatus); 2254 } while (wpid != pid && wpid > 0); 2255 if (wpid < 0) { 2256 error("wait: %m"); 2257 wstatus = 0; 2258 } 2259 } else { 2260 execve(scriptName, argv, envp); 2261 error("execve (%s, ...): %m", scriptName); 2262 } 2263 2264 if (ip) 2265 script_flush_env(ip->client); 2266 2267 return (wstatus & 0xff); 2268 } 2269 2270 void 2271 script_set_env(struct client_state *client, const char *prefix, 2272 const char *name, const char *value) 2273 { 2274 int i, j, namelen; 2275 2276 namelen = strlen(name); 2277 2278 for (i = 0; client->scriptEnv[i]; i++) 2279 if (strncmp(client->scriptEnv[i], name, namelen) == 0 && 2280 client->scriptEnv[i][namelen] == '=') 2281 break; 2282 2283 if (client->scriptEnv[i]) 2284 /* Reuse the slot. */ 2285 free(client->scriptEnv[i]); 2286 else { 2287 /* New variable. Expand if necessary. */ 2288 if (i >= client->scriptEnvsize - 1) { 2289 char **newscriptEnv; 2290 int newscriptEnvsize = client->scriptEnvsize + 50; 2291 2292 newscriptEnv = realloc(client->scriptEnv, 2293 newscriptEnvsize); 2294 if (newscriptEnv == NULL) { 2295 free(client->scriptEnv); 2296 client->scriptEnv = NULL; 2297 client->scriptEnvsize = 0; 2298 error("script_set_env: no memory for variable"); 2299 } 2300 client->scriptEnv = newscriptEnv; 2301 client->scriptEnvsize = newscriptEnvsize; 2302 } 2303 /* need to set the NULL pointer at end of array beyond 2304 the new slot. */ 2305 client->scriptEnv[i + 1] = NULL; 2306 } 2307 /* Allocate space and format the variable in the appropriate slot. */ 2308 client->scriptEnv[i] = malloc(strlen(prefix) + strlen(name) + 1 + 2309 strlen(value) + 1); 2310 if (client->scriptEnv[i] == NULL) 2311 error("script_set_env: no memory for variable assignment"); 2312 2313 /* No `` or $() command substitution allowed in environment values! */ 2314 for (j=0; j < strlen(value); j++) 2315 switch (value[j]) { 2316 case '`': 2317 case '$': 2318 error("illegal character (%c) in value '%s'", value[j], 2319 value); 2320 /* not reached */ 2321 } 2322 snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) + 2323 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value); 2324 } 2325 2326 void 2327 script_flush_env(struct client_state *client) 2328 { 2329 int i; 2330 2331 for (i = 0; client->scriptEnv[i]; i++) { 2332 free(client->scriptEnv[i]); 2333 client->scriptEnv[i] = NULL; 2334 } 2335 client->scriptEnvsize = 0; 2336 } 2337 2338 int 2339 dhcp_option_ev_name(char *buf, size_t buflen, struct option *option) 2340 { 2341 int i; 2342 2343 for (i = 0; option->name[i]; i++) { 2344 if (i + 1 == buflen) 2345 return 0; 2346 if (option->name[i] == '-') 2347 buf[i] = '_'; 2348 else 2349 buf[i] = option->name[i]; 2350 } 2351 2352 buf[i] = 0; 2353 return 1; 2354 } 2355 2356 void 2357 go_daemon(void) 2358 { 2359 static int state = 0; 2360 cap_rights_t rights; 2361 2362 if (no_daemon || state) 2363 return; 2364 2365 state = 1; 2366 2367 /* Stop logging to stderr... */ 2368 log_perror = 0; 2369 2370 if (daemon(1, 0) == -1) 2371 error("daemon"); 2372 2373 cap_rights_init(&rights); 2374 2375 if (pidfile != NULL) { 2376 pidfile_write(pidfile); 2377 if (cap_rights_limit(pidfile_fileno(pidfile), &rights) < 0 && 2378 errno != ENOSYS) { 2379 error("can't limit pidfile descriptor: %m"); 2380 } 2381 } 2382 2383 /* we are chrooted, daemon(3) fails to open /dev/null */ 2384 if (nullfd != -1) { 2385 dup2(nullfd, STDIN_FILENO); 2386 dup2(nullfd, STDOUT_FILENO); 2387 dup2(nullfd, STDERR_FILENO); 2388 close(nullfd); 2389 nullfd = -1; 2390 } 2391 2392 if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) 2393 error("can't limit stdin: %m"); 2394 cap_rights_init(&rights, CAP_WRITE); 2395 if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) 2396 error("can't limit stdout: %m"); 2397 if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) 2398 error("can't limit stderr: %m"); 2399 } 2400 2401 int 2402 check_option(struct client_lease *l, int option) 2403 { 2404 char *opbuf; 2405 char *sbuf; 2406 2407 /* we use this, since this is what gets passed to dhclient-script */ 2408 2409 opbuf = pretty_print_option(option, l->options[option].data, 2410 l->options[option].len, 0, 0); 2411 2412 sbuf = option_as_string(option, l->options[option].data, 2413 l->options[option].len); 2414 2415 switch (option) { 2416 case DHO_SUBNET_MASK: 2417 case DHO_TIME_SERVERS: 2418 case DHO_NAME_SERVERS: 2419 case DHO_ROUTERS: 2420 case DHO_DOMAIN_NAME_SERVERS: 2421 case DHO_LOG_SERVERS: 2422 case DHO_COOKIE_SERVERS: 2423 case DHO_LPR_SERVERS: 2424 case DHO_IMPRESS_SERVERS: 2425 case DHO_RESOURCE_LOCATION_SERVERS: 2426 case DHO_SWAP_SERVER: 2427 case DHO_BROADCAST_ADDRESS: 2428 case DHO_NIS_SERVERS: 2429 case DHO_NTP_SERVERS: 2430 case DHO_NETBIOS_NAME_SERVERS: 2431 case DHO_NETBIOS_DD_SERVER: 2432 case DHO_FONT_SERVERS: 2433 case DHO_DHCP_SERVER_IDENTIFIER: 2434 case DHO_NISPLUS_SERVERS: 2435 case DHO_MOBILE_IP_HOME_AGENT: 2436 case DHO_SMTP_SERVER: 2437 case DHO_POP_SERVER: 2438 case DHO_NNTP_SERVER: 2439 case DHO_WWW_SERVER: 2440 case DHO_FINGER_SERVER: 2441 case DHO_IRC_SERVER: 2442 case DHO_STREETTALK_SERVER: 2443 case DHO_STREETTALK_DA_SERVER: 2444 if (!ipv4addrs(opbuf)) { 2445 warning("Invalid IP address in option: %s", opbuf); 2446 return (0); 2447 } 2448 return (1) ; 2449 case DHO_HOST_NAME: 2450 case DHO_NIS_DOMAIN: 2451 case DHO_NISPLUS_DOMAIN: 2452 case DHO_TFTP_SERVER_NAME: 2453 if (!res_hnok(sbuf)) { 2454 warning("Bogus Host Name option %d: %s (%s)", option, 2455 sbuf, opbuf); 2456 l->options[option].len = 0; 2457 free(l->options[option].data); 2458 } 2459 return (1); 2460 case DHO_DOMAIN_NAME: 2461 case DHO_DOMAIN_SEARCH: 2462 if (!res_hnok(sbuf)) { 2463 if (!check_search(sbuf)) { 2464 warning("Bogus domain search list %d: %s (%s)", 2465 option, sbuf, opbuf); 2466 l->options[option].len = 0; 2467 free(l->options[option].data); 2468 } 2469 } 2470 return (1); 2471 case DHO_PAD: 2472 case DHO_TIME_OFFSET: 2473 case DHO_BOOT_SIZE: 2474 case DHO_MERIT_DUMP: 2475 case DHO_ROOT_PATH: 2476 case DHO_EXTENSIONS_PATH: 2477 case DHO_IP_FORWARDING: 2478 case DHO_NON_LOCAL_SOURCE_ROUTING: 2479 case DHO_POLICY_FILTER: 2480 case DHO_MAX_DGRAM_REASSEMBLY: 2481 case DHO_DEFAULT_IP_TTL: 2482 case DHO_PATH_MTU_AGING_TIMEOUT: 2483 case DHO_PATH_MTU_PLATEAU_TABLE: 2484 case DHO_INTERFACE_MTU: 2485 case DHO_ALL_SUBNETS_LOCAL: 2486 case DHO_PERFORM_MASK_DISCOVERY: 2487 case DHO_MASK_SUPPLIER: 2488 case DHO_ROUTER_DISCOVERY: 2489 case DHO_ROUTER_SOLICITATION_ADDRESS: 2490 case DHO_STATIC_ROUTES: 2491 case DHO_TRAILER_ENCAPSULATION: 2492 case DHO_ARP_CACHE_TIMEOUT: 2493 case DHO_IEEE802_3_ENCAPSULATION: 2494 case DHO_DEFAULT_TCP_TTL: 2495 case DHO_TCP_KEEPALIVE_INTERVAL: 2496 case DHO_TCP_KEEPALIVE_GARBAGE: 2497 case DHO_VENDOR_ENCAPSULATED_OPTIONS: 2498 case DHO_NETBIOS_NODE_TYPE: 2499 case DHO_NETBIOS_SCOPE: 2500 case DHO_X_DISPLAY_MANAGER: 2501 case DHO_DHCP_REQUESTED_ADDRESS: 2502 case DHO_DHCP_LEASE_TIME: 2503 case DHO_DHCP_OPTION_OVERLOAD: 2504 case DHO_DHCP_MESSAGE_TYPE: 2505 case DHO_DHCP_PARAMETER_REQUEST_LIST: 2506 case DHO_DHCP_MESSAGE: 2507 case DHO_DHCP_MAX_MESSAGE_SIZE: 2508 case DHO_DHCP_RENEWAL_TIME: 2509 case DHO_DHCP_REBINDING_TIME: 2510 case DHO_DHCP_CLASS_IDENTIFIER: 2511 case DHO_DHCP_CLIENT_IDENTIFIER: 2512 case DHO_BOOTFILE_NAME: 2513 case DHO_DHCP_USER_CLASS_ID: 2514 case DHO_END: 2515 return (1); 2516 case DHO_CLASSLESS_ROUTES: 2517 return (check_classless_option(l->options[option].data, 2518 l->options[option].len)); 2519 default: 2520 warning("unknown dhcp option value 0x%x", option); 2521 return (unknown_ok); 2522 } 2523 } 2524 2525 /* RFC 3442 The Classless Static Routes option checks */ 2526 int 2527 check_classless_option(unsigned char *data, int len) 2528 { 2529 int i = 0; 2530 unsigned char width; 2531 in_addr_t addr, mask; 2532 2533 if (len < 5) { 2534 warning("Too small length: %d", len); 2535 return (0); 2536 } 2537 while(i < len) { 2538 width = data[i++]; 2539 if (width == 0) { 2540 i += 4; 2541 continue; 2542 } else if (width < 9) { 2543 addr = (in_addr_t)(data[i] << 24); 2544 i += 1; 2545 } else if (width < 17) { 2546 addr = (in_addr_t)(data[i] << 24) + 2547 (in_addr_t)(data[i + 1] << 16); 2548 i += 2; 2549 } else if (width < 25) { 2550 addr = (in_addr_t)(data[i] << 24) + 2551 (in_addr_t)(data[i + 1] << 16) + 2552 (in_addr_t)(data[i + 2] << 8); 2553 i += 3; 2554 } else if (width < 33) { 2555 addr = (in_addr_t)(data[i] << 24) + 2556 (in_addr_t)(data[i + 1] << 16) + 2557 (in_addr_t)(data[i + 2] << 8) + 2558 data[i + 3]; 2559 i += 4; 2560 } else { 2561 warning("Incorrect subnet width: %d", width); 2562 return (0); 2563 } 2564 mask = (in_addr_t)(~0) << (32 - width); 2565 addr = ntohl(addr); 2566 mask = ntohl(mask); 2567 2568 /* 2569 * From RFC 3442: 2570 * ... After deriving a subnet number and subnet mask 2571 * from each destination descriptor, the DHCP client 2572 * MUST zero any bits in the subnet number where the 2573 * corresponding bit in the mask is zero... 2574 */ 2575 if ((addr & mask) != addr) { 2576 addr &= mask; 2577 data[i - 1] = (unsigned char)( 2578 (addr >> (((32 - width)/8)*8)) & 0xFF); 2579 } 2580 i += 4; 2581 } 2582 if (i > len) { 2583 warning("Incorrect data length: %d (must be %d)", len, i); 2584 return (0); 2585 } 2586 return (1); 2587 } 2588 2589 int 2590 res_hnok(const char *dn) 2591 { 2592 int pch = PERIOD, ch = *dn++; 2593 2594 while (ch != '\0') { 2595 int nch = *dn++; 2596 2597 if (periodchar(ch)) { 2598 ; 2599 } else if (periodchar(pch)) { 2600 if (!borderchar(ch)) 2601 return (0); 2602 } else if (periodchar(nch) || nch == '\0') { 2603 if (!borderchar(ch)) 2604 return (0); 2605 } else { 2606 if (!middlechar(ch)) 2607 return (0); 2608 } 2609 pch = ch, ch = nch; 2610 } 2611 return (1); 2612 } 2613 2614 int 2615 check_search(const char *srch) 2616 { 2617 int pch = PERIOD, ch = *srch++; 2618 int domains = 1; 2619 2620 /* 256 char limit re resolv.conf(5) */ 2621 if (strlen(srch) > 256) 2622 return (0); 2623 2624 while (whitechar(ch)) 2625 ch = *srch++; 2626 2627 while (ch != '\0') { 2628 int nch = *srch++; 2629 2630 if (periodchar(ch) || whitechar(ch)) { 2631 ; 2632 } else if (periodchar(pch)) { 2633 if (!borderchar(ch)) 2634 return (0); 2635 } else if (periodchar(nch) || nch == '\0') { 2636 if (!borderchar(ch)) 2637 return (0); 2638 } else { 2639 if (!middlechar(ch)) 2640 return (0); 2641 } 2642 if (!whitechar(ch)) { 2643 pch = ch; 2644 } else { 2645 while (whitechar(nch)) { 2646 nch = *srch++; 2647 } 2648 if (nch != '\0') 2649 domains++; 2650 pch = PERIOD; 2651 } 2652 ch = nch; 2653 } 2654 /* 6 domain limit re resolv.conf(5) */ 2655 if (domains > 6) 2656 return (0); 2657 return (1); 2658 } 2659 2660 /* Does buf consist only of dotted decimal ipv4 addrs? 2661 * return how many if so, 2662 * otherwise, return 0 2663 */ 2664 int 2665 ipv4addrs(char * buf) 2666 { 2667 struct in_addr jnk; 2668 int count = 0; 2669 2670 while (inet_aton(buf, &jnk) == 1){ 2671 count++; 2672 while (periodchar(*buf) || digitchar(*buf)) 2673 buf++; 2674 if (*buf == '\0') 2675 return (count); 2676 while (*buf == ' ') 2677 buf++; 2678 } 2679 return (0); 2680 } 2681 2682 2683 char * 2684 option_as_string(unsigned int code, unsigned char *data, int len) 2685 { 2686 static char optbuf[32768]; /* XXX */ 2687 char *op = optbuf; 2688 int opleft = sizeof(optbuf); 2689 unsigned char *dp = data; 2690 2691 if (code > 255) 2692 error("option_as_string: bad code %d", code); 2693 2694 for (; dp < data + len; dp++) { 2695 if (!isascii(*dp) || !isprint(*dp)) { 2696 if (dp + 1 != data + len || *dp != 0) { 2697 snprintf(op, opleft, "\\%03o", *dp); 2698 op += 4; 2699 opleft -= 4; 2700 } 2701 } else if (*dp == '"' || *dp == '\'' || *dp == '$' || 2702 *dp == '`' || *dp == '\\') { 2703 *op++ = '\\'; 2704 *op++ = *dp; 2705 opleft -= 2; 2706 } else { 2707 *op++ = *dp; 2708 opleft--; 2709 } 2710 } 2711 if (opleft < 1) 2712 goto toobig; 2713 *op = 0; 2714 return optbuf; 2715 toobig: 2716 warning("dhcp option too large"); 2717 return "<error>"; 2718 } 2719 2720 int 2721 fork_privchld(int fd, int fd2) 2722 { 2723 struct pollfd pfd[1]; 2724 int nfds; 2725 2726 switch (fork()) { 2727 case -1: 2728 error("cannot fork"); 2729 case 0: 2730 break; 2731 default: 2732 return (0); 2733 } 2734 2735 setproctitle("%s [priv]", ifi->name); 2736 2737 setsid(); 2738 dup2(nullfd, STDIN_FILENO); 2739 dup2(nullfd, STDOUT_FILENO); 2740 dup2(nullfd, STDERR_FILENO); 2741 close(nullfd); 2742 close(fd2); 2743 close(ifi->rfdesc); 2744 ifi->rfdesc = -1; 2745 2746 for (;;) { 2747 pfd[0].fd = fd; 2748 pfd[0].events = POLLIN; 2749 if ((nfds = poll(pfd, 1, INFTIM)) == -1) 2750 if (errno != EINTR) 2751 error("poll error"); 2752 2753 if (nfds == 0 || !(pfd[0].revents & POLLIN)) 2754 continue; 2755 2756 dispatch_imsg(ifi, fd); 2757 } 2758 } 2759