1 /* $OpenBSD: engine.c,v 1.55 2024/11/21 13:35:20 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org> 5 * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org> 6 * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 7 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/types.h> 23 #include <sys/queue.h> 24 #include <sys/socket.h> 25 #include <sys/syslog.h> 26 #include <sys/uio.h> 27 #include <sys/mbuf.h> 28 29 #include <net/if.h> 30 #include <net/route.h> 31 #include <arpa/inet.h> 32 #include <netinet/in.h> 33 #include <netinet/if_ether.h> 34 #include <netinet/ip.h> 35 #include <netinet/udp.h> 36 37 #include <errno.h> 38 #include <event.h> 39 #include <imsg.h> 40 #include <pwd.h> 41 #include <signal.h> 42 #include <stddef.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <time.h> 47 #include <unistd.h> 48 #include <vis.h> 49 50 #include "checksum.h" 51 #include "log.h" 52 #include "dhcpleased.h" 53 #include "engine.h" 54 55 /* 56 * RFC 2131 4.1 p23 has "SHOULD be 4 seconds", we are a bit more aggressive, 57 * networks are faster these days. 58 */ 59 #define START_EXP_BACKOFF 1 60 #define MAX_EXP_BACKOFF_SLOW 64 /* RFC 2131 4.1 p23 */ 61 #define MAX_EXP_BACKOFF_FAST 2 62 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 63 64 enum if_state { 65 IF_DOWN, 66 IF_INIT, 67 /* IF_SELECTING, */ 68 IF_REQUESTING, 69 IF_BOUND, 70 IF_RENEWING, 71 IF_REBINDING, 72 /* IF_INIT_REBOOT, */ 73 IF_REBOOTING, 74 IF_IPV6_ONLY, 75 }; 76 77 const char* if_state_name[] = { 78 "Down", 79 "Init", 80 /* "Selecting", */ 81 "Requesting", 82 "Bound", 83 "Renewing", 84 "Rebinding", 85 /* "Init-Reboot", */ 86 "Rebooting", 87 "IPv6 only", 88 }; 89 90 struct dhcpleased_iface { 91 LIST_ENTRY(dhcpleased_iface) entries; 92 enum if_state state; 93 struct event timer; 94 struct timeval timo; 95 uint32_t if_index; 96 int rdomain; 97 int running; 98 struct ether_addr hw_address; 99 int link_state; 100 uint32_t cur_mtu; 101 uint32_t xid; 102 struct timespec request_time; 103 struct in_addr server_identifier; 104 struct in_addr dhcp_server; /* for unicast */ 105 struct in_addr requested_ip; 106 struct in_addr mask; 107 struct in_addr siaddr; 108 char file[4 * DHCP_FILE_LEN + 1]; 109 char hostname[4 * 255 + 1]; 110 char domainname[4 * 255 + 1]; 111 struct dhcp_route prev_routes[MAX_DHCP_ROUTES]; 112 int prev_routes_len; 113 struct dhcp_route routes[MAX_DHCP_ROUTES]; 114 int routes_len; 115 struct in_addr nameservers[MAX_RDNS_COUNT]; 116 uint32_t lease_time; 117 uint32_t renewal_time; 118 uint32_t rebinding_time; 119 uint32_t ipv6_only_time; 120 }; 121 122 LIST_HEAD(, dhcpleased_iface) dhcpleased_interfaces; 123 124 __dead void engine_shutdown(void); 125 void engine_sig_handler(int sig, short, void *); 126 void engine_dispatch_frontend(int, short, void *); 127 void engine_dispatch_main(int, short, void *); 128 #ifndef SMALL 129 void send_interface_info(struct dhcpleased_iface *, pid_t); 130 void engine_showinfo_ctl(pid_t, uint32_t); 131 #endif /* SMALL */ 132 void engine_update_iface(struct imsg_ifinfo *); 133 struct dhcpleased_iface *get_dhcpleased_iface_by_id(uint32_t); 134 void remove_dhcpleased_iface(uint32_t); 135 void parse_dhcp(struct dhcpleased_iface *, 136 struct imsg_dhcp *); 137 void state_transition(struct dhcpleased_iface *, enum 138 if_state); 139 void iface_timeout(int, short, void *); 140 void request_dhcp_discover(struct dhcpleased_iface *); 141 void request_dhcp_request(struct dhcpleased_iface *); 142 void log_lease(struct dhcpleased_iface *, int); 143 void log_rdns(struct dhcpleased_iface *, int); 144 void send_configure_interface(struct dhcpleased_iface *); 145 void send_rdns_proposal(struct dhcpleased_iface *); 146 void send_deconfigure_interface(struct dhcpleased_iface *); 147 void send_rdns_withdraw(struct dhcpleased_iface *); 148 void send_routes_withdraw(struct dhcpleased_iface *); 149 void parse_lease(struct dhcpleased_iface *, 150 struct imsg_ifinfo *); 151 int engine_imsg_compose_main(int, pid_t, void *, uint16_t); 152 void log_dhcp_hdr(struct dhcp_hdr *); 153 const char *dhcp_message_type2str(uint8_t); 154 155 #ifndef SMALL 156 struct dhcpleased_conf *engine_conf; 157 #endif /* SMALL */ 158 159 static struct imsgev *iev_frontend; 160 static struct imsgev *iev_main; 161 int64_t proposal_id; 162 163 void 164 engine_sig_handler(int sig, short event, void *arg) 165 { 166 /* 167 * Normal signal handler rules don't apply because libevent 168 * decouples for us. 169 */ 170 171 switch (sig) { 172 case SIGINT: 173 case SIGTERM: 174 engine_shutdown(); 175 default: 176 fatalx("unexpected signal"); 177 } 178 } 179 180 void 181 engine(int debug, int verbose) 182 { 183 struct event ev_sigint, ev_sigterm; 184 struct passwd *pw; 185 186 #ifndef SMALL 187 engine_conf = config_new_empty(); 188 #endif /* SMALL */ 189 190 log_init(debug, LOG_DAEMON); 191 log_setverbose(verbose); 192 193 if ((pw = getpwnam(DHCPLEASED_USER)) == NULL) 194 fatal("getpwnam"); 195 196 if (chdir("/") == -1) 197 fatal("chdir(\"/\")"); 198 199 if (unveil("/", "") == -1) 200 fatal("unveil /"); 201 if (unveil(NULL, NULL) == -1) 202 fatal("unveil"); 203 204 setproctitle("%s", "engine"); 205 log_procinit("engine"); 206 207 if (setgroups(1, &pw->pw_gid) || 208 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 209 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 210 fatal("can't drop privileges"); 211 212 if (pledge("stdio recvfd", NULL) == -1) 213 fatal("pledge"); 214 215 event_init(); 216 217 /* Setup signal handler(s). */ 218 signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL); 219 signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL); 220 signal_add(&ev_sigint, NULL); 221 signal_add(&ev_sigterm, NULL); 222 signal(SIGPIPE, SIG_IGN); 223 signal(SIGHUP, SIG_IGN); 224 225 /* Setup pipe and event handler to the main process. */ 226 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 227 fatal(NULL); 228 229 if (imsgbuf_init(&iev_main->ibuf, 3) == -1) 230 fatal(NULL); 231 imsgbuf_allow_fdpass(&iev_main->ibuf); 232 iev_main->handler = engine_dispatch_main; 233 234 /* Setup event handlers. */ 235 iev_main->events = EV_READ; 236 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 237 iev_main->handler, iev_main); 238 event_add(&iev_main->ev, NULL); 239 240 LIST_INIT(&dhcpleased_interfaces); 241 242 event_dispatch(); 243 244 engine_shutdown(); 245 } 246 247 __dead void 248 engine_shutdown(void) 249 { 250 /* Close pipes. */ 251 imsgbuf_clear(&iev_frontend->ibuf); 252 close(iev_frontend->ibuf.fd); 253 imsgbuf_clear(&iev_main->ibuf); 254 close(iev_main->ibuf.fd); 255 256 free(iev_frontend); 257 free(iev_main); 258 259 log_info("engine exiting"); 260 exit(0); 261 } 262 263 int 264 engine_imsg_compose_frontend(int type, pid_t pid, void *data, 265 uint16_t datalen) 266 { 267 return (imsg_compose_event(iev_frontend, type, 0, pid, -1, 268 data, datalen)); 269 } 270 271 int 272 engine_imsg_compose_main(int type, pid_t pid, void *data, 273 uint16_t datalen) 274 { 275 return (imsg_compose_event(iev_main, type, 0, pid, -1, 276 data, datalen)); 277 } 278 279 void 280 engine_dispatch_frontend(int fd, short event, void *bula) 281 { 282 struct imsgev *iev = bula; 283 struct imsgbuf *ibuf = &iev->ibuf; 284 struct imsg imsg; 285 struct dhcpleased_iface *iface; 286 ssize_t n; 287 int shut = 0; 288 #ifndef SMALL 289 int verbose; 290 #endif /* SMALL */ 291 uint32_t if_index, type; 292 293 if (event & EV_READ) { 294 if ((n = imsgbuf_read(ibuf)) == -1) 295 fatal("imsgbuf_read error"); 296 if (n == 0) /* Connection closed. */ 297 shut = 1; 298 } 299 if (event & EV_WRITE) { 300 if (imsgbuf_write(ibuf) == -1) { 301 if (errno == EPIPE) /* Connection closed. */ 302 shut = 1; 303 else 304 fatal("imsgbuf_write"); 305 } 306 } 307 308 for (;;) { 309 if ((n = imsg_get(ibuf, &imsg)) == -1) 310 fatal("%s: imsg_get error", __func__); 311 if (n == 0) /* No more messages. */ 312 break; 313 314 type = imsg_get_type(&imsg); 315 316 switch (type) { 317 #ifndef SMALL 318 case IMSG_CTL_LOG_VERBOSE: 319 if (imsg_get_data(&imsg, &verbose, 320 sizeof(verbose)) == -1) 321 fatalx("%s: invalid %s", __func__, i2s(type)); 322 323 log_setverbose(verbose); 324 break; 325 case IMSG_CTL_SHOW_INTERFACE_INFO: 326 if (imsg_get_data(&imsg, &if_index, 327 sizeof(if_index)) == -1) 328 fatalx("%s: invalid %s", __func__, i2s(type)); 329 330 engine_showinfo_ctl(imsg_get_pid(&imsg), if_index); 331 break; 332 case IMSG_REQUEST_REBOOT: 333 if (imsg_get_data(&imsg, &if_index, 334 sizeof(if_index)) == -1) 335 fatalx("%s: invalid %s", __func__, i2s(type)); 336 337 iface = get_dhcpleased_iface_by_id(if_index); 338 if (iface != NULL) { 339 switch (iface->state) { 340 case IF_DOWN: 341 break; 342 case IF_INIT: 343 case IF_REQUESTING: 344 state_transition(iface, iface->state); 345 break; 346 case IF_RENEWING: 347 case IF_REBINDING: 348 case IF_REBOOTING: 349 case IF_BOUND: 350 case IF_IPV6_ONLY: 351 state_transition(iface, IF_REBOOTING); 352 break; 353 } 354 } 355 break; 356 #endif /* SMALL */ 357 case IMSG_REMOVE_IF: 358 if (imsg_get_data(&imsg, &if_index, 359 sizeof(if_index)) == -1) 360 fatalx("%s: invalid %s", __func__, i2s(type)); 361 362 remove_dhcpleased_iface(if_index); 363 break; 364 case IMSG_DHCP: { 365 struct imsg_dhcp imsg_dhcp; 366 367 if (imsg_get_data(&imsg, &imsg_dhcp, 368 sizeof(imsg_dhcp)) == -1) 369 fatalx("%s: invalid %s", __func__, i2s(type)); 370 371 iface = get_dhcpleased_iface_by_id(imsg_dhcp.if_index); 372 if (iface != NULL) 373 parse_dhcp(iface, &imsg_dhcp); 374 break; 375 } 376 case IMSG_REPROPOSE_RDNS: 377 LIST_FOREACH (iface, &dhcpleased_interfaces, entries) 378 send_rdns_proposal(iface); 379 break; 380 default: 381 log_debug("%s: unexpected imsg %d", __func__, type); 382 break; 383 } 384 imsg_free(&imsg); 385 } 386 if (!shut) 387 imsg_event_add(iev); 388 else { 389 /* This pipe is dead. Remove its event handler. */ 390 event_del(&iev->ev); 391 event_loopexit(NULL); 392 } 393 } 394 395 void 396 engine_dispatch_main(int fd, short event, void *bula) 397 { 398 #ifndef SMALL 399 static struct dhcpleased_conf *nconf; 400 static struct iface_conf *iface_conf; 401 #endif /* SMALL */ 402 struct imsg imsg; 403 struct imsgev *iev = bula; 404 struct imsgbuf *ibuf = &iev->ibuf; 405 struct imsg_ifinfo imsg_ifinfo; 406 ssize_t n; 407 uint32_t type; 408 int shut = 0; 409 410 if (event & EV_READ) { 411 if ((n = imsgbuf_read(ibuf)) == -1) 412 fatal("imsgbuf_read error"); 413 if (n == 0) /* Connection closed. */ 414 shut = 1; 415 } 416 if (event & EV_WRITE) { 417 if (imsgbuf_write(ibuf) == -1) { 418 if (errno == EPIPE) /* Connection closed. */ 419 shut = 1; 420 else 421 fatal("imsgbuf_write"); 422 } 423 } 424 425 for (;;) { 426 if ((n = imsg_get(ibuf, &imsg)) == -1) 427 fatal("%s: imsg_get error", __func__); 428 if (n == 0) /* No more messages. */ 429 break; 430 431 type = imsg_get_type(&imsg); 432 433 switch (type) { 434 case IMSG_SOCKET_IPC: 435 /* 436 * Setup pipe and event handler to the frontend 437 * process. 438 */ 439 if (iev_frontend) 440 fatalx("%s: received unexpected imsg fd " 441 "to engine", __func__); 442 443 if ((fd = imsg_get_fd(&imsg)) == -1) 444 fatalx("%s: expected to receive imsg fd to " 445 "engine but didn't receive any", __func__); 446 447 iev_frontend = malloc(sizeof(struct imsgev)); 448 if (iev_frontend == NULL) 449 fatal(NULL); 450 451 if (imsgbuf_init(&iev_frontend->ibuf, fd) == -1) 452 fatal(NULL); 453 iev_frontend->handler = engine_dispatch_frontend; 454 iev_frontend->events = EV_READ; 455 456 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 457 iev_frontend->events, iev_frontend->handler, 458 iev_frontend); 459 event_add(&iev_frontend->ev, NULL); 460 461 if (pledge("stdio", NULL) == -1) 462 fatal("pledge"); 463 464 break; 465 case IMSG_UPDATE_IF: 466 if (imsg_get_data(&imsg, &imsg_ifinfo, 467 sizeof(imsg_ifinfo)) == -1) 468 fatalx("%s: invalid %s", __func__, i2s(type)); 469 if (imsg_ifinfo.lease[LEASE_SIZE - 1] != '\0') 470 fatalx("Invalid lease"); 471 472 engine_update_iface(&imsg_ifinfo); 473 break; 474 #ifndef SMALL 475 case IMSG_RECONF_CONF: 476 if (nconf != NULL) 477 fatalx("%s: IMSG_RECONF_CONF already in " 478 "progress", __func__); 479 if ((nconf = malloc(sizeof(struct dhcpleased_conf))) == 480 NULL) 481 fatal(NULL); 482 SIMPLEQ_INIT(&nconf->iface_list); 483 break; 484 case IMSG_RECONF_IFACE: 485 if ((iface_conf = malloc(sizeof(struct iface_conf))) 486 == NULL) 487 fatal(NULL); 488 489 if (imsg_get_data(&imsg, iface_conf, 490 sizeof(struct iface_conf)) == -1) 491 fatalx("%s: invalid %s", __func__, i2s(type)); 492 493 iface_conf->vc_id = NULL; 494 iface_conf->vc_id_len = 0; 495 iface_conf->c_id = NULL; 496 iface_conf->c_id_len = 0; 497 iface_conf->h_name = NULL; 498 SIMPLEQ_INSERT_TAIL(&nconf->iface_list, 499 iface_conf, entry); 500 break; 501 case IMSG_RECONF_VC_ID: 502 if (iface_conf == NULL) 503 fatalx("%s: %s without IMSG_RECONF_IFACE", 504 __func__, i2s(type)); 505 if (iface_conf->vc_id != NULL) 506 fatalx("%s: multiple %s for the same interface", 507 __func__, i2s(type)); 508 if ((iface_conf->vc_id_len = imsg_get_len(&imsg)) 509 > 255 + 2 || iface_conf->vc_id_len == 0) 510 fatalx("%s: invalid %s", __func__, i2s(type)); 511 if ((iface_conf->vc_id = malloc(iface_conf->vc_id_len)) 512 == NULL) 513 fatal(NULL); 514 if (imsg_get_data(&imsg, iface_conf->vc_id, 515 iface_conf->vc_id_len) == -1) 516 fatalx("%s: invalid %s", __func__, i2s(type)); 517 break; 518 case IMSG_RECONF_C_ID: 519 if (iface_conf == NULL) 520 fatalx("%s: %s without IMSG_RECONF_IFACE", 521 __func__, i2s(type)); 522 if (iface_conf->c_id != NULL) 523 fatalx("%s: multiple %s for the same interface", 524 __func__, i2s(type)); 525 if ((iface_conf->c_id_len = imsg_get_len(&imsg)) 526 > 255 + 2 || iface_conf->c_id_len == 0) 527 fatalx("%s: invalid %s", __func__, i2s(type)); 528 if ((iface_conf->c_id = malloc(iface_conf->c_id_len)) 529 == NULL) 530 fatal(NULL); 531 if (imsg_get_data(&imsg, iface_conf->c_id, 532 iface_conf->c_id_len) == -1) 533 fatalx("%s: invalid %s", __func__, i2s(type)); 534 break; 535 case IMSG_RECONF_H_NAME: { 536 size_t len; 537 538 if (iface_conf == NULL) 539 fatalx("%s: %s without IMSG_RECONF_IFACE", 540 __func__, i2s(type)); 541 if (iface_conf->h_name != NULL) 542 fatalx("%s: multiple %s for the same interface", 543 __func__, i2s(type)); 544 if ((len = imsg_get_len(&imsg)) > 256 || len == 0) 545 fatalx("%s: invalid %s", __func__, i2s(type)); 546 if ((iface_conf->h_name = malloc(len)) == NULL) 547 fatal(NULL); 548 if (imsg_get_data(&imsg, iface_conf->h_name, len) == -1) 549 fatalx("%s: invalid %s", __func__, i2s(type)); 550 if (iface_conf->h_name[len - 1] != '\0') 551 fatalx("Invalid hostname"); 552 break; 553 } 554 case IMSG_RECONF_END: { 555 struct dhcpleased_iface *iface; 556 int *ifaces; 557 int i, if_index; 558 char *if_name; 559 char ifnamebuf[IF_NAMESIZE]; 560 561 if (nconf == NULL) 562 fatalx("%s: %s without IMSG_RECONF_CONF", 563 __func__, i2s(type)); 564 565 ifaces = changed_ifaces(engine_conf, nconf); 566 merge_config(engine_conf, nconf); 567 nconf = NULL; 568 for (i = 0; ifaces[i] != 0; i++) { 569 if_index = ifaces[i]; 570 if_name = if_indextoname(if_index, ifnamebuf); 571 iface = get_dhcpleased_iface_by_id(if_index); 572 if (if_name == NULL || iface == NULL) 573 continue; 574 iface_conf = find_iface_conf( 575 &engine_conf->iface_list, if_name); 576 if (iface_conf == NULL) 577 continue; 578 if (iface_conf->ignore & IGN_DNS) 579 send_rdns_withdraw(iface); 580 if (iface_conf->ignore & IGN_ROUTES) 581 send_routes_withdraw(iface); 582 } 583 free(ifaces); 584 break; 585 } 586 #endif /* SMALL */ 587 default: 588 log_debug("%s: unexpected imsg %d", __func__, type); 589 break; 590 } 591 imsg_free(&imsg); 592 } 593 if (!shut) 594 imsg_event_add(iev); 595 else { 596 /* This pipe is dead. Remove its event handler. */ 597 event_del(&iev->ev); 598 event_loopexit(NULL); 599 } 600 } 601 602 #ifndef SMALL 603 void 604 send_interface_info(struct dhcpleased_iface *iface, pid_t pid) 605 { 606 struct ctl_engine_info cei; 607 608 memset(&cei, 0, sizeof(cei)); 609 cei.if_index = iface->if_index; 610 cei.running = iface->running; 611 cei.link_state = iface->link_state; 612 strlcpy(cei.state, if_state_name[iface->state], sizeof(cei.state)); 613 memcpy(&cei.request_time, &iface->request_time, 614 sizeof(cei.request_time)); 615 cei.server_identifier = iface->server_identifier; 616 cei.dhcp_server = iface->dhcp_server; 617 cei.requested_ip = iface->requested_ip; 618 cei.mask = iface->mask; 619 cei.routes_len = iface->routes_len; 620 memcpy(cei.routes, iface->routes, sizeof(cei.routes)); 621 memcpy(cei.nameservers, iface->nameservers, sizeof(cei.nameservers)); 622 cei.lease_time = iface->lease_time; 623 cei.renewal_time = iface->renewal_time; 624 cei.rebinding_time = iface->rebinding_time; 625 engine_imsg_compose_frontend(IMSG_CTL_SHOW_INTERFACE_INFO, pid, &cei, 626 sizeof(cei)); 627 } 628 629 void 630 engine_showinfo_ctl(pid_t pid, uint32_t if_index) 631 { 632 struct dhcpleased_iface *iface; 633 634 if ((iface = get_dhcpleased_iface_by_id(if_index)) != NULL) 635 send_interface_info(iface, pid); 636 else 637 engine_imsg_compose_frontend(IMSG_CTL_END, pid, NULL, 0); 638 } 639 #endif /* SMALL */ 640 641 void 642 engine_update_iface(struct imsg_ifinfo *imsg_ifinfo) 643 { 644 struct dhcpleased_iface *iface; 645 int need_refresh = 0; 646 647 iface = get_dhcpleased_iface_by_id(imsg_ifinfo->if_index); 648 649 if (iface == NULL) { 650 if ((iface = calloc(1, sizeof(*iface))) == NULL) 651 fatal("calloc"); 652 iface->state = IF_DOWN; 653 iface->xid = arc4random(); 654 iface->timo.tv_usec = arc4random_uniform(1000000); 655 evtimer_set(&iface->timer, iface_timeout, iface); 656 iface->if_index = imsg_ifinfo->if_index; 657 iface->rdomain = imsg_ifinfo->rdomain; 658 iface->running = imsg_ifinfo->running; 659 iface->link_state = imsg_ifinfo->link_state; 660 iface->requested_ip.s_addr = INADDR_ANY; 661 memcpy(&iface->hw_address, &imsg_ifinfo->hw_address, 662 sizeof(struct ether_addr)); 663 LIST_INSERT_HEAD(&dhcpleased_interfaces, iface, entries); 664 need_refresh = 1; 665 } else { 666 if (memcmp(&iface->hw_address, &imsg_ifinfo->hw_address, 667 sizeof(struct ether_addr)) != 0) { 668 memcpy(&iface->hw_address, &imsg_ifinfo->hw_address, 669 sizeof(struct ether_addr)); 670 need_refresh = 1; 671 } 672 if (imsg_ifinfo->rdomain != iface->rdomain) { 673 iface->rdomain = imsg_ifinfo->rdomain; 674 need_refresh = 1; 675 } 676 if (imsg_ifinfo->running != iface->running) { 677 iface->running = imsg_ifinfo->running; 678 need_refresh = 1; 679 } 680 681 if (imsg_ifinfo->link_state != iface->link_state) { 682 iface->link_state = imsg_ifinfo->link_state; 683 need_refresh = 1; 684 } 685 } 686 687 if (!need_refresh) 688 return; 689 690 if (iface->running && LINK_STATE_IS_UP(iface->link_state)) { 691 if (iface->requested_ip.s_addr == INADDR_ANY) 692 parse_lease(iface, imsg_ifinfo); 693 694 if (iface->requested_ip.s_addr == INADDR_ANY) 695 state_transition(iface, IF_INIT); 696 else 697 state_transition(iface, IF_REBOOTING); 698 } else 699 state_transition(iface, IF_DOWN); 700 } 701 struct dhcpleased_iface* 702 get_dhcpleased_iface_by_id(uint32_t if_index) 703 { 704 struct dhcpleased_iface *iface; 705 LIST_FOREACH (iface, &dhcpleased_interfaces, entries) { 706 if (iface->if_index == if_index) 707 return (iface); 708 } 709 710 return (NULL); 711 } 712 713 void 714 remove_dhcpleased_iface(uint32_t if_index) 715 { 716 struct dhcpleased_iface *iface; 717 718 iface = get_dhcpleased_iface_by_id(if_index); 719 720 if (iface == NULL) 721 return; 722 723 send_rdns_withdraw(iface); 724 send_deconfigure_interface(iface); 725 LIST_REMOVE(iface, entries); 726 evtimer_del(&iface->timer); 727 free(iface); 728 } 729 730 void 731 parse_dhcp(struct dhcpleased_iface *iface, struct imsg_dhcp *dhcp) 732 { 733 static uint8_t cookie[] = DHCP_COOKIE; 734 static struct ether_addr bcast_mac; 735 #ifndef SMALL 736 struct iface_conf *iface_conf; 737 #endif /* SMALL */ 738 struct ether_header *eh; 739 struct ether_addr ether_src, ether_dst; 740 struct ip *ip; 741 struct udphdr *udp; 742 struct dhcp_hdr *dhcp_hdr; 743 struct in_addr server_identifier, subnet_mask; 744 struct in_addr nameservers[MAX_RDNS_COUNT]; 745 struct dhcp_route routes[MAX_DHCP_ROUTES]; 746 size_t rem, i; 747 uint32_t sum, usum, lease_time = 0, renewal_time = 0; 748 uint32_t rebinding_time = 0; 749 uint32_t ipv6_only_time = 0; 750 uint8_t *p, dho = DHO_PAD, dho_len, slen; 751 uint8_t dhcp_message_type = 0; 752 int routes_len = 0, routers = 0, csr = 0; 753 char from[sizeof("xx:xx:xx:xx:xx:xx")]; 754 char to[sizeof("xx:xx:xx:xx:xx:xx")]; 755 char hbuf_src[INET_ADDRSTRLEN]; 756 char hbuf_dst[INET_ADDRSTRLEN]; 757 char hbuf[INET_ADDRSTRLEN]; 758 char domainname[4 * 255 + 1]; 759 char hostname[4 * 255 + 1]; 760 char ifnamebuf[IF_NAMESIZE], *if_name; 761 762 if (bcast_mac.ether_addr_octet[0] == 0) 763 memset(bcast_mac.ether_addr_octet, 0xff, ETHER_ADDR_LEN); 764 765 if_name = if_indextoname(iface->if_index, ifnamebuf); 766 767 #ifndef SMALL 768 iface_conf = find_iface_conf(&engine_conf->iface_list, if_name); 769 #endif /* SMALL*/ 770 771 memset(hbuf_src, 0, sizeof(hbuf_src)); 772 memset(hbuf_dst, 0, sizeof(hbuf_dst)); 773 774 p = dhcp->packet; 775 rem = dhcp->len; 776 777 if (rem < sizeof(*eh)) { 778 log_warnx("%s: message too short", __func__); 779 return; 780 } 781 eh = (struct ether_header *)p; 782 memcpy(ether_src.ether_addr_octet, eh->ether_shost, 783 sizeof(ether_src.ether_addr_octet)); 784 strlcpy(from, ether_ntoa(ðer_src), sizeof(from)); 785 memcpy(ether_dst.ether_addr_octet, eh->ether_dhost, 786 sizeof(ether_dst.ether_addr_octet)); 787 strlcpy(to, ether_ntoa(ðer_dst), sizeof(to)); 788 p += sizeof(*eh); 789 rem -= sizeof(*eh); 790 791 if (memcmp(ðer_dst, &iface->hw_address, sizeof(ether_dst)) != 0 && 792 memcmp(ðer_dst, &bcast_mac, sizeof(ether_dst)) != 0) 793 return ; /* silently ignore packet not for us */ 794 795 if (rem < sizeof(*ip)) 796 goto too_short; 797 798 if (log_getverbose() > 1) 799 log_debug("%s, from: %s, to: %s", __func__, from, to); 800 801 ip = (struct ip *)p; 802 803 if (rem < (size_t)ip->ip_hl << 2) 804 goto too_short; 805 806 if ((dhcp->csumflags & M_IPV4_CSUM_IN_OK) == 0 && 807 wrapsum(checksum((uint8_t *)ip, ip->ip_hl << 2, 0)) != 0) { 808 log_warnx("%s: bad IP checksum", __func__); 809 return; 810 } 811 if (rem < ntohs(ip->ip_len)) 812 goto too_short; 813 814 p += ip->ip_hl << 2; 815 rem -= ip->ip_hl << 2; 816 817 if (inet_ntop(AF_INET, &ip->ip_src, hbuf_src, sizeof(hbuf_src)) == NULL) 818 hbuf_src[0] = '\0'; 819 if (inet_ntop(AF_INET, &ip->ip_dst, hbuf_dst, sizeof(hbuf_dst)) == NULL) 820 hbuf_dst[0] = '\0'; 821 822 #ifndef SMALL 823 if (iface_conf != NULL) { 824 for (i = 0; (int)i < iface_conf->ignore_servers_len; i++) { 825 if (iface_conf->ignore_servers[i].s_addr == 826 ip->ip_src.s_addr) { 827 log_debug("ignoring server %s", hbuf_src); 828 return; 829 } 830 } 831 } 832 #endif /* SMALL */ 833 834 if (rem < sizeof(*udp)) 835 goto too_short; 836 837 udp = (struct udphdr *)p; 838 if (rem < ntohs(udp->uh_ulen)) 839 goto too_short; 840 841 if (rem > ntohs(udp->uh_ulen)) { 842 if (log_getverbose() > 1) { 843 log_debug("%s: accepting packet with %lu bytes of data" 844 " after udp payload", __func__, rem - 845 ntohs(udp->uh_ulen)); 846 } 847 rem = ntohs(udp->uh_ulen); 848 } 849 850 p += sizeof(*udp); 851 rem -= sizeof(*udp); 852 853 if ((dhcp->csumflags & M_UDP_CSUM_IN_OK) == 0) { 854 usum = udp->uh_sum; 855 udp->uh_sum = 0; 856 857 sum = wrapsum(checksum((uint8_t *)udp, sizeof(*udp), 858 checksum(p, rem, 859 checksum((uint8_t *)&ip->ip_src, 2 * sizeof(ip->ip_src), 860 IPPROTO_UDP + ntohs(udp->uh_ulen))))); 861 862 if (usum != 0 && usum != sum) { 863 log_warnx("%s: bad UDP checksum", __func__); 864 return; 865 } 866 } 867 868 if (log_getverbose() > 1) { 869 log_debug("%s: %s:%d -> %s:%d", __func__, hbuf_src, 870 ntohs(udp->uh_sport), hbuf_dst, ntohs(udp->uh_dport)); 871 } 872 873 if (rem < sizeof(*dhcp_hdr)) 874 goto too_short; 875 876 dhcp_hdr = (struct dhcp_hdr *)p; 877 p += sizeof(*dhcp_hdr); 878 rem -= sizeof(*dhcp_hdr); 879 880 dhcp_hdr->sname[DHCP_SNAME_LEN -1 ] = '\0'; /* ensure it's a string */ 881 dhcp_hdr->file[DHCP_FILE_LEN -1 ] = '\0'; /* ensure it's a string */ 882 883 if (log_getverbose() > 1) 884 log_dhcp_hdr(dhcp_hdr); 885 886 if (dhcp_hdr->op != DHCP_BOOTREPLY) { 887 log_warnx("%s: ignoring non-reply packet", __func__); 888 return; 889 } 890 891 if (ntohl(dhcp_hdr->xid) != iface->xid) 892 return; /* silently ignore wrong xid */ 893 894 if (rem < sizeof(cookie)) 895 goto too_short; 896 897 if (memcmp(p, cookie, sizeof(cookie)) != 0) { 898 log_warnx("%s: no dhcp cookie in packet from %s", __func__, 899 from); 900 return; 901 } 902 p += sizeof(cookie); 903 rem -= sizeof(cookie); 904 905 memset(&server_identifier, 0, sizeof(server_identifier)); 906 memset(&subnet_mask, 0, sizeof(subnet_mask)); 907 memset(&routes, 0, sizeof(routes)); 908 memset(&nameservers, 0, sizeof(nameservers)); 909 memset(hostname, 0, sizeof(hostname)); 910 memset(domainname, 0, sizeof(domainname)); 911 912 while (rem > 0 && dho != DHO_END) { 913 dho = *p; 914 p += 1; 915 rem -= 1; 916 /* only DHO_END and DHO_PAD are 1 byte long without length */ 917 if (dho == DHO_PAD || dho == DHO_END) 918 dho_len = 0; 919 else { 920 if (rem == 0) 921 goto too_short; /* missing option length */ 922 dho_len = *p; 923 p += 1; 924 rem -= 1; 925 if (rem < dho_len) 926 goto too_short; 927 } 928 929 switch (dho) { 930 case DHO_PAD: 931 if (log_getverbose() > 1) 932 log_debug("DHO_PAD"); 933 break; 934 case DHO_END: 935 if (log_getverbose() > 1) 936 log_debug("DHO_END"); 937 break; 938 case DHO_DHCP_MESSAGE_TYPE: 939 if (dho_len != 1) 940 goto wrong_length; 941 dhcp_message_type = *p; 942 if (log_getverbose() > 1) { 943 log_debug("DHO_DHCP_MESSAGE_TYPE: %s", 944 dhcp_message_type2str(dhcp_message_type)); 945 } 946 p += dho_len; 947 rem -= dho_len; 948 break; 949 case DHO_DHCP_SERVER_IDENTIFIER: 950 if (dho_len != sizeof(server_identifier)) 951 goto wrong_length; 952 memcpy(&server_identifier, p, 953 sizeof(server_identifier)); 954 if (log_getverbose() > 1) { 955 log_debug("DHO_DHCP_SERVER_IDENTIFIER: %s", 956 inet_ntop(AF_INET, &server_identifier, 957 hbuf, sizeof(hbuf))); 958 } 959 p += dho_len; 960 rem -= dho_len; 961 break; 962 case DHO_DHCP_LEASE_TIME: 963 if (dho_len != sizeof(lease_time)) 964 goto wrong_length; 965 memcpy(&lease_time, p, sizeof(lease_time)); 966 lease_time = ntohl(lease_time); 967 if (log_getverbose() > 1) { 968 log_debug("DHO_DHCP_LEASE_TIME %us", 969 lease_time); 970 } 971 p += dho_len; 972 rem -= dho_len; 973 break; 974 case DHO_SUBNET_MASK: 975 if (dho_len != sizeof(subnet_mask)) 976 goto wrong_length; 977 memcpy(&subnet_mask, p, sizeof(subnet_mask)); 978 if (log_getverbose() > 1) { 979 log_debug("DHO_SUBNET_MASK: %s", 980 inet_ntop(AF_INET, &subnet_mask, hbuf, 981 sizeof(hbuf))); 982 } 983 p += dho_len; 984 rem -= dho_len; 985 break; 986 case DHO_ROUTERS: 987 if (dho_len < sizeof(routes[routes_len].gw)) 988 goto wrong_length; 989 if (dho_len % sizeof(routes[routes_len].gw) != 0) 990 goto wrong_length; 991 992 /* 993 * Ignore routers option if classless static routes 994 * are present (RFC3442). 995 */ 996 if (!csr) { 997 routers = 1; 998 while (routes_len < MAX_DHCP_ROUTES && 999 dho_len > 0) { 1000 memcpy(&routes[routes_len].gw, p, 1001 sizeof(routes[routes_len].gw)); 1002 if (log_getverbose() > 1) { 1003 log_debug("DHO_ROUTER: %s", 1004 inet_ntop(AF_INET, 1005 &routes[routes_len].gw, 1006 hbuf, sizeof(hbuf))); 1007 } 1008 p += sizeof(routes[routes_len].gw); 1009 rem -= sizeof(routes[routes_len].gw); 1010 dho_len -= 1011 sizeof(routes[routes_len].gw); 1012 routes_len++; 1013 } 1014 } 1015 if (dho_len != 0) { 1016 /* ignore > MAX_DHCP_ROUTES routes */ 1017 p += dho_len; 1018 rem -= dho_len; 1019 } 1020 break; 1021 case DHO_DOMAIN_NAME_SERVERS: 1022 if (dho_len < sizeof(nameservers[0])) 1023 goto wrong_length; 1024 if (dho_len % sizeof(nameservers[0]) != 0) 1025 goto wrong_length; 1026 /* we limit ourself to 8 nameservers for proposals */ 1027 memcpy(&nameservers, p, MINIMUM(sizeof(nameservers), 1028 dho_len)); 1029 if (log_getverbose() > 1) { 1030 for (i = 0; i < MINIMUM(sizeof(nameservers), 1031 dho_len / sizeof(nameservers[0])); i++) { 1032 log_debug("DHO_DOMAIN_NAME_SERVERS: %s " 1033 "(%lu/%lu)", inet_ntop(AF_INET, 1034 &nameservers[i], hbuf, 1035 sizeof(hbuf)), i + 1, 1036 dho_len / sizeof(nameservers[0])); 1037 } 1038 } 1039 p += dho_len; 1040 rem -= dho_len; 1041 break; 1042 case DHO_HOST_NAME: 1043 if (dho_len < 1) { 1044 /* 1045 * Protocol violation: minimum length is 1; 1046 * pretend the option is not there 1047 */ 1048 break; 1049 } 1050 /* MUST delete trailing NUL, per RFC 2132 */ 1051 slen = dho_len; 1052 while (slen > 0 && p[slen - 1] == '\0') 1053 slen--; 1054 /* slen might be 0 here, pretend option is not there. */ 1055 strvisx(hostname, p, slen, VIS_SAFE); 1056 if (log_getverbose() > 1) 1057 log_debug("DHO_HOST_NAME: %s", hostname); 1058 p += dho_len; 1059 rem -= dho_len; 1060 break; 1061 case DHO_DOMAIN_NAME: 1062 if (dho_len < 1) { 1063 /* 1064 * Protocol violation: minimum length is 1; 1065 * pretend the option is not there 1066 */ 1067 break; 1068 } 1069 /* MUST delete trailing NUL, per RFC 2132 */ 1070 slen = dho_len; 1071 while (slen > 0 && p[slen - 1] == '\0') 1072 slen--; 1073 /* slen might be 0 here, pretend option is not there. */ 1074 strvisx(domainname, p, slen, VIS_SAFE); 1075 if (log_getverbose() > 1) 1076 log_debug("DHO_DOMAIN_NAME: %s", domainname); 1077 p += dho_len; 1078 rem -= dho_len; 1079 break; 1080 case DHO_DHCP_RENEWAL_TIME: 1081 if (dho_len != sizeof(renewal_time)) 1082 goto wrong_length; 1083 memcpy(&renewal_time, p, sizeof(renewal_time)); 1084 renewal_time = ntohl(renewal_time); 1085 if (log_getverbose() > 1) { 1086 log_debug("DHO_DHCP_RENEWAL_TIME %us", 1087 renewal_time); 1088 } 1089 p += dho_len; 1090 rem -= dho_len; 1091 break; 1092 case DHO_DHCP_REBINDING_TIME: 1093 if (dho_len != sizeof(rebinding_time)) 1094 goto wrong_length; 1095 memcpy(&rebinding_time, p, sizeof(rebinding_time)); 1096 rebinding_time = ntohl(rebinding_time); 1097 if (log_getverbose() > 1) { 1098 log_debug("DHO_DHCP_REBINDING_TIME %us", 1099 rebinding_time); 1100 } 1101 p += dho_len; 1102 rem -= dho_len; 1103 break; 1104 case DHO_DHCP_CLIENT_IDENTIFIER: 1105 /* the server is supposed to echo this back to us */ 1106 #ifndef SMALL 1107 if (iface_conf != NULL && iface_conf->c_id_len > 0) { 1108 if (dho_len != iface_conf->c_id[1]) { 1109 log_warnx("wrong " 1110 "DHO_DHCP_CLIENT_IDENTIFIER"); 1111 return; 1112 } 1113 if (memcmp(p, &iface_conf->c_id[2], dho_len) != 1114 0) { 1115 log_warnx("wrong " 1116 "DHO_DHCP_CLIENT_IDENTIFIER"); 1117 return; 1118 } 1119 } else 1120 #endif /* SMALL */ 1121 { 1122 if (dho_len != 1 + sizeof(iface->hw_address)) 1123 goto wrong_length; 1124 if (*p != HTYPE_ETHER) { 1125 log_warnx("DHO_DHCP_CLIENT_IDENTIFIER: " 1126 "wrong type"); 1127 return; 1128 } 1129 if (memcmp(p + 1, &iface->hw_address, 1130 sizeof(iface->hw_address)) != 0) { 1131 log_warnx("wrong " 1132 "DHO_DHCP_CLIENT_IDENTIFIER"); 1133 return; 1134 } 1135 } 1136 p += dho_len; 1137 rem -= dho_len; 1138 break; 1139 case DHO_CLASSLESS_STATIC_ROUTES: { 1140 int prefixlen, compressed_prefixlen; 1141 1142 csr = 1; 1143 if (routers) { 1144 /* 1145 * Ignore routers option if classless static 1146 * routes are present (RFC3442). 1147 */ 1148 routers = 0; 1149 routes_len = 0; 1150 } 1151 while (routes_len < MAX_DHCP_ROUTES && dho_len > 0) { 1152 prefixlen = *p; 1153 p += 1; 1154 rem -= 1; 1155 dho_len -= 1; 1156 1157 if (prefixlen < 0 || prefixlen > 32) { 1158 log_warnx("%s: invalid prefixlen: %d", 1159 __func__, prefixlen); 1160 return; 1161 } 1162 1163 if (prefixlen > 0) 1164 routes[routes_len].mask.s_addr = 1165 htonl(0xffffffff << (32 - 1166 prefixlen)); 1167 else 1168 routes[routes_len].mask.s_addr = 1169 INADDR_ANY; 1170 1171 compressed_prefixlen = (prefixlen + 7) / 8; 1172 if (dho_len < compressed_prefixlen) 1173 goto wrong_length; 1174 1175 memcpy(&routes[routes_len].dst, p, 1176 compressed_prefixlen); 1177 p += compressed_prefixlen; 1178 rem -= compressed_prefixlen; 1179 dho_len -= compressed_prefixlen; 1180 1181 if (dho_len < sizeof(routes[routes_len].gw)) 1182 goto wrong_length; 1183 1184 memcpy(&routes[routes_len].gw, p, 1185 sizeof(routes[routes_len].gw)); 1186 p += sizeof(routes[routes_len].gw); 1187 rem -= sizeof(routes[routes_len].gw); 1188 dho_len -= sizeof(routes[routes_len].gw); 1189 1190 routes_len++; 1191 } 1192 1193 if (dho_len != 0) { 1194 /* ignore > MAX_DHCP_ROUTES routes */ 1195 p += dho_len; 1196 rem -= dho_len; 1197 } 1198 break; 1199 } 1200 case DHO_IPV6_ONLY_PREFERRED: 1201 if (dho_len != sizeof(ipv6_only_time)) 1202 goto wrong_length; 1203 memcpy(&ipv6_only_time, p, sizeof(ipv6_only_time)); 1204 ipv6_only_time = ntohl(ipv6_only_time); 1205 if (log_getverbose() > 1) { 1206 log_debug("DHO_IPV6_ONLY_PREFERRED %us", 1207 ipv6_only_time); 1208 } 1209 p += dho_len; 1210 rem -= dho_len; 1211 break; 1212 default: 1213 if (log_getverbose() > 1) 1214 log_debug("DHO_%u, len: %u", dho, dho_len); 1215 p += dho_len; 1216 rem -= dho_len; 1217 } 1218 1219 } 1220 while (rem != 0) { 1221 if (*p != DHO_PAD) 1222 break; 1223 p++; 1224 rem--; 1225 } 1226 if (rem != 0) 1227 log_debug("%s: %lu bytes garbage data from %s", __func__, rem, 1228 from); 1229 1230 log_debug("%s on %s from %s/%s to %s/%s", 1231 dhcp_message_type2str(dhcp_message_type), if_name == NULL ? "?" : 1232 if_name, from, hbuf_src, to, hbuf_dst); 1233 1234 switch (dhcp_message_type) { 1235 case DHCPOFFER: 1236 if (iface->state != IF_INIT) { 1237 log_debug("ignoring unexpected DHCPOFFER"); 1238 return; 1239 } 1240 if (server_identifier.s_addr == INADDR_ANY && 1241 dhcp_hdr->yiaddr.s_addr == INADDR_ANY) { 1242 log_warnx("%s: did not receive server identifier or " 1243 "offered IP address", __func__); 1244 return; 1245 } 1246 #ifndef SMALL 1247 if (iface_conf != NULL && iface_conf->prefer_ipv6 && 1248 ipv6_only_time > 0) { 1249 iface->ipv6_only_time = ipv6_only_time; 1250 state_transition(iface, IF_IPV6_ONLY); 1251 break; 1252 } 1253 #endif 1254 iface->server_identifier = server_identifier; 1255 iface->dhcp_server = server_identifier; 1256 iface->requested_ip = dhcp_hdr->yiaddr; 1257 state_transition(iface, IF_REQUESTING); 1258 break; 1259 case DHCPACK: 1260 switch (iface->state) { 1261 case IF_REQUESTING: 1262 case IF_RENEWING: 1263 case IF_REBINDING: 1264 case IF_REBOOTING: 1265 break; 1266 default: 1267 log_debug("ignoring unexpected DHCPACK"); 1268 return; 1269 } 1270 if (server_identifier.s_addr == INADDR_ANY && 1271 dhcp_hdr->yiaddr.s_addr == INADDR_ANY) { 1272 log_warnx("%s: did not receive server identifier or " 1273 "offered IP address", __func__); 1274 return; 1275 } 1276 if (lease_time == 0) { 1277 log_warnx("%s no lease time from %s", __func__, from); 1278 return; 1279 } 1280 if (subnet_mask.s_addr == INADDR_ANY) { 1281 log_warnx("%s: no subnetmask received from %s", 1282 __func__, from); 1283 return; 1284 } 1285 1286 /* Defaults if we didn't receive renewal or rebinding time. */ 1287 if (renewal_time == 0) 1288 renewal_time = lease_time / 2; 1289 if (rebinding_time == 0) 1290 rebinding_time = lease_time - (lease_time / 8); 1291 1292 /* RFC 2131 4.4.5 */ 1293 /* Ignore invalid T1/T2 options */ 1294 if (renewal_time >= rebinding_time) { 1295 log_warnx("%s: renewal_time(%u) >= rebinding_time(%u) " 1296 "from %s: using defaults", 1297 __func__, renewal_time, rebinding_time, from); 1298 renewal_time = rebinding_time = 0; 1299 } else if (rebinding_time >= lease_time) { 1300 log_warnx("%s: rebinding_time(%u) >= lease_time(%u) " 1301 "from %s: using defaults", 1302 __func__, rebinding_time, lease_time, from); 1303 renewal_time = rebinding_time = 0; 1304 } 1305 1306 /* Defaults if we received wrong renewal or rebinding time. */ 1307 if (renewal_time == 0) 1308 renewal_time = lease_time / 2; 1309 if (rebinding_time == 0) 1310 rebinding_time = lease_time - (lease_time / 8); 1311 1312 clock_gettime(CLOCK_MONOTONIC, &iface->request_time); 1313 iface->server_identifier = server_identifier; 1314 iface->dhcp_server = server_identifier; 1315 iface->requested_ip = dhcp_hdr->yiaddr; 1316 iface->mask = subnet_mask; 1317 #ifndef SMALL 1318 if (iface_conf != NULL && iface_conf->ignore & IGN_ROUTES) { 1319 iface->routes_len = 0; 1320 memset(iface->routes, 0, sizeof(iface->routes)); 1321 } else 1322 #endif /* SMALL */ 1323 { 1324 iface->prev_routes_len = iface->routes_len; 1325 memcpy(iface->prev_routes, iface->routes, 1326 sizeof(iface->prev_routes)); 1327 iface->routes_len = routes_len; 1328 memcpy(iface->routes, routes, sizeof(iface->routes)); 1329 } 1330 iface->lease_time = lease_time; 1331 iface->renewal_time = renewal_time; 1332 iface->rebinding_time = rebinding_time; 1333 1334 #ifndef SMALL 1335 if (iface_conf != NULL && iface_conf->ignore & IGN_DNS) { 1336 memset(iface->nameservers, 0, 1337 sizeof(iface->nameservers)); 1338 } else 1339 #endif /* SMALL */ 1340 { 1341 memcpy(iface->nameservers, nameservers, 1342 sizeof(iface->nameservers)); 1343 } 1344 1345 iface->siaddr = dhcp_hdr->siaddr; 1346 1347 /* we made sure this is a string futher up */ 1348 strnvis(iface->file, dhcp_hdr->file, sizeof(iface->file), 1349 VIS_SAFE); 1350 1351 strlcpy(iface->domainname, domainname, 1352 sizeof(iface->domainname)); 1353 strlcpy(iface->hostname, hostname, sizeof(iface->hostname)); 1354 #ifndef SMALL 1355 if (iface_conf != NULL && iface_conf->prefer_ipv6 && 1356 ipv6_only_time > 0) { 1357 iface->ipv6_only_time = ipv6_only_time; 1358 state_transition(iface, IF_IPV6_ONLY); 1359 break; 1360 } 1361 #endif 1362 state_transition(iface, IF_BOUND); 1363 break; 1364 case DHCPNAK: 1365 switch (iface->state) { 1366 case IF_REQUESTING: 1367 case IF_RENEWING: 1368 case IF_REBINDING: 1369 case IF_REBOOTING: 1370 break; 1371 default: 1372 log_debug("ignoring unexpected DHCPNAK"); 1373 return; 1374 } 1375 1376 state_transition(iface, IF_INIT); 1377 break; 1378 default: 1379 log_warnx("%s: unimplemented message type %d", __func__, 1380 dhcp_message_type); 1381 break; 1382 } 1383 return; 1384 too_short: 1385 log_warnx("%s: message from %s too short", __func__, from); 1386 return; 1387 wrong_length: 1388 log_warnx("%s: received option %d with wrong length: %d", __func__, 1389 dho, dho_len); 1390 return; 1391 } 1392 1393 /* XXX check valid transitions */ 1394 void 1395 state_transition(struct dhcpleased_iface *iface, enum if_state new_state) 1396 { 1397 enum if_state old_state = iface->state; 1398 struct timespec now, res; 1399 char ifnamebuf[IF_NAMESIZE], *if_name; 1400 1401 iface->state = new_state; 1402 1403 switch (new_state) { 1404 case IF_DOWN: 1405 if (iface->requested_ip.s_addr == INADDR_ANY) { 1406 /* nothing to do until iface comes up */ 1407 iface->timo.tv_sec = -1; 1408 break; 1409 } 1410 if (old_state == IF_DOWN) { 1411 /* nameservers already withdrawn when if went down */ 1412 send_deconfigure_interface(iface); 1413 /* nothing more to do until iface comes back */ 1414 iface->timo.tv_sec = -1; 1415 } else { 1416 send_rdns_withdraw(iface); 1417 clock_gettime(CLOCK_MONOTONIC, &now); 1418 timespecsub(&now, &iface->request_time, &res); 1419 iface->timo.tv_sec = iface->lease_time - res.tv_sec; 1420 if (iface->timo.tv_sec < 0) 1421 iface->timo.tv_sec = 0; /* deconfigure now */ 1422 } 1423 break; 1424 case IF_INIT: 1425 switch (old_state) { 1426 case IF_INIT: 1427 if (iface->timo.tv_sec < MAX_EXP_BACKOFF_SLOW) 1428 iface->timo.tv_sec *= 2; 1429 break; 1430 case IF_REQUESTING: 1431 case IF_RENEWING: 1432 case IF_REBINDING: 1433 case IF_REBOOTING: 1434 /* lease expired, got DHCPNAK or timeout: delete IP */ 1435 send_rdns_withdraw(iface); 1436 send_deconfigure_interface(iface); 1437 /* fall through */ 1438 case IF_DOWN: 1439 case IF_IPV6_ONLY: 1440 iface->timo.tv_sec = START_EXP_BACKOFF; 1441 iface->xid = arc4random(); 1442 break; 1443 case IF_BOUND: 1444 fatalx("invalid transition Bound -> Init"); 1445 break; 1446 } 1447 request_dhcp_discover(iface); 1448 break; 1449 case IF_REBOOTING: 1450 if (old_state == IF_REBOOTING) 1451 iface->timo.tv_sec *= 2; 1452 else { 1453 iface->timo.tv_sec = START_EXP_BACKOFF; 1454 iface->xid = arc4random(); 1455 } 1456 request_dhcp_request(iface); 1457 break; 1458 case IF_REQUESTING: 1459 if (old_state == IF_REQUESTING) 1460 iface->timo.tv_sec *= 2; 1461 else 1462 iface->timo.tv_sec = START_EXP_BACKOFF; 1463 request_dhcp_request(iface); 1464 break; 1465 case IF_BOUND: 1466 iface->timo.tv_sec = iface->renewal_time; 1467 if (old_state == IF_REQUESTING || old_state == IF_REBOOTING) { 1468 send_configure_interface(iface); 1469 send_rdns_proposal(iface); 1470 } 1471 break; 1472 case IF_RENEWING: 1473 if (old_state == IF_BOUND) { 1474 iface->timo.tv_sec = (iface->rebinding_time - 1475 iface->renewal_time) / 2; /* RFC 2131 4.4.5 */ 1476 iface->xid = arc4random(); 1477 } else 1478 iface->timo.tv_sec /= 2; 1479 1480 if (iface->timo.tv_sec < 60) 1481 iface->timo.tv_sec = 60; 1482 request_dhcp_request(iface); 1483 break; 1484 case IF_REBINDING: 1485 if (old_state == IF_RENEWING) { 1486 iface->timo.tv_sec = (iface->lease_time - 1487 iface->rebinding_time) / 2; /* RFC 2131 4.4.5 */ 1488 } else 1489 iface->timo.tv_sec /= 2; 1490 request_dhcp_request(iface); 1491 break; 1492 case IF_IPV6_ONLY: 1493 switch (old_state) { 1494 case IF_REQUESTING: 1495 case IF_RENEWING: 1496 case IF_REBINDING: 1497 case IF_REBOOTING: 1498 /* going IPv6 only: delete legacy IP */ 1499 send_rdns_withdraw(iface); 1500 send_deconfigure_interface(iface); 1501 /* fall through */ 1502 case IF_INIT: 1503 case IF_DOWN: 1504 case IF_IPV6_ONLY: 1505 iface->timo.tv_sec = iface->ipv6_only_time; 1506 break; 1507 case IF_BOUND: 1508 fatalx("invalid transition Bound -> IPv6 only"); 1509 break; 1510 } 1511 } 1512 1513 if_name = if_indextoname(iface->if_index, ifnamebuf); 1514 log_debug("%s[%s] %s -> %s, timo: %lld", __func__, if_name == NULL ? 1515 "?" : if_name, if_state_name[old_state], if_state_name[new_state], 1516 iface->timo.tv_sec); 1517 1518 if (iface->timo.tv_sec == -1) { 1519 if (evtimer_pending(&iface->timer, NULL)) 1520 evtimer_del(&iface->timer); 1521 } else 1522 evtimer_add(&iface->timer, &iface->timo); 1523 } 1524 1525 void 1526 iface_timeout(int fd, short events, void *arg) 1527 { 1528 struct dhcpleased_iface *iface = (struct dhcpleased_iface *)arg; 1529 struct timespec now, res; 1530 1531 log_debug("%s[%d]: %s", __func__, iface->if_index, 1532 if_state_name[iface->state]); 1533 1534 switch (iface->state) { 1535 case IF_DOWN: 1536 state_transition(iface, IF_DOWN); 1537 break; 1538 case IF_INIT: 1539 state_transition(iface, IF_INIT); 1540 break; 1541 case IF_REBOOTING: 1542 if (iface->timo.tv_sec >= MAX_EXP_BACKOFF_FAST) 1543 state_transition(iface, IF_INIT); 1544 else 1545 state_transition(iface, IF_REBOOTING); 1546 break; 1547 case IF_REQUESTING: 1548 if (iface->timo.tv_sec >= MAX_EXP_BACKOFF_SLOW) 1549 state_transition(iface, IF_INIT); 1550 else 1551 state_transition(iface, IF_REQUESTING); 1552 break; 1553 case IF_BOUND: 1554 state_transition(iface, IF_RENEWING); 1555 break; 1556 case IF_RENEWING: 1557 clock_gettime(CLOCK_MONOTONIC, &now); 1558 timespecsub(&now, &iface->request_time, &res); 1559 log_debug("%s: res.tv_sec: %lld, rebinding_time: %u", __func__, 1560 res.tv_sec, iface->rebinding_time); 1561 if (res.tv_sec >= iface->rebinding_time) 1562 state_transition(iface, IF_REBINDING); 1563 else 1564 state_transition(iface, IF_RENEWING); 1565 break; 1566 case IF_REBINDING: 1567 clock_gettime(CLOCK_MONOTONIC, &now); 1568 timespecsub(&now, &iface->request_time, &res); 1569 log_debug("%s: res.tv_sec: %lld, lease_time: %u", __func__, 1570 res.tv_sec, iface->lease_time); 1571 if (res.tv_sec > iface->lease_time) 1572 state_transition(iface, IF_INIT); 1573 else 1574 state_transition(iface, IF_REBINDING); 1575 break; 1576 case IF_IPV6_ONLY: 1577 state_transition(iface, IF_REQUESTING); 1578 break; 1579 } 1580 } 1581 1582 void 1583 request_dhcp_discover(struct dhcpleased_iface *iface) 1584 { 1585 struct imsg_req_dhcp imsg; 1586 1587 memset(&imsg, 0, sizeof(imsg)); 1588 1589 imsg.if_index = iface->if_index; 1590 imsg.xid = iface->xid; 1591 1592 /* 1593 * similar to RFC 2131 4.3.6, Table 4 for DHCPDISCOVER 1594 * ------------------------------ 1595 * | | INIT | 1596 * ------------------------------ 1597 * |broad/unicast | broadcast | 1598 * |server-ip | MUST NOT | 1599 * |requested-ip | MAY | 1600 * |ciaddr | zero | 1601 * ------------------------------ 1602 * 1603 * Leaving everything at 0 from the memset results in this table with 1604 * requested-ip not set. 1605 */ 1606 1607 engine_imsg_compose_frontend(IMSG_SEND_DISCOVER, 0, &imsg, sizeof(imsg)); 1608 } 1609 1610 void 1611 request_dhcp_request(struct dhcpleased_iface *iface) 1612 { 1613 struct imsg_req_dhcp imsg; 1614 1615 imsg.if_index = iface->if_index; 1616 imsg.xid = iface->xid; 1617 1618 /* 1619 * RFC 2131 4.3.6, Table 4 1620 * --------------------------------------------------------------------- 1621 * | |REBOOTING |REQUESTING |RENEWING |REBINDING | 1622 * --------------------------------------------------------------------- 1623 * |broad/unicast |broadcast |broadcast |unicast |broadcast | 1624 * |server-ip |MUST NOT |MUST |MUST NOT |MUST NOT | 1625 * |requested-ip |MUST |MUST |MUST NOT |MUST NOT | 1626 * |ciaddr |zero |zero |IP address |IP address| 1627 * --------------------------------------------------------------------- 1628 */ 1629 switch (iface->state) { 1630 case IF_DOWN: 1631 fatalx("invalid state IF_DOWN in %s", __func__); 1632 break; 1633 case IF_INIT: 1634 fatalx("invalid state IF_INIT in %s", __func__); 1635 break; 1636 case IF_BOUND: 1637 fatalx("invalid state IF_BOUND in %s", __func__); 1638 break; 1639 case IF_REBOOTING: 1640 imsg.dhcp_server.s_addr = INADDR_ANY; /* broadcast */ 1641 imsg.server_identifier.s_addr = INADDR_ANY; /* MUST NOT */ 1642 imsg.requested_ip = iface->requested_ip; /* MUST */ 1643 imsg.ciaddr.s_addr = INADDR_ANY; /* zero */ 1644 break; 1645 case IF_REQUESTING: 1646 imsg.dhcp_server.s_addr = INADDR_ANY; /* broadcast */ 1647 imsg.server_identifier = 1648 iface->server_identifier; /* MUST */ 1649 imsg.requested_ip = iface->requested_ip; /* MUST */ 1650 imsg.ciaddr.s_addr = INADDR_ANY; /* zero */ 1651 break; 1652 case IF_RENEWING: 1653 imsg.dhcp_server = iface->dhcp_server; /* unicast */ 1654 imsg.server_identifier.s_addr = INADDR_ANY; /* MUST NOT */ 1655 imsg.requested_ip.s_addr = INADDR_ANY; /* MUST NOT */ 1656 imsg.ciaddr = iface->requested_ip; /* IP address */ 1657 break; 1658 case IF_REBINDING: 1659 imsg.dhcp_server.s_addr = INADDR_ANY; /* broadcast */ 1660 imsg.server_identifier.s_addr = INADDR_ANY; /* MUST NOT */ 1661 imsg.requested_ip.s_addr = INADDR_ANY; /* MUST NOT */ 1662 imsg.ciaddr = iface->requested_ip; /* IP address */ 1663 break; 1664 case IF_IPV6_ONLY: 1665 fatalx("invalid state IF_IPV6_ONLY in %s", __func__); 1666 break; 1667 } 1668 1669 engine_imsg_compose_frontend(IMSG_SEND_REQUEST, 0, &imsg, sizeof(imsg)); 1670 } 1671 1672 void 1673 log_lease(struct dhcpleased_iface *iface, int deconfigure) 1674 { 1675 char hbuf_lease[INET_ADDRSTRLEN], hbuf_server[INET_ADDRSTRLEN]; 1676 char ifnamebuf[IF_NAMESIZE], *if_name; 1677 1678 if_name = if_indextoname(iface->if_index, ifnamebuf); 1679 inet_ntop(AF_INET, &iface->requested_ip, hbuf_lease, 1680 sizeof(hbuf_lease)); 1681 inet_ntop(AF_INET, &iface->server_identifier, hbuf_server, 1682 sizeof(hbuf_server)); 1683 1684 1685 if (deconfigure) 1686 log_info("deleting %s from %s (lease from %s)", hbuf_lease, 1687 if_name == NULL ? "?" : if_name, hbuf_server); 1688 else 1689 log_info("adding %s to %s (lease from %s)", hbuf_lease, 1690 if_name == NULL ? "?" : if_name, hbuf_server); 1691 } 1692 1693 void 1694 send_configure_interface(struct dhcpleased_iface *iface) 1695 { 1696 struct imsg_configure_interface imsg; 1697 int i, j, found; 1698 1699 log_lease(iface, 0); 1700 1701 memset(&imsg, 0, sizeof(imsg)); 1702 imsg.if_index = iface->if_index; 1703 imsg.rdomain = iface->rdomain; 1704 imsg.addr = iface->requested_ip; 1705 imsg.mask = iface->mask; 1706 imsg.siaddr = iface->siaddr; 1707 strlcpy(imsg.file, iface->file, sizeof(imsg.file)); 1708 strlcpy(imsg.domainname, iface->domainname, sizeof(imsg.domainname)); 1709 strlcpy(imsg.hostname, iface->hostname, sizeof(imsg.hostname)); 1710 for (i = 0; i < iface->prev_routes_len; i++) { 1711 found = 0; 1712 for (j = 0; j < iface->routes_len; j++) { 1713 if (memcmp(&iface->prev_routes[i], &iface->routes[j], 1714 sizeof(struct dhcp_route)) == 0) { 1715 found = 1; 1716 break; 1717 } 1718 } 1719 if (!found) 1720 imsg.routes[imsg.routes_len++] = iface->prev_routes[i]; 1721 } 1722 if (imsg.routes_len > 0) 1723 engine_imsg_compose_main(IMSG_WITHDRAW_ROUTES, 0, &imsg, 1724 sizeof(imsg)); 1725 imsg.routes_len = iface->routes_len; 1726 memcpy(imsg.routes, iface->routes, sizeof(imsg.routes)); 1727 engine_imsg_compose_main(IMSG_CONFIGURE_INTERFACE, 0, &imsg, 1728 sizeof(imsg)); 1729 } 1730 1731 void 1732 send_deconfigure_interface(struct dhcpleased_iface *iface) 1733 { 1734 struct imsg_configure_interface imsg; 1735 1736 if (iface->requested_ip.s_addr == INADDR_ANY) 1737 return; 1738 1739 log_lease(iface, 1); 1740 1741 imsg.if_index = iface->if_index; 1742 imsg.rdomain = iface->rdomain; 1743 imsg.addr = iface->requested_ip; 1744 imsg.mask = iface->mask; 1745 imsg.siaddr = iface->siaddr; 1746 strlcpy(imsg.file, iface->file, sizeof(imsg.file)); 1747 strlcpy(imsg.domainname, iface->domainname, sizeof(imsg.domainname)); 1748 strlcpy(imsg.hostname, iface->hostname, sizeof(imsg.hostname)); 1749 imsg.routes_len = iface->routes_len; 1750 memcpy(imsg.routes, iface->routes, sizeof(imsg.routes)); 1751 engine_imsg_compose_main(IMSG_DECONFIGURE_INTERFACE, 0, &imsg, 1752 sizeof(imsg)); 1753 1754 iface->server_identifier.s_addr = INADDR_ANY; 1755 iface->dhcp_server.s_addr = INADDR_ANY; 1756 iface->requested_ip.s_addr = INADDR_ANY; 1757 iface->mask.s_addr = INADDR_ANY; 1758 iface->routes_len = 0; 1759 memset(iface->routes, 0, sizeof(iface->routes)); 1760 } 1761 1762 void 1763 send_routes_withdraw(struct dhcpleased_iface *iface) 1764 { 1765 struct imsg_configure_interface imsg; 1766 1767 if (iface->requested_ip.s_addr == INADDR_ANY || iface->routes_len == 0) 1768 return; 1769 1770 imsg.if_index = iface->if_index; 1771 imsg.rdomain = iface->rdomain; 1772 imsg.addr = iface->requested_ip; 1773 imsg.mask = iface->mask; 1774 imsg.siaddr = iface->siaddr; 1775 strlcpy(imsg.file, iface->file, sizeof(imsg.file)); 1776 strlcpy(imsg.domainname, iface->domainname, sizeof(imsg.domainname)); 1777 strlcpy(imsg.hostname, iface->hostname, sizeof(imsg.hostname)); 1778 imsg.routes_len = iface->routes_len; 1779 memcpy(imsg.routes, iface->routes, sizeof(imsg.routes)); 1780 engine_imsg_compose_main(IMSG_WITHDRAW_ROUTES, 0, &imsg, 1781 sizeof(imsg)); 1782 } 1783 1784 void 1785 log_rdns(struct dhcpleased_iface *iface, int withdraw) 1786 { 1787 int i; 1788 char hbuf_rdns[INET_ADDRSTRLEN], hbuf_server[INET_ADDRSTRLEN]; 1789 char ifnamebuf[IF_NAMESIZE], *if_name, *rdns_buf = NULL, *tmp_buf; 1790 1791 if_name = if_indextoname(iface->if_index, ifnamebuf); 1792 1793 inet_ntop(AF_INET, &iface->server_identifier, hbuf_server, 1794 sizeof(hbuf_server)); 1795 1796 for (i = 0; i < MAX_RDNS_COUNT && iface->nameservers[i].s_addr != 1797 INADDR_ANY; i++) { 1798 inet_ntop(AF_INET, &iface->nameservers[i], hbuf_rdns, 1799 sizeof(hbuf_rdns)); 1800 tmp_buf = rdns_buf; 1801 if (asprintf(&rdns_buf, "%s %s", tmp_buf ? tmp_buf : "", 1802 hbuf_rdns) < 0) { 1803 rdns_buf = NULL; 1804 break; 1805 } 1806 free(tmp_buf); 1807 } 1808 1809 if (rdns_buf != NULL) { 1810 if (withdraw) { 1811 log_info("deleting nameservers%s (lease from %s on %s)", 1812 rdns_buf, hbuf_server, if_name == NULL ? "?" : 1813 if_name); 1814 } else { 1815 log_info("adding nameservers%s (lease from %s on %s)", 1816 rdns_buf, hbuf_server, if_name == NULL ? "?" : 1817 if_name); 1818 } 1819 free(rdns_buf); 1820 } 1821 } 1822 1823 void 1824 send_rdns_proposal(struct dhcpleased_iface *iface) 1825 { 1826 struct imsg_propose_rdns imsg; 1827 1828 log_rdns(iface, 0); 1829 1830 memset(&imsg, 0, sizeof(imsg)); 1831 1832 imsg.if_index = iface->if_index; 1833 imsg.rdomain = iface->rdomain; 1834 for (imsg.rdns_count = 0; imsg.rdns_count < MAX_RDNS_COUNT && 1835 iface->nameservers[imsg.rdns_count].s_addr != INADDR_ANY; 1836 imsg.rdns_count++) 1837 ; 1838 memcpy(imsg.rdns, iface->nameservers, sizeof(imsg.rdns)); 1839 engine_imsg_compose_main(IMSG_PROPOSE_RDNS, 0, &imsg, sizeof(imsg)); 1840 } 1841 1842 void 1843 send_rdns_withdraw(struct dhcpleased_iface *iface) 1844 { 1845 struct imsg_propose_rdns imsg; 1846 1847 log_rdns(iface, 1); 1848 1849 memset(&imsg, 0, sizeof(imsg)); 1850 1851 imsg.if_index = iface->if_index; 1852 imsg.rdomain = iface->rdomain; 1853 engine_imsg_compose_main(IMSG_WITHDRAW_RDNS, 0, &imsg, sizeof(imsg)); 1854 memset(iface->nameservers, 0, sizeof(iface->nameservers)); 1855 } 1856 1857 void 1858 parse_lease(struct dhcpleased_iface *iface, struct imsg_ifinfo *imsg_ifinfo) 1859 { 1860 char *p, *p1; 1861 1862 iface->requested_ip.s_addr = INADDR_ANY; 1863 1864 if ((p = strstr(imsg_ifinfo->lease, LEASE_IP_PREFIX)) == NULL) 1865 return; 1866 1867 p += sizeof(LEASE_IP_PREFIX) - 1; 1868 if ((p1 = strchr(p, '\n')) == NULL) 1869 return; 1870 *p1 = '\0'; 1871 1872 if (inet_pton(AF_INET, p, &iface->requested_ip) != 1) 1873 iface->requested_ip.s_addr = INADDR_ANY; 1874 } 1875 1876 void 1877 log_dhcp_hdr(struct dhcp_hdr *dhcp_hdr) 1878 { 1879 #ifndef SMALL 1880 char hbuf[INET_ADDRSTRLEN]; 1881 1882 log_debug("dhcp_hdr op: %s (%d)", dhcp_hdr->op == DHCP_BOOTREQUEST ? 1883 "Boot Request" : dhcp_hdr->op == DHCP_BOOTREPLY ? "Boot Reply" : 1884 "Unknown", dhcp_hdr->op); 1885 log_debug("dhcp_hdr htype: %s (%d)", dhcp_hdr->htype == 1 ? "Ethernet": 1886 "Unknown", dhcp_hdr->htype); 1887 log_debug("dhcp_hdr hlen: %d", dhcp_hdr->hlen); 1888 log_debug("dhcp_hdr hops: %d", dhcp_hdr->hops); 1889 log_debug("dhcp_hdr xid: 0x%x", ntohl(dhcp_hdr->xid)); 1890 log_debug("dhcp_hdr secs: %u", dhcp_hdr->secs); 1891 log_debug("dhcp_hdr flags: 0x%x", dhcp_hdr->flags); 1892 log_debug("dhcp_hdr ciaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->ciaddr, 1893 hbuf, sizeof(hbuf))); 1894 log_debug("dhcp_hdr yiaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->yiaddr, 1895 hbuf, sizeof(hbuf))); 1896 log_debug("dhcp_hdr siaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->siaddr, 1897 hbuf, sizeof(hbuf))); 1898 log_debug("dhcp_hdr giaddr: %s", inet_ntop(AF_INET, &dhcp_hdr->giaddr, 1899 hbuf, sizeof(hbuf))); 1900 log_debug("dhcp_hdr chaddr: %02x:%02x:%02x:%02x:%02x:%02x " 1901 "(%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x)", 1902 dhcp_hdr->chaddr[0], dhcp_hdr->chaddr[1], dhcp_hdr->chaddr[2], 1903 dhcp_hdr->chaddr[3], dhcp_hdr->chaddr[4], dhcp_hdr->chaddr[5], 1904 dhcp_hdr->chaddr[6], dhcp_hdr->chaddr[7], dhcp_hdr->chaddr[8], 1905 dhcp_hdr->chaddr[9], dhcp_hdr->chaddr[10], dhcp_hdr->chaddr[11], 1906 dhcp_hdr->chaddr[12], dhcp_hdr->chaddr[13], dhcp_hdr->chaddr[14], 1907 dhcp_hdr->chaddr[15]); 1908 /* ignore sname and file, if we ever print it use strvis(3) */ 1909 #endif 1910 } 1911 1912 const char * 1913 dhcp_message_type2str(uint8_t dhcp_message_type) 1914 { 1915 switch (dhcp_message_type) { 1916 case DHCPDISCOVER: 1917 return "DHCPDISCOVER"; 1918 case DHCPOFFER: 1919 return "DHCPOFFER"; 1920 case DHCPREQUEST: 1921 return "DHCPREQUEST"; 1922 case DHCPDECLINE: 1923 return "DHCPDECLINE"; 1924 case DHCPACK: 1925 return "DHCPACK"; 1926 case DHCPNAK: 1927 return "DHCPNAK"; 1928 case DHCPRELEASE: 1929 return "DHCPRELEASE"; 1930 case DHCPINFORM: 1931 return "DHCPINFORM"; 1932 default: 1933 return "Unknown"; 1934 } 1935 } 1936