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