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