1 /* $OpenBSD: dhcpleased.c,v 1.39 2024/11/21 13:35:20 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org> 5 * Copyright (c) 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 #include <sys/types.h> 22 #include <sys/ioctl.h> 23 #include <sys/queue.h> 24 #include <sys/socket.h> 25 #include <sys/stat.h> 26 #include <sys/syslog.h> 27 #include <sys/sysctl.h> 28 #include <sys/uio.h> 29 #include <sys/wait.h> 30 31 #include <net/if.h> 32 #include <net/route.h> 33 #include <net/if_dl.h> 34 #include <netinet/in.h> 35 #include <netinet/if_ether.h> 36 #include <netinet/in_var.h> 37 38 #include <arpa/inet.h> 39 40 #include <err.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <event.h> 44 #include <ifaddrs.h> 45 #include <imsg.h> 46 #include <netdb.h> 47 #include <pwd.h> 48 #include <stddef.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <signal.h> 53 #include <unistd.h> 54 55 #include "bpf.h" 56 #include "log.h" 57 #include "dhcpleased.h" 58 #include "frontend.h" 59 #include "engine.h" 60 #include "control.h" 61 62 enum dhcpleased_process { 63 PROC_MAIN, 64 PROC_ENGINE, 65 PROC_FRONTEND 66 }; 67 68 __dead void usage(void); 69 __dead void main_shutdown(void); 70 71 void main_sig_handler(int, short, void *); 72 73 static pid_t start_child(enum dhcpleased_process, char *, int, int, int); 74 75 void main_dispatch_frontend(int, short, void *); 76 void main_dispatch_engine(int, short, void *); 77 void open_bpfsock(uint32_t); 78 void configure_interface(struct imsg_configure_interface *); 79 void deconfigure_interface(struct imsg_configure_interface *); 80 void propose_rdns(struct imsg_propose_rdns *); 81 void configure_routes(uint8_t, struct imsg_configure_interface *); 82 void configure_route(uint8_t, uint32_t, int, struct sockaddr_in *, struct 83 sockaddr_in *, struct sockaddr_in *, struct sockaddr_in *, int); 84 void read_lease_file(struct imsg_ifinfo *); 85 86 static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); 87 int main_imsg_compose_frontend(int, int, void *, uint16_t); 88 int main_imsg_compose_engine(int, int, void *, uint16_t); 89 90 #ifndef SMALL 91 int main_imsg_send_config(struct dhcpleased_conf *); 92 #endif /* SMALL */ 93 int main_reload(void); 94 95 static struct imsgev *iev_frontend; 96 static struct imsgev *iev_engine; 97 98 #ifndef SMALL 99 struct dhcpleased_conf *main_conf; 100 #endif 101 const char default_conffile[] = _PATH_CONF_FILE; 102 const char *conffile = default_conffile; 103 pid_t frontend_pid; 104 pid_t engine_pid; 105 106 int routesock, ioctl_sock, rtm_seq, no_lease_files; 107 108 void 109 main_sig_handler(int sig, short event, void *arg) 110 { 111 /* 112 * Normal signal handler rules don't apply because libevent 113 * decouples for us. 114 */ 115 116 switch (sig) { 117 case SIGTERM: 118 case SIGINT: 119 main_shutdown(); 120 case SIGHUP: 121 #ifndef SMALL 122 if (main_reload() == -1) 123 log_warnx("configuration reload failed"); 124 else 125 log_debug("configuration reloaded"); 126 #endif /* SMALL */ 127 break; 128 default: 129 fatalx("unexpected signal"); 130 } 131 } 132 133 __dead void 134 usage(void) 135 { 136 extern char *__progname; 137 138 fprintf(stderr, "usage: %s [-dnv] [-f file] [-s socket]\n", 139 __progname); 140 exit(1); 141 } 142 143 int 144 main(int argc, char *argv[]) 145 { 146 struct event ev_sigint, ev_sigterm, ev_sighup; 147 int ch; 148 int debug = 0, engine_flag = 0, frontend_flag = 0; 149 int verbose = 0, no_action = 0; 150 char *saved_argv0; 151 int pipe_main2frontend[2]; 152 int pipe_main2engine[2]; 153 int frontend_routesock, rtfilter, lockfd; 154 int rtable_any = RTABLE_ANY; 155 char *csock = _PATH_DHCPLEASED_SOCKET; 156 #ifndef SMALL 157 int control_fd; 158 #endif /* SMALL */ 159 160 log_init(1, LOG_DAEMON); /* Log to stderr until daemonized. */ 161 log_setverbose(1); 162 163 saved_argv0 = argv[0]; 164 if (saved_argv0 == NULL) 165 saved_argv0 = "dhcpleased"; 166 167 while ((ch = getopt(argc, argv, "dEFf:ns:v")) != -1) { 168 switch (ch) { 169 case 'd': 170 debug = 1; 171 break; 172 case 'E': 173 engine_flag = 1; 174 break; 175 case 'F': 176 frontend_flag = 1; 177 break; 178 case 'f': 179 conffile = optarg; 180 break; 181 case 'n': 182 no_action = 1; 183 break; 184 case 's': 185 csock = optarg; 186 break; 187 case 'v': 188 verbose++; 189 break; 190 default: 191 usage(); 192 } 193 } 194 195 argc -= optind; 196 argv += optind; 197 if (argc > 0 || (engine_flag && frontend_flag)) 198 usage(); 199 200 if (engine_flag) 201 engine(debug, verbose); 202 else if (frontend_flag) 203 frontend(debug, verbose); 204 205 #ifndef SMALL 206 /* parse config file */ 207 if ((main_conf = parse_config(conffile)) == NULL) 208 exit(1); 209 210 if (no_action) { 211 if (verbose) 212 print_config(main_conf); 213 else 214 fprintf(stderr, "configuration OK\n"); 215 exit(0); 216 } 217 #endif /* SMALL */ 218 219 /* Check for root privileges. */ 220 if (geteuid()) 221 errx(1, "need root privileges"); 222 223 lockfd = open(_PATH_LOCKFILE, O_CREAT|O_RDWR|O_EXLOCK|O_NONBLOCK, 0600); 224 if (lockfd == -1) { 225 if (errno == EAGAIN) 226 errx(1, "already running"); 227 err(1, "%s", _PATH_LOCKFILE); 228 } 229 230 /* Check for assigned daemon user */ 231 if (getpwnam(DHCPLEASED_USER) == NULL) 232 errx(1, "unknown user %s", DHCPLEASED_USER); 233 234 log_init(debug, LOG_DAEMON); 235 log_setverbose(verbose); 236 237 if (!debug) 238 daemon(0, 0); 239 240 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 241 PF_UNSPEC, pipe_main2frontend) == -1) 242 fatal("main2frontend socketpair"); 243 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 244 PF_UNSPEC, pipe_main2engine) == -1) 245 fatal("main2engine socketpair"); 246 247 /* Start children. */ 248 engine_pid = start_child(PROC_ENGINE, saved_argv0, pipe_main2engine[1], 249 debug, verbose); 250 frontend_pid = start_child(PROC_FRONTEND, saved_argv0, 251 pipe_main2frontend[1], debug, verbose); 252 253 log_procinit("main"); 254 255 if ((routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC | 256 SOCK_NONBLOCK, AF_INET)) == -1) 257 fatal("route socket"); 258 shutdown(routesock, SHUT_RD); 259 260 event_init(); 261 262 /* Setup signal handler. */ 263 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); 264 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); 265 signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); 266 signal_add(&ev_sigint, NULL); 267 signal_add(&ev_sigterm, NULL); 268 signal_add(&ev_sighup, NULL); 269 signal(SIGPIPE, SIG_IGN); 270 271 /* Setup pipes to children. */ 272 273 if ((iev_frontend = malloc(sizeof(struct imsgev))) == NULL || 274 (iev_engine = malloc(sizeof(struct imsgev))) == NULL) 275 fatal(NULL); 276 if (imsgbuf_init(&iev_frontend->ibuf, pipe_main2frontend[0]) == -1) 277 fatal(NULL); 278 imsgbuf_allow_fdpass(&iev_frontend->ibuf); 279 iev_frontend->handler = main_dispatch_frontend; 280 if (imsgbuf_init(&iev_engine->ibuf, pipe_main2engine[0]) == -1) 281 fatal(NULL); 282 imsgbuf_allow_fdpass(&iev_engine->ibuf); 283 iev_engine->handler = main_dispatch_engine; 284 285 /* Setup event handlers for pipes to engine & frontend. */ 286 iev_frontend->events = EV_READ; 287 event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 288 iev_frontend->events, iev_frontend->handler, iev_frontend); 289 event_add(&iev_frontend->ev, NULL); 290 291 iev_engine->events = EV_READ; 292 event_set(&iev_engine->ev, iev_engine->ibuf.fd, iev_engine->events, 293 iev_engine->handler, iev_engine); 294 event_add(&iev_engine->ev, NULL); 295 296 if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf)) 297 fatal("could not establish imsg links"); 298 299 if ((ioctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1) 300 fatal("socket"); 301 302 if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, 303 AF_INET)) == -1) 304 fatal("route socket"); 305 306 rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_PROPOSAL) | 307 ROUTE_FILTER(RTM_IFANNOUNCE); 308 if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, 309 &rtfilter, sizeof(rtfilter)) == -1) 310 fatal("setsockopt(ROUTE_MSGFILTER)"); 311 if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_TABLEFILTER, 312 &rtable_any, sizeof(rtable_any)) == -1) 313 fatal("setsockopt(ROUTE_TABLEFILTER)"); 314 315 #ifndef SMALL 316 if ((control_fd = control_init(csock)) == -1) 317 warnx("control socket setup failed"); 318 #endif /* SMALL */ 319 320 if (unveil(conffile, "r") == -1) 321 fatal("unveil %s", conffile); 322 if (unveil("/dev/bpf", "rw") == -1) 323 fatal("unveil /dev/bpf"); 324 325 if (unveil(_PATH_LEASE, "rwc") == -1) { 326 no_lease_files = 1; 327 log_warn("disabling lease files, unveil " _PATH_LEASE); 328 } 329 330 if (unveil(NULL, NULL) == -1) 331 fatal("unveil"); 332 #if notyet 333 if (pledge("stdio inet rpath wpath sendfd wroute bpf", NULL) == -1) 334 fatal("pledge"); 335 #endif 336 main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, NULL, 0); 337 338 #ifndef SMALL 339 if (control_fd != -1) 340 main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL, 0); 341 main_imsg_send_config(main_conf); 342 #endif /* SMALL */ 343 344 main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL, 0); 345 346 event_dispatch(); 347 348 main_shutdown(); 349 return (0); 350 } 351 352 __dead void 353 main_shutdown(void) 354 { 355 pid_t pid; 356 int status; 357 358 /* Close pipes. */ 359 imsgbuf_clear(&iev_frontend->ibuf); 360 close(iev_frontend->ibuf.fd); 361 imsgbuf_clear(&iev_engine->ibuf); 362 close(iev_engine->ibuf.fd); 363 364 #ifndef SMALL 365 config_clear(main_conf); 366 #endif /* SMALL */ 367 368 log_debug("waiting for children to terminate"); 369 do { 370 pid = wait(&status); 371 if (pid == -1) { 372 if (errno != EINTR && errno != ECHILD) 373 fatal("wait"); 374 } else if (WIFSIGNALED(status)) 375 log_warnx("%s terminated; signal %d", 376 (pid == engine_pid) ? "engine" : 377 "frontend", WTERMSIG(status)); 378 } while (pid != -1 || (pid == -1 && errno == EINTR)); 379 380 free(iev_frontend); 381 free(iev_engine); 382 383 log_info("terminating"); 384 exit(0); 385 } 386 387 static pid_t 388 start_child(enum dhcpleased_process p, char *argv0, int fd, int debug, int 389 verbose) 390 { 391 char *argv[7]; 392 int argc = 0; 393 pid_t pid; 394 395 switch (pid = fork()) { 396 case -1: 397 fatal("cannot fork"); 398 case 0: 399 break; 400 default: 401 close(fd); 402 return (pid); 403 } 404 405 if (fd != 3) { 406 if (dup2(fd, 3) == -1) 407 fatal("cannot setup imsg fd"); 408 } else if (fcntl(fd, F_SETFD, 0) == -1) 409 fatal("cannot setup imsg fd"); 410 411 argv[argc++] = argv0; 412 switch (p) { 413 case PROC_MAIN: 414 fatalx("Can not start main process"); 415 case PROC_ENGINE: 416 argv[argc++] = "-E"; 417 break; 418 case PROC_FRONTEND: 419 argv[argc++] = "-F"; 420 break; 421 } 422 if (debug) 423 argv[argc++] = "-d"; 424 if (verbose) 425 argv[argc++] = "-v"; 426 if (verbose > 1) 427 argv[argc++] = "-v"; 428 argv[argc++] = NULL; 429 430 execvp(argv0, argv); 431 fatal("execvp"); 432 } 433 434 void 435 main_dispatch_frontend(int fd, short event, void *bula) 436 { 437 struct imsgev *iev = bula; 438 struct imsgbuf *ibuf; 439 struct imsg imsg; 440 struct imsg_ifinfo imsg_ifinfo; 441 ssize_t n; 442 int shut = 0; 443 uint32_t if_index, type; 444 #ifndef SMALL 445 int verbose; 446 #endif /* SMALL */ 447 448 ibuf = &iev->ibuf; 449 450 if (event & EV_READ) { 451 if ((n = imsgbuf_read(ibuf)) == -1) 452 fatal("imsgbuf_read error"); 453 if (n == 0) /* Connection closed. */ 454 shut = 1; 455 } 456 if (event & EV_WRITE) { 457 if (imsgbuf_write(ibuf) == -1) { 458 if (errno == EPIPE) /* Connection closed. */ 459 shut = 1; 460 else 461 fatal("imsgbuf_write"); 462 } 463 } 464 465 for (;;) { 466 if ((n = imsg_get(ibuf, &imsg)) == -1) 467 fatal("imsg_get"); 468 if (n == 0) /* No more messages. */ 469 break; 470 471 type = imsg_get_type(&imsg); 472 473 switch (type) { 474 case IMSG_OPEN_BPFSOCK: 475 if (imsg_get_data(&imsg, &if_index, 476 sizeof(if_index)) == -1) 477 fatalx("%s: invalid %s", __func__, i2s(type)); 478 479 open_bpfsock(if_index); 480 break; 481 #ifndef SMALL 482 case IMSG_CTL_RELOAD: 483 if (main_reload() == -1) 484 log_warnx("configuration reload failed"); 485 else 486 log_warnx("configuration reloaded"); 487 break; 488 case IMSG_CTL_LOG_VERBOSE: 489 if (imsg_get_data(&imsg, &verbose, 490 sizeof(verbose)) == -1) 491 fatalx("%s: invalid %s", __func__, i2s(type)); 492 493 log_setverbose(verbose); 494 break; 495 #endif /* SMALL */ 496 case IMSG_UPDATE_IF: 497 if (imsg_get_data(&imsg, &imsg_ifinfo, 498 sizeof(imsg_ifinfo)) == -1) 499 fatalx("%s: invalid %s", __func__, i2s(type)); 500 501 read_lease_file(&imsg_ifinfo); 502 main_imsg_compose_engine(IMSG_UPDATE_IF, -1, 503 &imsg_ifinfo, sizeof(imsg_ifinfo)); 504 break; 505 default: 506 log_debug("%s: error handling imsg %d", __func__, type); 507 break; 508 } 509 imsg_free(&imsg); 510 } 511 if (!shut) 512 imsg_event_add(iev); 513 else { 514 /* This pipe is dead. Remove its event handler */ 515 event_del(&iev->ev); 516 event_loopexit(NULL); 517 } 518 } 519 520 void 521 main_dispatch_engine(int fd, short event, void *bula) 522 { 523 struct imsgev *iev = bula; 524 struct imsgbuf *ibuf; 525 struct imsg imsg; 526 ssize_t n; 527 uint32_t type; 528 int shut = 0; 529 530 ibuf = &iev->ibuf; 531 532 if (event & EV_READ) { 533 if ((n = imsgbuf_read(ibuf)) == -1) 534 fatal("imsgbuf_read error"); 535 if (n == 0) /* Connection closed. */ 536 shut = 1; 537 } 538 if (event & EV_WRITE) { 539 if (imsgbuf_write(ibuf) == -1) { 540 if (errno == EPIPE) /* Connection closed. */ 541 shut = 1; 542 else 543 fatal("imsgbuf_write"); 544 } 545 } 546 547 for (;;) { 548 if ((n = imsg_get(ibuf, &imsg)) == -1) 549 fatal("imsg_get"); 550 if (n == 0) /* No more messages. */ 551 break; 552 553 type = imsg_get_type(&imsg); 554 555 switch (type) { 556 case IMSG_CONFIGURE_INTERFACE: { 557 struct imsg_configure_interface imsg_interface; 558 559 if (imsg_get_data(&imsg, &imsg_interface, 560 sizeof(imsg_interface)) == -1) 561 fatalx("%s: invalid %s", __func__, i2s(type)); 562 563 if (imsg_interface.routes_len >= MAX_DHCP_ROUTES) 564 fatalx("%s: too many routes in imsg", __func__); 565 configure_interface(&imsg_interface); 566 break; 567 } 568 case IMSG_DECONFIGURE_INTERFACE: { 569 struct imsg_configure_interface imsg_interface; 570 571 if (imsg_get_data(&imsg, &imsg_interface, 572 sizeof(imsg_interface)) == -1) 573 fatalx("%s: invalid %s", __func__, i2s(type)); 574 if (imsg_interface.routes_len >= MAX_DHCP_ROUTES) 575 fatalx("%s: too many routes in imsg", __func__); 576 577 deconfigure_interface(&imsg_interface); 578 main_imsg_compose_frontend(IMSG_CLOSE_UDPSOCK, -1, 579 &imsg_interface.if_index, 580 sizeof(imsg_interface.if_index)); 581 break; 582 } 583 case IMSG_WITHDRAW_ROUTES: { 584 struct imsg_configure_interface imsg_interface; 585 586 if (imsg_get_data(&imsg, &imsg_interface, 587 sizeof(imsg_interface)) == -1) 588 fatalx("%s: invalid %s", __func__, i2s(type)); 589 if (imsg_interface.routes_len >= MAX_DHCP_ROUTES) 590 fatalx("%s: too many routes in imsg", __func__); 591 592 if (imsg_interface.routes_len > 0) 593 configure_routes(RTM_DELETE, &imsg_interface); 594 break; 595 } 596 case IMSG_PROPOSE_RDNS: { 597 struct imsg_propose_rdns rdns; 598 599 if (imsg_get_data(&imsg, &rdns, sizeof(rdns)) == -1) 600 fatalx("%s: invalid %s", __func__, i2s(type)); 601 if ((2 + rdns.rdns_count * sizeof(struct in_addr)) > 602 sizeof(struct sockaddr_rtdns)) 603 fatalx("%s: rdns_count too big: %d", __func__, 604 rdns.rdns_count); 605 606 propose_rdns(&rdns); 607 break; 608 } 609 case IMSG_WITHDRAW_RDNS: { 610 struct imsg_propose_rdns rdns; 611 612 if (imsg_get_data(&imsg, &rdns, sizeof(rdns)) == -1) 613 fatalx("%s: invalid %s", __func__, i2s(type)); 614 if (rdns.rdns_count != 0) 615 fatalx("%s: expected rdns_count == 0: %d", 616 __func__, rdns.rdns_count); 617 618 propose_rdns(&rdns); 619 break; 620 } 621 default: 622 log_debug("%s: error handling imsg %d", __func__, type); 623 break; 624 } 625 imsg_free(&imsg); 626 } 627 if (!shut) 628 imsg_event_add(iev); 629 else { 630 /* This pipe is dead. Remove its event handler. */ 631 event_del(&iev->ev); 632 event_loopexit(NULL); 633 } 634 } 635 636 int 637 main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen) 638 { 639 if (iev_frontend) 640 return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data, 641 datalen)); 642 else 643 return (-1); 644 } 645 646 int 647 main_imsg_compose_engine(int type, int fd, void *data, uint16_t datalen) 648 { 649 if (iev_engine) 650 return(imsg_compose_event(iev_engine, type, 0, 0, fd, data, 651 datalen)); 652 else 653 return (-1); 654 } 655 656 void 657 imsg_event_add(struct imsgev *iev) 658 { 659 iev->events = EV_READ; 660 if (imsgbuf_queuelen(&iev->ibuf) > 0) 661 iev->events |= EV_WRITE; 662 663 event_del(&iev->ev); 664 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); 665 event_add(&iev->ev, NULL); 666 } 667 668 int 669 imsg_compose_event(struct imsgev *iev, uint16_t type, uint32_t peerid, 670 pid_t pid, int fd, void *data, uint16_t datalen) 671 { 672 int ret; 673 674 if ((ret = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, 675 datalen)) != -1) 676 imsg_event_add(iev); 677 678 return (ret); 679 } 680 681 int 682 imsg_forward_event(struct imsgev *iev, struct imsg *imsg) 683 { 684 int ret; 685 686 if ((ret = imsg_forward(&iev->ibuf, imsg)) != -1) 687 imsg_event_add(iev); 688 689 return (ret); 690 } 691 692 static int 693 main_imsg_send_ipc_sockets(struct imsgbuf *frontend_buf, 694 struct imsgbuf *engine_buf) 695 { 696 int pipe_frontend2engine[2]; 697 698 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 699 PF_UNSPEC, pipe_frontend2engine) == -1) 700 return (-1); 701 702 if (imsg_compose(frontend_buf, IMSG_SOCKET_IPC, 0, 0, 703 pipe_frontend2engine[0], NULL, 0) == -1) 704 return (-1); 705 imsgbuf_flush(frontend_buf); 706 if (imsg_compose(engine_buf, IMSG_SOCKET_IPC, 0, 0, 707 pipe_frontend2engine[1], NULL, 0) == -1) 708 return (-1); 709 imsgbuf_flush(engine_buf); 710 return (0); 711 } 712 713 #ifndef SMALL 714 int 715 main_reload(void) 716 { 717 struct dhcpleased_conf *xconf; 718 719 if ((xconf = parse_config(conffile)) == NULL) 720 return (-1); 721 722 if (main_imsg_send_config(xconf) == -1) 723 return (-1); 724 725 merge_config(main_conf, xconf); 726 727 return (0); 728 } 729 730 int 731 main_imsg_send_config(struct dhcpleased_conf *xconf) 732 { 733 struct iface_conf *iface_conf; 734 735 main_imsg_compose_frontend(IMSG_RECONF_CONF, -1, NULL, 0); 736 main_imsg_compose_engine(IMSG_RECONF_CONF, -1, NULL, 0); 737 738 /* Send the interface list to the frontend & engine. */ 739 SIMPLEQ_FOREACH(iface_conf, &xconf->iface_list, entry) { 740 main_imsg_compose_frontend(IMSG_RECONF_IFACE, -1, iface_conf, 741 sizeof(*iface_conf)); 742 main_imsg_compose_engine(IMSG_RECONF_IFACE, -1, iface_conf, 743 sizeof(*iface_conf)); 744 if (iface_conf->vc_id_len) { 745 main_imsg_compose_frontend(IMSG_RECONF_VC_ID, -1, 746 iface_conf->vc_id, iface_conf->vc_id_len); 747 main_imsg_compose_engine(IMSG_RECONF_VC_ID, -1, 748 iface_conf->vc_id, iface_conf->vc_id_len); 749 } 750 if (iface_conf->c_id_len) { 751 main_imsg_compose_frontend(IMSG_RECONF_C_ID, -1, 752 iface_conf->c_id, iface_conf->c_id_len); 753 main_imsg_compose_engine(IMSG_RECONF_C_ID, -1, 754 iface_conf->c_id, iface_conf->c_id_len); 755 } 756 if (iface_conf->h_name != NULL) 757 main_imsg_compose_frontend(IMSG_RECONF_H_NAME, -1, 758 iface_conf->h_name, strlen(iface_conf->h_name) + 1); 759 } 760 761 /* Config is now complete. */ 762 main_imsg_compose_frontend(IMSG_RECONF_END, -1, NULL, 0); 763 main_imsg_compose_engine(IMSG_RECONF_END, -1, NULL, 0); 764 765 return (0); 766 } 767 #endif /* SMALL */ 768 769 void 770 configure_interface(struct imsg_configure_interface *imsg) 771 { 772 struct ifaliasreq ifaliasreq; 773 struct ifaddrs *ifap, *ifa; 774 struct sockaddr_in *req_sin_addr, *req_sin_mask; 775 int found = 0, udpsock, opt = 1, len, fd = -1; 776 char *if_name; 777 char ip_ntop_buf[INET_ADDRSTRLEN]; 778 char nextserver_ntop_buf[INET_ADDRSTRLEN]; 779 char lease_buf[LEASE_SIZE]; 780 char lease_file_buf[sizeof(_PATH_LEASE) + 781 IF_NAMESIZE]; 782 char tmpl[] = _PATH_LEASE"XXXXXXXXXX"; 783 784 memset(&ifaliasreq, 0, sizeof(ifaliasreq)); 785 786 if_name = if_indextoname(imsg->if_index, ifaliasreq.ifra_name); 787 if (if_name == NULL) { 788 log_warnx("%s: cannot find interface %d", __func__, 789 imsg->if_index); 790 return; 791 } 792 793 log_debug("%s %s", __func__, if_name); 794 795 if (getifaddrs(&ifap) != 0) 796 fatal("getifaddrs"); 797 798 req_sin_addr = (struct sockaddr_in *)&ifaliasreq.ifra_addr; 799 req_sin_addr->sin_family = AF_INET; 800 req_sin_addr->sin_len = sizeof(*req_sin_addr); 801 802 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 803 struct in_addr addr, mask; 804 805 if (strcmp(if_name, ifa->ifa_name) != 0) 806 continue; 807 if (ifa->ifa_addr == NULL) 808 continue; 809 if (ifa->ifa_addr->sa_family != AF_INET) 810 continue; 811 812 addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; 813 mask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr; 814 815 if (imsg->addr.s_addr == addr.s_addr) { 816 if (imsg->mask.s_addr == mask.s_addr) 817 found = 1; 818 else { 819 req_sin_addr->sin_addr = addr; 820 if (ioctl(ioctl_sock, SIOCDIFADDR, &ifaliasreq) 821 == -1) { 822 if (errno != EADDRNOTAVAIL) 823 log_warn("SIOCDIFADDR"); 824 } 825 } 826 break; 827 } 828 } 829 freeifaddrs(ifap); 830 831 req_sin_addr->sin_addr = imsg->addr; 832 if (!found) { 833 req_sin_mask = (struct sockaddr_in *)&ifaliasreq.ifra_mask; 834 req_sin_mask->sin_family = AF_INET; 835 req_sin_mask->sin_len = sizeof(*req_sin_mask); 836 req_sin_mask->sin_addr = imsg->mask; 837 if (ioctl(ioctl_sock, SIOCAIFADDR, &ifaliasreq) == -1) 838 log_warn("SIOCAIFADDR"); 839 } 840 if (imsg->routes_len > 0) 841 configure_routes(RTM_ADD, imsg); 842 843 req_sin_addr->sin_port = ntohs(CLIENT_PORT); 844 if ((udpsock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 845 log_warn("socket"); 846 return; 847 } 848 if (setsockopt(udpsock, SOL_SOCKET, SO_REUSEADDR, &opt, 849 sizeof(opt)) == -1) 850 log_warn("setting SO_REUSEADDR on socket"); 851 852 if (setsockopt(udpsock, SOL_SOCKET, SO_RTABLE, &imsg->rdomain, 853 sizeof(imsg->rdomain)) == -1) { 854 /* we might race against removal of the rdomain */ 855 log_warn("setsockopt SO_RTABLE"); 856 close(udpsock); 857 return; 858 } 859 860 if (bind(udpsock, (struct sockaddr *)req_sin_addr, 861 sizeof(*req_sin_addr)) == -1) { 862 close(udpsock); 863 return; 864 } 865 866 shutdown(udpsock, SHUT_RD); 867 868 main_imsg_compose_frontend(IMSG_UDPSOCK, udpsock, 869 &imsg->if_index, sizeof(imsg->if_index)); 870 871 if (no_lease_files) 872 return; 873 874 if (inet_ntop(AF_INET, &imsg->addr, ip_ntop_buf, sizeof(ip_ntop_buf)) == 875 NULL) { 876 log_warn("%s: inet_ntop", __func__); 877 return; 878 } 879 880 if (imsg->siaddr.s_addr == INADDR_ANY) 881 nextserver_ntop_buf[0] = '\0'; 882 else { 883 if (inet_ntop(AF_INET, &imsg->siaddr, nextserver_ntop_buf, 884 sizeof(nextserver_ntop_buf)) == NULL) { 885 log_warn("%s: inet_ntop", __func__); 886 return; 887 } 888 } 889 len = snprintf(lease_file_buf, sizeof(lease_file_buf), "%s%s", 890 _PATH_LEASE, if_name); 891 if ( len == -1 || (size_t) len >= sizeof(lease_file_buf)) { 892 log_warnx("%s: failed to encode lease path for %s", __func__, 893 if_name); 894 return; 895 } 896 897 len = snprintf(lease_buf, sizeof(lease_buf), 898 "%s\n%s%s\n%s%s\n%s%s\n%s%s\n%s%s\n", 899 LEASE_VERSION, LEASE_IP_PREFIX, ip_ntop_buf, 900 LEASE_NEXTSERVER_PREFIX, nextserver_ntop_buf, LEASE_BOOTFILE_PREFIX, 901 imsg->file, LEASE_HOSTNAME_PREFIX, imsg->hostname, 902 LEASE_DOMAIN_PREFIX, imsg->domainname); 903 if ( len == -1 || (size_t) len >= sizeof(lease_buf)) { 904 log_warnx("%s: failed to encode lease for %s", __func__, 905 ip_ntop_buf); 906 return; 907 } 908 909 if ((fd = mkstemp(tmpl)) == -1) { 910 log_warn("%s: mkstemp", __func__); 911 return; 912 } 913 914 if (write(fd, lease_buf, len) < len) 915 goto err; 916 917 if (fchmod(fd, 0644) == -1) 918 goto err; 919 920 if (close(fd) == -1) 921 goto err; 922 fd = -1; 923 924 if (rename(tmpl, lease_file_buf) == -1) 925 goto err; 926 return; 927 err: 928 log_warn("%s", __func__); 929 if (fd != -1) 930 close(fd); 931 unlink(tmpl); 932 } 933 934 void 935 deconfigure_interface(struct imsg_configure_interface *imsg) 936 { 937 struct ifaliasreq ifaliasreq; 938 struct sockaddr_in *req_sin_addr; 939 940 memset(&ifaliasreq, 0, sizeof(ifaliasreq)); 941 942 #if 0 943 /* 944 * When two default routes have the same gateway the kernel always 945 * deletes the first which might be the wrong one. When we then 946 * deconfigure the IP address from the interface the kernel deletes 947 * all routes pointing out that interface and we end up with no 948 * default. 949 * This can happen with a wired & wireless interface on the same 950 * layer 2 network and the user issues ifconfig $WIFI inet -autoconf. 951 * Work around this issue by not deleting the default route and let 952 * the kernel handle it when we remove the IP address a few lines 953 * down. 954 */ 955 if (imsg->routes_len > 0) 956 configure_routes(RTM_DELETE, imsg); 957 #endif 958 959 if (if_indextoname(imsg->if_index, ifaliasreq.ifra_name) == NULL) { 960 log_warnx("%s: cannot find interface %d", __func__, 961 imsg->if_index); 962 return; 963 } 964 965 log_debug("%s %s", __func__, ifaliasreq.ifra_name); 966 967 req_sin_addr = (struct sockaddr_in *)&ifaliasreq.ifra_addr; 968 req_sin_addr->sin_family = AF_INET; 969 req_sin_addr->sin_len = sizeof(*req_sin_addr); 970 971 req_sin_addr->sin_addr = imsg->addr; 972 if (ioctl(ioctl_sock, SIOCDIFADDR, &ifaliasreq) == -1) { 973 if (errno != EADDRNOTAVAIL) 974 log_warn("SIOCDIFADDR"); 975 } 976 } 977 978 void 979 configure_routes(uint8_t rtm_type, struct imsg_configure_interface *imsg) 980 { 981 struct sockaddr_in dst, mask, gw, ifa; 982 in_addr_t addrnet, gwnet; 983 int i; 984 985 memset(&ifa, 0, sizeof(ifa)); 986 ifa.sin_family = AF_INET; 987 ifa.sin_len = sizeof(ifa); 988 ifa.sin_addr = imsg->addr; 989 990 memset(&dst, 0, sizeof(dst)); 991 dst.sin_family = AF_INET; 992 dst.sin_len = sizeof(dst); 993 994 memset(&mask, 0, sizeof(mask)); 995 mask.sin_family = AF_INET; 996 mask.sin_len = sizeof(mask); 997 998 memset(&gw, 0, sizeof(gw)); 999 gw.sin_family = AF_INET; 1000 gw.sin_len = sizeof(gw); 1001 1002 addrnet = imsg->addr.s_addr & imsg->mask.s_addr; 1003 1004 for (i = 0; i < imsg->routes_len; i++) { 1005 dst.sin_addr = imsg->routes[i].dst; 1006 mask.sin_addr = imsg->routes[i].mask; 1007 gw.sin_addr = imsg->routes[i].gw; 1008 1009 if (gw.sin_addr.s_addr == INADDR_ANY) { 1010 /* direct route */ 1011 configure_route(rtm_type, imsg->if_index, 1012 imsg->rdomain, &dst, &mask, &ifa, NULL, 1013 RTF_CLONING); 1014 } else if (mask.sin_addr.s_addr == INADDR_ANY) { 1015 /* default route */ 1016 gwnet = gw.sin_addr.s_addr & imsg->mask.s_addr; 1017 if (addrnet != gwnet) { 1018 /* 1019 * The gateway for the default route is outside 1020 * the configured prefix. Install a direct 1021 * cloning route for the gateway to make the 1022 * default route reachable. 1023 */ 1024 mask.sin_addr.s_addr = 0xffffffff; 1025 configure_route(rtm_type, imsg->if_index, 1026 imsg->rdomain, &gw, &mask, &ifa, NULL, 1027 RTF_CLONING); 1028 mask.sin_addr = imsg->routes[i].mask; 1029 } 1030 1031 if (gw.sin_addr.s_addr == ifa.sin_addr.s_addr) { 1032 /* directly connected default */ 1033 configure_route(rtm_type, imsg->if_index, 1034 imsg->rdomain, &dst, &mask, &gw, NULL, 0); 1035 } else { 1036 /* default route via gateway */ 1037 configure_route(rtm_type, imsg->if_index, 1038 imsg->rdomain, &dst, &mask, &gw, &ifa, 1039 RTF_GATEWAY); 1040 } 1041 } else { 1042 /* non-default via gateway */ 1043 configure_route(rtm_type, imsg->if_index, imsg->rdomain, 1044 &dst, &mask, &gw, NULL, RTF_GATEWAY); 1045 } 1046 } 1047 } 1048 1049 #define ROUNDUP(a) \ 1050 (((a) & (sizeof(long) - 1)) ? (1 + ((a) | (sizeof(long) - 1))) : (a)) 1051 void 1052 configure_route(uint8_t rtm_type, uint32_t if_index, int rdomain, struct 1053 sockaddr_in *dst, struct sockaddr_in *mask, struct sockaddr_in *gw, 1054 struct sockaddr_in *ifa, int rtm_flags) 1055 { 1056 struct rt_msghdr rtm; 1057 struct sockaddr_dl ifp; 1058 struct sockaddr_rtlabel rl; 1059 struct iovec iov[14]; 1060 long pad = 0; 1061 int iovcnt = 0, padlen; 1062 1063 memset(&rtm, 0, sizeof(rtm)); 1064 1065 rtm.rtm_version = RTM_VERSION; 1066 rtm.rtm_type = rtm_type; 1067 rtm.rtm_msglen = sizeof(rtm); 1068 rtm.rtm_index = if_index; 1069 rtm.rtm_tableid = rdomain; 1070 rtm.rtm_seq = ++rtm_seq; 1071 rtm.rtm_priority = RTP_NONE; 1072 rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP | 1073 RTA_LABEL; 1074 rtm.rtm_flags = RTF_UP | RTF_STATIC | RTF_MPATH | rtm_flags; 1075 1076 if (ifa) 1077 rtm.rtm_addrs |= RTA_IFA; 1078 1079 iov[iovcnt].iov_base = &rtm; 1080 iov[iovcnt++].iov_len = sizeof(rtm); 1081 1082 iov[iovcnt].iov_base = dst; 1083 iov[iovcnt++].iov_len = dst->sin_len; 1084 rtm.rtm_msglen += dst->sin_len; 1085 padlen = ROUNDUP(dst->sin_len) - dst->sin_len; 1086 if (padlen > 0) { 1087 iov[iovcnt].iov_base = &pad; 1088 iov[iovcnt++].iov_len = padlen; 1089 rtm.rtm_msglen += padlen; 1090 } 1091 1092 iov[iovcnt].iov_base = gw; 1093 iov[iovcnt++].iov_len = gw->sin_len; 1094 rtm.rtm_msglen += gw->sin_len; 1095 padlen = ROUNDUP(gw->sin_len) - gw->sin_len; 1096 if (padlen > 0) { 1097 iov[iovcnt].iov_base = &pad; 1098 iov[iovcnt++].iov_len = padlen; 1099 rtm.rtm_msglen += padlen; 1100 } 1101 1102 iov[iovcnt].iov_base = mask; 1103 iov[iovcnt++].iov_len = mask->sin_len; 1104 rtm.rtm_msglen += mask->sin_len; 1105 padlen = ROUNDUP(mask->sin_len) - mask->sin_len; 1106 if (padlen > 0) { 1107 iov[iovcnt].iov_base = &pad; 1108 iov[iovcnt++].iov_len = padlen; 1109 rtm.rtm_msglen += padlen; 1110 } 1111 1112 memset(&ifp, 0, sizeof(ifp)); 1113 ifp.sdl_len = sizeof(struct sockaddr_dl); 1114 ifp.sdl_family = AF_LINK; 1115 ifp.sdl_index = if_index; 1116 iov[iovcnt].iov_base = &ifp; 1117 iov[iovcnt++].iov_len = sizeof(ifp); 1118 rtm.rtm_msglen += sizeof(ifp); 1119 padlen = ROUNDUP(sizeof(ifp)) - sizeof(ifp); 1120 if (padlen > 0) { 1121 iov[iovcnt].iov_base = &pad; 1122 iov[iovcnt++].iov_len = padlen; 1123 rtm.rtm_msglen += padlen; 1124 } 1125 1126 if (ifa) { 1127 iov[iovcnt].iov_base = ifa; 1128 iov[iovcnt++].iov_len = ifa->sin_len; 1129 rtm.rtm_msglen += ifa->sin_len; 1130 padlen = ROUNDUP(ifa->sin_len) - ifa->sin_len; 1131 if (padlen > 0) { 1132 iov[iovcnt].iov_base = &pad; 1133 iov[iovcnt++].iov_len = padlen; 1134 rtm.rtm_msglen += padlen; 1135 } 1136 } 1137 1138 memset(&rl, 0, sizeof(rl)); 1139 rl.sr_len = sizeof(rl); 1140 rl.sr_family = AF_UNSPEC; 1141 (void)snprintf(rl.sr_label, sizeof(rl.sr_label), "%s", 1142 DHCPLEASED_RTA_LABEL); 1143 iov[iovcnt].iov_base = &rl; 1144 iov[iovcnt++].iov_len = sizeof(rl); 1145 rtm.rtm_msglen += sizeof(rl); 1146 padlen = ROUNDUP(sizeof(rl)) - sizeof(rl); 1147 if (padlen > 0) { 1148 iov[iovcnt].iov_base = &pad; 1149 iov[iovcnt++].iov_len = padlen; 1150 rtm.rtm_msglen += padlen; 1151 } 1152 1153 if (writev(routesock, iov, iovcnt) == -1) { 1154 if (errno != EEXIST) 1155 log_warn("failed to send route message"); 1156 } 1157 } 1158 1159 #ifndef SMALL 1160 const char* 1161 sin_to_str(struct sockaddr_in *sin) 1162 { 1163 static char hbuf[NI_MAXHOST]; 1164 int error; 1165 1166 error = getnameinfo((struct sockaddr *)sin, sin->sin_len, hbuf, 1167 sizeof(hbuf), NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); 1168 if (error) { 1169 log_warnx("%s", gai_strerror(error)); 1170 strlcpy(hbuf, "unknown", sizeof(hbuf)); 1171 } 1172 return hbuf; 1173 } 1174 #endif /* SMALL */ 1175 1176 void 1177 open_bpfsock(uint32_t if_index) 1178 { 1179 int bpfsock; 1180 char ifname[IF_NAMESIZE]; 1181 1182 if (if_indextoname(if_index, ifname) == NULL) { 1183 log_warnx("%s: cannot find interface %d", __func__, if_index); 1184 return; 1185 } 1186 1187 if ((bpfsock = get_bpf_sock(ifname)) == -1) 1188 return; 1189 1190 main_imsg_compose_frontend(IMSG_BPFSOCK, bpfsock, &if_index, 1191 sizeof(if_index)); 1192 } 1193 1194 void 1195 propose_rdns(struct imsg_propose_rdns *rdns) 1196 { 1197 struct rt_msghdr rtm; 1198 struct sockaddr_rtdns rtdns; 1199 struct iovec iov[3]; 1200 long pad = 0; 1201 int iovcnt = 0, padlen; 1202 1203 memset(&rtm, 0, sizeof(rtm)); 1204 1205 rtm.rtm_version = RTM_VERSION; 1206 rtm.rtm_type = RTM_PROPOSAL; 1207 rtm.rtm_msglen = sizeof(rtm); 1208 rtm.rtm_tableid = rdns->rdomain; 1209 rtm.rtm_index = rdns->if_index; 1210 rtm.rtm_seq = ++rtm_seq; 1211 rtm.rtm_priority = RTP_PROPOSAL_DHCLIENT; 1212 rtm.rtm_addrs = RTA_DNS; 1213 rtm.rtm_flags = RTF_UP; 1214 1215 iov[iovcnt].iov_base = &rtm; 1216 iov[iovcnt++].iov_len = sizeof(rtm); 1217 1218 memset(&rtdns, 0, sizeof(rtdns)); 1219 rtdns.sr_family = AF_INET; 1220 rtdns.sr_len = 2 + rdns->rdns_count * sizeof(struct in_addr); 1221 memcpy(rtdns.sr_dns, rdns->rdns, rtdns.sr_len - 2); 1222 1223 iov[iovcnt].iov_base = &rtdns; 1224 iov[iovcnt++].iov_len = sizeof(rtdns); 1225 rtm.rtm_msglen += sizeof(rtdns); 1226 padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns); 1227 if (padlen > 0) { 1228 iov[iovcnt].iov_base = &pad; 1229 iov[iovcnt++].iov_len = padlen; 1230 rtm.rtm_msglen += padlen; 1231 } 1232 1233 if (writev(routesock, iov, iovcnt) == -1) 1234 log_warn("failed to propose nameservers"); 1235 } 1236 1237 void 1238 read_lease_file(struct imsg_ifinfo *imsg_ifinfo) 1239 { 1240 int len, fd; 1241 char if_name[IF_NAMESIZE]; 1242 char lease_file_buf[sizeof(_PATH_LEASE) + IF_NAMESIZE]; 1243 1244 if (no_lease_files) 1245 return; 1246 1247 memset(imsg_ifinfo->lease, 0, sizeof(imsg_ifinfo->lease)); 1248 1249 if (if_indextoname(imsg_ifinfo->if_index, if_name) == NULL) { 1250 log_warnx("%s: cannot find interface %d", __func__, 1251 imsg_ifinfo->if_index); 1252 return; 1253 } 1254 1255 len = snprintf(lease_file_buf, sizeof(lease_file_buf), "%s%s", 1256 _PATH_LEASE, if_name); 1257 if ( len == -1 || (size_t) len >= sizeof(lease_file_buf)) { 1258 log_warnx("%s: failed to encode lease path for %s", __func__, 1259 if_name); 1260 return; 1261 } 1262 1263 if ((fd = open(lease_file_buf, O_RDONLY)) == -1) 1264 return; 1265 1266 /* no need for error handling, we'll just do a DHCP discover */ 1267 read(fd, imsg_ifinfo->lease, sizeof(imsg_ifinfo->lease) - 1); 1268 close(fd); 1269 } 1270 1271 #ifndef SMALL 1272 void 1273 merge_config(struct dhcpleased_conf *conf, struct dhcpleased_conf *xconf) 1274 { 1275 struct iface_conf *iface_conf; 1276 1277 /* Remove & discard existing interfaces. */ 1278 while ((iface_conf = SIMPLEQ_FIRST(&conf->iface_list)) != NULL) { 1279 SIMPLEQ_REMOVE_HEAD(&conf->iface_list, entry); 1280 free(iface_conf->vc_id); 1281 free(iface_conf->c_id); 1282 free(iface_conf->h_name); 1283 free(iface_conf); 1284 } 1285 1286 /* Add new interfaces. */ 1287 SIMPLEQ_CONCAT(&conf->iface_list, &xconf->iface_list); 1288 1289 free(xconf); 1290 } 1291 1292 struct dhcpleased_conf * 1293 config_new_empty(void) 1294 { 1295 struct dhcpleased_conf *xconf; 1296 1297 xconf = calloc(1, sizeof(*xconf)); 1298 if (xconf == NULL) 1299 fatal(NULL); 1300 1301 SIMPLEQ_INIT(&xconf->iface_list); 1302 1303 return (xconf); 1304 } 1305 1306 void 1307 config_clear(struct dhcpleased_conf *conf) 1308 { 1309 struct dhcpleased_conf *xconf; 1310 1311 /* Merge current config with an empty config. */ 1312 xconf = config_new_empty(); 1313 merge_config(conf, xconf); 1314 1315 free(conf); 1316 } 1317 1318 #define I2S(x) case x: return #x 1319 1320 const char* 1321 i2s(uint32_t type) 1322 { 1323 static char unknown[sizeof("IMSG_4294967295")]; 1324 1325 switch (type) { 1326 I2S(IMSG_NONE); 1327 I2S(IMSG_CTL_LOG_VERBOSE); 1328 I2S(IMSG_CTL_SHOW_INTERFACE_INFO); 1329 I2S(IMSG_CTL_SEND_REQUEST); 1330 I2S(IMSG_CTL_RELOAD); 1331 I2S(IMSG_CTL_END); 1332 I2S(IMSG_RECONF_CONF); 1333 I2S(IMSG_RECONF_IFACE); 1334 I2S(IMSG_RECONF_VC_ID); 1335 I2S(IMSG_RECONF_C_ID); 1336 I2S(IMSG_RECONF_H_NAME); 1337 I2S(IMSG_RECONF_END); 1338 I2S(IMSG_SEND_DISCOVER); 1339 I2S(IMSG_SEND_REQUEST); 1340 I2S(IMSG_SOCKET_IPC); 1341 I2S(IMSG_OPEN_BPFSOCK); 1342 I2S(IMSG_BPFSOCK); 1343 I2S(IMSG_UDPSOCK); 1344 I2S(IMSG_CLOSE_UDPSOCK); 1345 I2S(IMSG_ROUTESOCK); 1346 I2S(IMSG_CONTROLFD); 1347 I2S(IMSG_STARTUP); 1348 I2S(IMSG_UPDATE_IF); 1349 I2S(IMSG_REMOVE_IF); 1350 I2S(IMSG_DHCP); 1351 I2S(IMSG_CONFIGURE_INTERFACE); 1352 I2S(IMSG_DECONFIGURE_INTERFACE); 1353 I2S(IMSG_PROPOSE_RDNS); 1354 I2S(IMSG_WITHDRAW_RDNS); 1355 I2S(IMSG_WITHDRAW_ROUTES); 1356 I2S(IMSG_REPROPOSE_RDNS); 1357 I2S(IMSG_REQUEST_REBOOT); 1358 default: 1359 snprintf(unknown, sizeof(unknown), "IMSG_%u", type); 1360 return unknown; 1361 } 1362 } 1363 #undef I2S 1364 1365 #endif /* SMALL */ 1366