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