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