1 /* $OpenBSD: frontend.c,v 1.32 2023/12/14 09:58:37 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/syslog.h> 26 #include <sys/uio.h> 27 28 #include <net/bpf.h> 29 #include <net/if.h> 30 #include <net/if_dl.h> 31 #include <net/if_types.h> 32 #include <net/route.h> 33 34 #include <netinet/in.h> 35 #include <netinet/if_ether.h> 36 #include <netinet/ip.h> 37 #include <netinet/udp.h> 38 39 #include <arpa/inet.h> 40 41 #include <errno.h> 42 #include <event.h> 43 #include <ifaddrs.h> 44 #include <imsg.h> 45 #include <pwd.h> 46 #include <signal.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 52 #include "bpf.h" 53 #include "log.h" 54 #include "dhcpleased.h" 55 #include "frontend.h" 56 #include "control.h" 57 #include "checksum.h" 58 59 #define ROUTE_SOCKET_BUF_SIZE 16384 60 #define BOOTP_MIN_LEN 300 /* fixed bootp packet adds up to 300 */ 61 62 struct bpf_ev { 63 struct event ev; 64 uint8_t buf[BPFLEN]; 65 }; 66 67 struct iface { 68 LIST_ENTRY(iface) entries; 69 struct bpf_ev bpfev; 70 struct imsg_ifinfo ifinfo; 71 int send_discover; 72 uint32_t xid; 73 struct in_addr ciaddr; 74 struct in_addr requested_ip; 75 struct in_addr server_identifier; 76 struct in_addr dhcp_server; 77 int udpsock; 78 }; 79 80 __dead void frontend_shutdown(void); 81 void frontend_sig_handler(int, short, void *); 82 void update_iface(struct if_msghdr *, struct sockaddr_dl *); 83 void frontend_startup(void); 84 void init_ifaces(void); 85 void route_receive(int, short, void *); 86 void handle_route_message(struct rt_msghdr *, struct sockaddr **); 87 void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 88 void bpf_receive(int, short, void *); 89 int get_flags(char *); 90 int get_xflags(char *); 91 struct iface *get_iface_by_id(uint32_t); 92 void remove_iface(uint32_t); 93 void set_bpfsock(int, uint32_t); 94 void iface_data_from_imsg(struct iface*, struct imsg_req_dhcp *); 95 ssize_t build_packet(uint8_t, char *, uint32_t, struct ether_addr *, 96 struct in_addr *, struct in_addr *, struct in_addr *); 97 void send_packet(uint8_t, struct iface *); 98 void bpf_send_packet(struct iface *, uint8_t *, ssize_t); 99 int udp_send_packet(struct iface *, uint8_t *, ssize_t); 100 #ifndef SMALL 101 int iface_conf_cmp(struct iface_conf *, struct iface_conf *); 102 #endif /* SMALL */ 103 104 LIST_HEAD(, iface) interfaces; 105 struct dhcpleased_conf *frontend_conf; 106 static struct imsgev *iev_main; 107 static struct imsgev *iev_engine; 108 struct event ev_route; 109 int ioctlsock; 110 111 uint8_t dhcp_packet[1500]; 112 113 void 114 frontend_sig_handler(int sig, short event, void *bula) 115 { 116 /* 117 * Normal signal handler rules don't apply because libevent 118 * decouples for us. 119 */ 120 121 switch (sig) { 122 case SIGINT: 123 case SIGTERM: 124 frontend_shutdown(); 125 default: 126 fatalx("unexpected signal"); 127 } 128 } 129 130 void 131 frontend(int debug, int verbose) 132 { 133 struct event ev_sigint, ev_sigterm; 134 struct passwd *pw; 135 136 #ifndef SMALL 137 frontend_conf = config_new_empty(); 138 #endif /* SMALL */ 139 140 log_init(debug, LOG_DAEMON); 141 log_setverbose(verbose); 142 143 if ((pw = getpwnam(DHCPLEASED_USER)) == NULL) 144 fatal("getpwnam"); 145 146 if (chdir("/") == -1) 147 fatal("chdir(\"/\")"); 148 149 if (unveil("/", "") == -1) 150 fatal("unveil /"); 151 if (unveil(NULL, NULL) == -1) 152 fatal("unveil"); 153 154 setproctitle("%s", "frontend"); 155 log_procinit("frontend"); 156 157 if ((ioctlsock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1) 158 fatal("socket"); 159 160 if (setgroups(1, &pw->pw_gid) || 161 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 162 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 163 fatal("can't drop privileges"); 164 165 if (pledge("stdio unix recvfd route", NULL) == -1) 166 fatal("pledge"); 167 event_init(); 168 169 /* Setup signal handler. */ 170 signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL); 171 signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL); 172 signal_add(&ev_sigint, NULL); 173 signal_add(&ev_sigterm, NULL); 174 signal(SIGPIPE, SIG_IGN); 175 signal(SIGHUP, SIG_IGN); 176 177 /* Setup pipe and event handler to the parent process. */ 178 if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 179 fatal(NULL); 180 imsg_init(&iev_main->ibuf, 3); 181 iev_main->handler = frontend_dispatch_main; 182 iev_main->events = EV_READ; 183 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 184 iev_main->handler, iev_main); 185 event_add(&iev_main->ev, NULL); 186 187 LIST_INIT(&interfaces); 188 event_dispatch(); 189 190 frontend_shutdown(); 191 } 192 193 __dead void 194 frontend_shutdown(void) 195 { 196 /* Close pipes. */ 197 msgbuf_write(&iev_engine->ibuf.w); 198 msgbuf_clear(&iev_engine->ibuf.w); 199 close(iev_engine->ibuf.fd); 200 msgbuf_write(&iev_main->ibuf.w); 201 msgbuf_clear(&iev_main->ibuf.w); 202 close(iev_main->ibuf.fd); 203 204 #ifndef SMALL 205 config_clear(frontend_conf); 206 #endif /* SMALL */ 207 208 free(iev_engine); 209 free(iev_main); 210 211 log_info("frontend exiting"); 212 exit(0); 213 } 214 215 int 216 frontend_imsg_compose_main(int type, pid_t pid, void *data, 217 uint16_t datalen) 218 { 219 return (imsg_compose_event(iev_main, type, 0, pid, -1, data, 220 datalen)); 221 } 222 223 int 224 frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid, 225 void *data, uint16_t datalen) 226 { 227 return (imsg_compose_event(iev_engine, type, peerid, pid, -1, 228 data, datalen)); 229 } 230 231 void 232 frontend_dispatch_main(int fd, short event, void *bula) 233 { 234 static struct dhcpleased_conf *nconf; 235 static struct iface_conf *iface_conf; 236 struct imsg imsg; 237 struct imsgev *iev = bula; 238 struct imsgbuf *ibuf = &iev->ibuf; 239 struct iface *iface; 240 ssize_t n; 241 int shut = 0, bpfsock, if_index, udpsock; 242 243 if (event & EV_READ) { 244 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 245 fatal("imsg_read error"); 246 if (n == 0) /* Connection closed. */ 247 shut = 1; 248 } 249 if (event & EV_WRITE) { 250 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 251 fatal("msgbuf_write"); 252 if (n == 0) /* Connection closed. */ 253 shut = 1; 254 } 255 256 for (;;) { 257 if ((n = imsg_get(ibuf, &imsg)) == -1) 258 fatal("%s: imsg_get error", __func__); 259 if (n == 0) /* No more messages. */ 260 break; 261 262 switch (imsg.hdr.type) { 263 case IMSG_SOCKET_IPC: 264 /* 265 * Setup pipe and event handler to the engine 266 * process. 267 */ 268 if (iev_engine) 269 fatalx("%s: received unexpected imsg fd " 270 "to frontend", __func__); 271 272 if ((fd = imsg_get_fd(&imsg)) == -1) 273 fatalx("%s: expected to receive imsg fd to " 274 "frontend but didn't receive any", 275 __func__); 276 277 iev_engine = malloc(sizeof(struct imsgev)); 278 if (iev_engine == NULL) 279 fatal(NULL); 280 281 imsg_init(&iev_engine->ibuf, fd); 282 iev_engine->handler = frontend_dispatch_engine; 283 iev_engine->events = EV_READ; 284 285 event_set(&iev_engine->ev, iev_engine->ibuf.fd, 286 iev_engine->events, iev_engine->handler, iev_engine); 287 event_add(&iev_engine->ev, NULL); 288 break; 289 case IMSG_BPFSOCK: 290 if ((bpfsock = imsg_get_fd(&imsg)) == -1) 291 fatalx("%s: expected to receive imsg " 292 "bpf fd but didn't receive any", 293 __func__); 294 if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 295 fatalx("%s: IMSG_BPFSOCK wrong length: " 296 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 297 memcpy(&if_index, imsg.data, sizeof(if_index)); 298 set_bpfsock(bpfsock, if_index); 299 break; 300 case IMSG_UDPSOCK: 301 if ((udpsock = imsg_get_fd(&imsg)) == -1) 302 fatalx("%s: expected to receive imsg " 303 "udpsocket fd but didn't receive any", 304 __func__); 305 if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 306 fatalx("%s: IMSG_UDPSOCK wrong length: " 307 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 308 memcpy(&if_index, imsg.data, sizeof(if_index)); 309 if ((iface = get_iface_by_id(if_index)) == NULL) { 310 close(fd); 311 break; 312 } 313 if (iface->udpsock != -1) 314 fatalx("%s: received unexpected udpsocket", 315 __func__); 316 iface->udpsock = udpsock; 317 break; 318 case IMSG_CLOSE_UDPSOCK: 319 if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 320 fatalx("%s: IMSG_UDPSOCK wrong length: " 321 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 322 memcpy(&if_index, imsg.data, sizeof(if_index)); 323 if ((iface = get_iface_by_id(if_index)) != NULL && 324 iface->udpsock != -1) { 325 close(iface->udpsock); 326 iface->udpsock = -1; 327 } 328 break; 329 case IMSG_ROUTESOCK: 330 if ((fd = imsg_get_fd(&imsg)) == -1) 331 fatalx("%s: expected to receive imsg " 332 "routesocket fd but didn't receive any", 333 __func__); 334 event_set(&ev_route, fd, EV_READ | EV_PERSIST, 335 route_receive, NULL); 336 break; 337 case IMSG_STARTUP: 338 frontend_startup(); 339 break; 340 #ifndef SMALL 341 case IMSG_RECONF_CONF: 342 if (nconf != NULL) 343 fatalx("%s: IMSG_RECONF_CONF already in " 344 "progress", __func__); 345 if ((nconf = malloc(sizeof(struct dhcpleased_conf))) == 346 NULL) 347 fatal(NULL); 348 SIMPLEQ_INIT(&nconf->iface_list); 349 break; 350 case IMSG_RECONF_IFACE: 351 if (IMSG_DATA_SIZE(imsg) != sizeof(struct 352 iface_conf)) 353 fatalx("%s: IMSG_RECONF_IFACE wrong length: " 354 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 355 if ((iface_conf = malloc(sizeof(struct iface_conf))) 356 == NULL) 357 fatal(NULL); 358 memcpy(iface_conf, imsg.data, sizeof(struct 359 iface_conf)); 360 iface_conf->vc_id = NULL; 361 iface_conf->vc_id_len = 0; 362 iface_conf->c_id = NULL; 363 iface_conf->c_id_len = 0; 364 iface_conf->h_name = NULL; 365 SIMPLEQ_INSERT_TAIL(&nconf->iface_list, 366 iface_conf, entry); 367 break; 368 case IMSG_RECONF_VC_ID: 369 if (iface_conf == NULL) 370 fatal("IMSG_RECONF_VC_ID without " 371 "IMSG_RECONF_IFACE"); 372 if (IMSG_DATA_SIZE(imsg) > 255 + 2) 373 fatalx("%s: IMSG_RECONF_VC_ID wrong length: " 374 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 375 if ((iface_conf->vc_id = malloc(IMSG_DATA_SIZE(imsg))) 376 == NULL) 377 fatal(NULL); 378 memcpy(iface_conf->vc_id, imsg.data, 379 IMSG_DATA_SIZE(imsg)); 380 iface_conf->vc_id_len = IMSG_DATA_SIZE(imsg); 381 break; 382 case IMSG_RECONF_C_ID: 383 if (iface_conf == NULL) 384 fatal("IMSG_RECONF_C_ID without " 385 "IMSG_RECONF_IFACE"); 386 if (IMSG_DATA_SIZE(imsg) > 255 + 2) 387 fatalx("%s: IMSG_RECONF_C_ID wrong length: " 388 "%lu", __func__, IMSG_DATA_SIZE(imsg)); 389 if ((iface_conf->c_id = malloc(IMSG_DATA_SIZE(imsg))) 390 == NULL) 391 fatal(NULL); 392 memcpy(iface_conf->c_id, imsg.data, 393 IMSG_DATA_SIZE(imsg)); 394 iface_conf->c_id_len = IMSG_DATA_SIZE(imsg); 395 break; 396 case IMSG_RECONF_H_NAME: 397 if (iface_conf == NULL) 398 fatal("IMSG_RECONF_H_NAME without " 399 "IMSG_RECONF_IFACE"); 400 if (((char *)imsg.data)[IMSG_DATA_SIZE(imsg) - 1] != 401 '\0') 402 fatalx("Invalid hostname"); 403 if (IMSG_DATA_SIZE(imsg) > 256) 404 fatalx("Invalid hostname"); 405 if ((iface_conf->h_name = strdup(imsg.data)) == NULL) 406 fatal(NULL); 407 break; 408 case IMSG_RECONF_END: { 409 int i; 410 int *ifaces; 411 char ifnamebuf[IF_NAMESIZE], *if_name; 412 413 if (nconf == NULL) 414 fatalx("%s: IMSG_RECONF_END without " 415 "IMSG_RECONF_CONF", __func__); 416 417 ifaces = changed_ifaces(frontend_conf, nconf); 418 merge_config(frontend_conf, nconf); 419 nconf = NULL; 420 for (i = 0; ifaces[i] != 0; i++) { 421 if_index = ifaces[i]; 422 if_name = if_indextoname(if_index, ifnamebuf); 423 log_debug("changed iface: %s[%d]", if_name != 424 NULL ? if_name : "<unknown>", if_index); 425 frontend_imsg_compose_engine( 426 IMSG_REQUEST_REBOOT, 0, 0, &if_index, 427 sizeof(if_index)); 428 } 429 free(ifaces); 430 break; 431 } 432 case IMSG_CONTROLFD: 433 if ((fd = imsg_get_fd(&imsg)) == -1) 434 fatalx("%s: expected to receive imsg " 435 "control fd but didn't receive any", 436 __func__); 437 /* Listen on control socket. */ 438 control_listen(fd); 439 break; 440 case IMSG_CTL_END: 441 control_imsg_relay(&imsg); 442 break; 443 #endif /* SMALL */ 444 default: 445 log_debug("%s: error handling imsg %d", __func__, 446 imsg.hdr.type); 447 break; 448 } 449 imsg_free(&imsg); 450 } 451 if (!shut) 452 imsg_event_add(iev); 453 else { 454 /* This pipe is dead. Remove its event handler. */ 455 event_del(&iev->ev); 456 event_loopexit(NULL); 457 } 458 } 459 460 void 461 frontend_dispatch_engine(int fd, short event, void *bula) 462 { 463 struct imsgev *iev = bula; 464 struct imsgbuf *ibuf = &iev->ibuf; 465 struct imsg imsg; 466 struct iface *iface; 467 ssize_t n; 468 int shut = 0; 469 470 if (event & EV_READ) { 471 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 472 fatal("imsg_read error"); 473 if (n == 0) /* Connection closed. */ 474 shut = 1; 475 } 476 if (event & EV_WRITE) { 477 if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 478 fatal("msgbuf_write"); 479 if (n == 0) /* Connection closed. */ 480 shut = 1; 481 } 482 483 for (;;) { 484 if ((n = imsg_get(ibuf, &imsg)) == -1) 485 fatal("%s: imsg_get error", __func__); 486 if (n == 0) /* No more messages. */ 487 break; 488 489 switch (imsg.hdr.type) { 490 #ifndef SMALL 491 case IMSG_CTL_END: 492 case IMSG_CTL_SHOW_INTERFACE_INFO: 493 control_imsg_relay(&imsg); 494 break; 495 #endif /* SMALL */ 496 case IMSG_SEND_DISCOVER: { 497 struct imsg_req_dhcp imsg_req_dhcp; 498 if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_dhcp)) 499 fatalx("%s: IMSG_SEND_DISCOVER wrong " 500 "length: %lu", __func__, 501 IMSG_DATA_SIZE(imsg)); 502 memcpy(&imsg_req_dhcp, imsg.data, 503 sizeof(imsg_req_dhcp)); 504 505 iface = get_iface_by_id(imsg_req_dhcp.if_index); 506 507 if (iface == NULL) 508 break; 509 510 iface_data_from_imsg(iface, &imsg_req_dhcp); 511 send_packet(DHCPDISCOVER, iface); 512 break; 513 } 514 case IMSG_SEND_REQUEST: { 515 struct imsg_req_dhcp imsg_req_dhcp; 516 if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_dhcp)) 517 fatalx("%s: IMSG_SEND_REQUEST wrong " 518 "length: %lu", __func__, 519 IMSG_DATA_SIZE(imsg)); 520 memcpy(&imsg_req_dhcp, imsg.data, 521 sizeof(imsg_req_dhcp)); 522 523 iface = get_iface_by_id(imsg_req_dhcp.if_index); 524 525 if (iface == NULL) 526 break; 527 528 iface_data_from_imsg(iface, &imsg_req_dhcp); 529 send_packet(DHCPREQUEST, iface); 530 break; 531 } 532 default: 533 log_debug("%s: error handling imsg %d", __func__, 534 imsg.hdr.type); 535 break; 536 } 537 imsg_free(&imsg); 538 } 539 if (!shut) 540 imsg_event_add(iev); 541 else { 542 /* This pipe is dead. Remove its event handler. */ 543 event_del(&iev->ev); 544 event_loopexit(NULL); 545 } 546 } 547 548 int 549 get_flags(char *if_name) 550 { 551 struct ifreq ifr; 552 553 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 554 if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) { 555 log_warn("SIOCGIFFLAGS"); 556 return -1; 557 } 558 return ifr.ifr_flags; 559 } 560 561 int 562 get_xflags(char *if_name) 563 { 564 struct ifreq ifr; 565 566 strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 567 if (ioctl(ioctlsock, SIOCGIFXFLAGS, (caddr_t)&ifr) == -1) { 568 log_warn("SIOCGIFXFLAGS"); 569 return -1; 570 } 571 return ifr.ifr_flags; 572 } 573 574 void 575 update_iface(struct if_msghdr *ifm, struct sockaddr_dl *sdl) 576 { 577 struct iface *iface; 578 struct imsg_ifinfo ifinfo; 579 uint32_t if_index; 580 int flags, xflags; 581 char ifnamebuf[IF_NAMESIZE], *if_name; 582 583 if_index = ifm->ifm_index; 584 585 flags = ifm->ifm_flags; 586 xflags = ifm->ifm_xflags; 587 588 iface = get_iface_by_id(if_index); 589 if_name = if_indextoname(if_index, ifnamebuf); 590 591 if (if_name == NULL) { 592 if (iface != NULL) { 593 log_debug("interface with idx %d removed", if_index); 594 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 595 &if_index, sizeof(if_index)); 596 remove_iface(if_index); 597 } 598 return; 599 } 600 601 if (!(xflags & IFXF_AUTOCONF4)) { 602 if (iface != NULL) { 603 log_info("Removed autoconf flag from %s", if_name); 604 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 605 &if_index, sizeof(if_index)); 606 remove_iface(if_index); 607 } 608 return; 609 } 610 611 memset(&ifinfo, 0, sizeof(ifinfo)); 612 ifinfo.if_index = if_index; 613 ifinfo.link_state = ifm->ifm_data.ifi_link_state; 614 ifinfo.rdomain = ifm->ifm_tableid; 615 ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == 616 (IFF_UP | IFF_RUNNING); 617 618 if (sdl != NULL && (sdl->sdl_type == IFT_ETHER || 619 sdl->sdl_type == IFT_CARP) && sdl->sdl_alen == ETHER_ADDR_LEN) 620 memcpy(ifinfo.hw_address.ether_addr_octet, LLADDR(sdl), 621 ETHER_ADDR_LEN); 622 else if (iface == NULL) { 623 log_warnx("Could not find AF_LINK address for %s.", if_name); 624 return; 625 } 626 627 if (iface == NULL) { 628 if ((iface = calloc(1, sizeof(*iface))) == NULL) 629 fatal("calloc"); 630 iface->udpsock = -1; 631 LIST_INSERT_HEAD(&interfaces, iface, entries); 632 frontend_imsg_compose_main(IMSG_OPEN_BPFSOCK, 0, 633 &if_index, sizeof(if_index)); 634 } else { 635 if (iface->ifinfo.rdomain != ifinfo.rdomain && 636 iface->udpsock != -1) { 637 close(iface->udpsock); 638 iface->udpsock = -1; 639 } 640 } 641 642 if (memcmp(&iface->ifinfo, &ifinfo, sizeof(iface->ifinfo)) != 0) { 643 memcpy(&iface->ifinfo, &ifinfo, sizeof(iface->ifinfo)); 644 frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &iface->ifinfo, 645 sizeof(iface->ifinfo)); 646 } 647 } 648 649 void 650 frontend_startup(void) 651 { 652 if (!event_initialized(&ev_route)) 653 fatalx("%s: did not receive a route socket from the main " 654 "process", __func__); 655 656 init_ifaces(); 657 if (pledge("stdio unix recvfd", NULL) == -1) 658 fatal("pledge"); 659 event_add(&ev_route, NULL); 660 } 661 662 void 663 init_ifaces(void) 664 { 665 struct iface *iface; 666 struct imsg_ifinfo ifinfo; 667 struct if_nameindex *ifnidxp, *ifnidx; 668 struct ifaddrs *ifap, *ifa; 669 uint32_t if_index; 670 int flags, xflags; 671 char *if_name; 672 673 if ((ifnidxp = if_nameindex()) == NULL) 674 fatalx("if_nameindex"); 675 676 if (getifaddrs(&ifap) != 0) 677 fatal("getifaddrs"); 678 679 for (ifnidx = ifnidxp; ifnidx->if_index != 0 && ifnidx->if_name != NULL; 680 ifnidx++) { 681 if_index = ifnidx->if_index; 682 if_name = ifnidx->if_name; 683 if ((flags = get_flags(if_name)) == -1) 684 continue; 685 if ((xflags = get_xflags(if_name)) == -1) 686 continue; 687 if (!(xflags & IFXF_AUTOCONF4)) 688 continue; 689 690 memset(&ifinfo, 0, sizeof(ifinfo)); 691 ifinfo.if_index = if_index; 692 ifinfo.link_state = -1; 693 ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == 694 (IFF_UP | IFF_RUNNING); 695 696 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 697 if (strcmp(if_name, ifa->ifa_name) != 0) 698 continue; 699 if (ifa->ifa_addr == NULL) 700 continue; 701 702 switch (ifa->ifa_addr->sa_family) { 703 case AF_LINK: { 704 struct if_data *if_data; 705 struct sockaddr_dl *sdl; 706 707 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 708 if ((sdl->sdl_type != IFT_ETHER && 709 sdl->sdl_type != IFT_CARP) || 710 sdl->sdl_alen != ETHER_ADDR_LEN) 711 continue; 712 memcpy(ifinfo.hw_address.ether_addr_octet, 713 LLADDR(sdl), ETHER_ADDR_LEN); 714 715 if_data = (struct if_data *)ifa->ifa_data; 716 ifinfo.link_state = if_data->ifi_link_state; 717 ifinfo.rdomain = if_data->ifi_rdomain; 718 goto out; 719 } 720 default: 721 break; 722 } 723 } 724 out: 725 if (ifinfo.link_state == -1) 726 /* no AF_LINK found */ 727 continue; 728 729 if ((iface = calloc(1, sizeof(*iface))) == NULL) 730 fatal("calloc"); 731 iface->udpsock = -1; 732 memcpy(&iface->ifinfo, &ifinfo, sizeof(iface->ifinfo)); 733 LIST_INSERT_HEAD(&interfaces, iface, entries); 734 frontend_imsg_compose_main(IMSG_OPEN_BPFSOCK, 0, 735 &if_index, sizeof(if_index)); 736 frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &iface->ifinfo, 737 sizeof(iface->ifinfo)); 738 } 739 740 freeifaddrs(ifap); 741 if_freenameindex(ifnidxp); 742 } 743 744 void 745 route_receive(int fd, short events, void *arg) 746 { 747 static uint8_t *buf; 748 749 struct rt_msghdr *rtm; 750 struct sockaddr *sa, *rti_info[RTAX_MAX]; 751 ssize_t n; 752 753 if (buf == NULL) { 754 buf = malloc(ROUTE_SOCKET_BUF_SIZE); 755 if (buf == NULL) 756 fatal("malloc"); 757 } 758 rtm = (struct rt_msghdr *)buf; 759 if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) { 760 if (errno == EAGAIN || errno == EINTR) 761 return; 762 log_warn("dispatch_rtmsg: read error"); 763 return; 764 } 765 766 if (n == 0) 767 fatal("routing socket closed"); 768 769 if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) { 770 log_warnx("partial rtm of %zd in buffer", n); 771 return; 772 } 773 774 if (rtm->rtm_version != RTM_VERSION) 775 return; 776 777 sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen); 778 get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 779 780 handle_route_message(rtm, rti_info); 781 } 782 783 void 784 handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) 785 { 786 struct sockaddr_dl *sdl = NULL; 787 struct if_announcemsghdr *ifan; 788 uint32_t if_index; 789 790 switch (rtm->rtm_type) { 791 case RTM_IFINFO: 792 if (rtm->rtm_addrs & RTA_IFP && rti_info[RTAX_IFP]->sa_family 793 == AF_LINK) 794 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 795 update_iface((struct if_msghdr *)rtm, sdl); 796 break; 797 case RTM_IFANNOUNCE: 798 ifan = (struct if_announcemsghdr *)rtm; 799 if_index = ifan->ifan_index; 800 if (ifan->ifan_what == IFAN_DEPARTURE) { 801 frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 802 &if_index, sizeof(if_index)); 803 remove_iface(if_index); 804 } 805 break; 806 case RTM_PROPOSAL: 807 if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) { 808 log_debug("RTP_PROPOSAL_SOLICIT"); 809 frontend_imsg_compose_engine(IMSG_REPROPOSE_RDNS, 810 0, 0, NULL, 0); 811 } 812 #ifndef SMALL 813 else if (rtm->rtm_flags & RTF_PROTO3) { 814 char ifnamebuf[IF_NAMESIZE], *if_name; 815 816 if_index = rtm->rtm_index; 817 if_name = if_indextoname(if_index, ifnamebuf); 818 log_warnx("\"dhclient %s\" ran, requesting new lease", 819 if_name != NULL ? if_name : "(unknown)"); 820 frontend_imsg_compose_engine(IMSG_REQUEST_REBOOT, 821 0, 0, &if_index, sizeof(if_index)); 822 } 823 #endif /* SMALL */ 824 break; 825 default: 826 log_debug("unexpected RTM: %d", rtm->rtm_type); 827 break; 828 } 829 } 830 831 #define ROUNDUP(a) \ 832 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 833 834 void 835 get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 836 { 837 int i; 838 839 for (i = 0; i < RTAX_MAX; i++) { 840 if (addrs & (1 << i)) { 841 rti_info[i] = sa; 842 sa = (struct sockaddr *)((char *)(sa) + 843 ROUNDUP(sa->sa_len)); 844 } else 845 rti_info[i] = NULL; 846 } 847 } 848 849 void 850 bpf_receive(int fd, short events, void *arg) 851 { 852 struct bpf_hdr *hdr; 853 struct imsg_dhcp imsg_dhcp; 854 struct iface *iface; 855 ssize_t len, rem; 856 uint8_t *p; 857 858 iface = (struct iface *)arg; 859 860 if ((len = read(fd, iface->bpfev.buf, BPFLEN)) == -1) { 861 log_warn("%s: read", __func__); 862 return; 863 } 864 865 if (len == 0) 866 fatal("%s len == 0", __func__); 867 868 memset(&imsg_dhcp, 0, sizeof(imsg_dhcp)); 869 imsg_dhcp.if_index = iface->ifinfo.if_index; 870 871 rem = len; 872 p = iface->bpfev.buf; 873 874 while (rem > 0) { 875 if ((size_t)rem < sizeof(*hdr)) { 876 log_warnx("packet too short"); 877 return; 878 } 879 hdr = (struct bpf_hdr *)p; 880 if (hdr->bh_caplen != hdr->bh_datalen) { 881 log_warnx("skipping truncated packet"); 882 goto cont; 883 } 884 if (rem < hdr->bh_hdrlen + hdr->bh_caplen) 885 /* we are done */ 886 break; 887 if (hdr->bh_caplen > sizeof(imsg_dhcp.packet)) { 888 log_warn("packet too big"); 889 goto cont; 890 } 891 memcpy(&imsg_dhcp.packet, p + hdr->bh_hdrlen, hdr->bh_caplen); 892 imsg_dhcp.len = hdr->bh_caplen; 893 frontend_imsg_compose_engine(IMSG_DHCP, 0, 0, &imsg_dhcp, 894 sizeof(imsg_dhcp)); 895 cont: 896 p += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen); 897 rem -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen); 898 899 } 900 } 901 902 void 903 iface_data_from_imsg(struct iface* iface, struct imsg_req_dhcp *imsg) 904 { 905 iface->xid = imsg->xid; 906 iface->ciaddr = imsg->ciaddr; 907 iface->requested_ip = imsg->requested_ip; 908 iface->server_identifier = imsg->server_identifier; 909 iface->dhcp_server = imsg->dhcp_server; 910 } 911 912 ssize_t 913 build_packet(uint8_t message_type, char *if_name, uint32_t xid, 914 struct ether_addr *hw_address, struct in_addr *ciaddr, struct in_addr 915 *requested_ip, struct in_addr *server_identifier) 916 { 917 static uint8_t dhcp_cookie[] = DHCP_COOKIE; 918 static uint8_t dhcp_message_type[] = {DHO_DHCP_MESSAGE_TYPE, 1, 919 DHCPDISCOVER}; 920 static uint8_t dhcp_hostname[255 + 2] = {DHO_HOST_NAME, 0 /*, ... */}; 921 static uint8_t dhcp_client_id[] = {DHO_DHCP_CLIENT_IDENTIFIER, 7, 922 HTYPE_ETHER, 0, 0, 0, 0, 0, 0}; 923 static uint8_t dhcp_req_list[] = {DHO_DHCP_PARAMETER_REQUEST_LIST, 924 8, DHO_SUBNET_MASK, DHO_ROUTERS, DHO_DOMAIN_NAME_SERVERS, 925 DHO_HOST_NAME, DHO_DOMAIN_NAME, DHO_BROADCAST_ADDRESS, 926 DHO_DOMAIN_SEARCH, DHO_CLASSLESS_STATIC_ROUTES}; 927 static uint8_t dhcp_req_list_v6[] = {DHO_DHCP_PARAMETER_REQUEST_LIST, 928 9, DHO_SUBNET_MASK, DHO_ROUTERS, DHO_DOMAIN_NAME_SERVERS, 929 DHO_HOST_NAME, DHO_DOMAIN_NAME, DHO_BROADCAST_ADDRESS, 930 DHO_DOMAIN_SEARCH, DHO_CLASSLESS_STATIC_ROUTES, 931 DHO_IPV6_ONLY_PREFERRED}; 932 static uint8_t dhcp_requested_address[] = {DHO_DHCP_REQUESTED_ADDRESS, 933 4, 0, 0, 0, 0}; 934 static uint8_t dhcp_server_identifier[] = {DHO_DHCP_SERVER_IDENTIFIER, 935 4, 0, 0, 0, 0}; 936 #ifndef SMALL 937 struct iface_conf *iface_conf; 938 #endif /* SMALL */ 939 struct dhcp_hdr *hdr; 940 ssize_t len; 941 uint8_t *p; 942 char *c; 943 944 #ifndef SMALL 945 iface_conf = find_iface_conf(&frontend_conf->iface_list, if_name); 946 #endif /* SMALL */ 947 948 memset(dhcp_packet, 0, sizeof(dhcp_packet)); 949 dhcp_message_type[2] = message_type; 950 p = dhcp_packet; 951 hdr = (struct dhcp_hdr *)p; 952 hdr->op = DHCP_BOOTREQUEST; 953 hdr->htype = HTYPE_ETHER; 954 hdr->hlen = 6; 955 hdr->hops = 0; 956 hdr->xid = htonl(xid); 957 hdr->secs = 0; 958 hdr->ciaddr = *ciaddr; 959 memcpy(hdr->chaddr, hw_address, sizeof(*hw_address)); 960 p += sizeof(struct dhcp_hdr); 961 memcpy(p, dhcp_cookie, sizeof(dhcp_cookie)); 962 p += sizeof(dhcp_cookie); 963 memcpy(p, dhcp_message_type, sizeof(dhcp_message_type)); 964 p += sizeof(dhcp_message_type); 965 966 #ifndef SMALL 967 if (iface_conf != NULL && iface_conf->h_name != NULL) { 968 if (iface_conf->h_name[0] != '\0') { 969 dhcp_hostname[1] = strlen(iface_conf->h_name); 970 memcpy(dhcp_hostname + 2, iface_conf->h_name, 971 strlen(iface_conf->h_name)); 972 memcpy(p, dhcp_hostname, dhcp_hostname[1] + 2); 973 p += dhcp_hostname[1] + 2; 974 } 975 } else 976 #endif /* SMALL */ 977 { 978 if (gethostname(dhcp_hostname + 2, 979 sizeof(dhcp_hostname) - 2) == 0 && 980 dhcp_hostname[2] != '\0') { 981 if ((c = strchr(dhcp_hostname + 2, '.')) != NULL) 982 *c = '\0'; 983 dhcp_hostname[1] = strlen(dhcp_hostname + 2); 984 memcpy(p, dhcp_hostname, dhcp_hostname[1] + 2); 985 p += dhcp_hostname[1] + 2; 986 } 987 } 988 989 #ifndef SMALL 990 if (iface_conf != NULL) { 991 if (iface_conf->c_id_len > 0) { 992 /* XXX check space */ 993 memcpy(p, iface_conf->c_id, iface_conf->c_id_len); 994 p += iface_conf->c_id_len; 995 } else { 996 memcpy(dhcp_client_id + 3, hw_address, sizeof(*hw_address)); 997 memcpy(p, dhcp_client_id, sizeof(dhcp_client_id)); 998 p += sizeof(dhcp_client_id); 999 } 1000 if (iface_conf->vc_id_len > 0) { 1001 /* XXX check space */ 1002 memcpy(p, iface_conf->vc_id, iface_conf->vc_id_len); 1003 p += iface_conf->vc_id_len; 1004 } 1005 if (iface_conf->prefer_ipv6) { 1006 memcpy(p, dhcp_req_list_v6, sizeof(dhcp_req_list_v6)); 1007 p += sizeof(dhcp_req_list_v6); 1008 1009 } else { 1010 memcpy(p, dhcp_req_list, sizeof(dhcp_req_list)); 1011 p += sizeof(dhcp_req_list); 1012 } 1013 } else 1014 #endif /* SMALL */ 1015 { 1016 memcpy(dhcp_client_id + 3, hw_address, sizeof(*hw_address)); 1017 memcpy(p, dhcp_client_id, sizeof(dhcp_client_id)); 1018 p += sizeof(dhcp_client_id); 1019 memcpy(p, dhcp_req_list, sizeof(dhcp_req_list)); 1020 p += sizeof(dhcp_req_list); 1021 } 1022 1023 if (requested_ip->s_addr != INADDR_ANY) { 1024 memcpy(dhcp_requested_address + 2, requested_ip, 1025 sizeof(*requested_ip)); 1026 memcpy(p, dhcp_requested_address, 1027 sizeof(dhcp_requested_address)); 1028 p += sizeof(dhcp_requested_address); 1029 } 1030 1031 if (server_identifier->s_addr != INADDR_ANY) { 1032 memcpy(dhcp_server_identifier + 2, server_identifier, 1033 sizeof(*server_identifier)); 1034 memcpy(p, dhcp_server_identifier, 1035 sizeof(dhcp_server_identifier)); 1036 p += sizeof(dhcp_server_identifier); 1037 } 1038 1039 *p = DHO_END; 1040 p += 1; 1041 1042 len = p - dhcp_packet; 1043 1044 /* dhcp_packet is initialized with DHO_PADs */ 1045 if (len < BOOTP_MIN_LEN) 1046 len = BOOTP_MIN_LEN; 1047 1048 return (len); 1049 } 1050 1051 void 1052 send_packet(uint8_t message_type, struct iface *iface) 1053 { 1054 ssize_t pkt_len; 1055 char ifnamebuf[IF_NAMESIZE], *if_name; 1056 1057 if (!event_initialized(&iface->bpfev.ev)) { 1058 iface->send_discover = 1; 1059 return; 1060 } 1061 1062 iface->send_discover = 0; 1063 1064 if ((if_name = if_indextoname(iface->ifinfo.if_index, ifnamebuf)) == NULL) 1065 return; /* iface went away, nothing to do */ 1066 1067 log_debug("%s on %s", message_type == DHCPDISCOVER ? "DHCPDISCOVER" : 1068 "DHCPREQUEST", if_name); 1069 1070 pkt_len = build_packet(message_type, if_name, iface->xid, 1071 &iface->ifinfo.hw_address, &iface->ciaddr, &iface->requested_ip, 1072 &iface->server_identifier); 1073 if (iface->dhcp_server.s_addr != INADDR_ANY) { 1074 if (udp_send_packet(iface, dhcp_packet, pkt_len) == -1) 1075 bpf_send_packet(iface, dhcp_packet, pkt_len); 1076 } else 1077 bpf_send_packet(iface, dhcp_packet, pkt_len); 1078 } 1079 1080 int 1081 udp_send_packet(struct iface *iface, uint8_t *packet, ssize_t len) 1082 { 1083 struct sockaddr_in to; 1084 1085 memset(&to, 0, sizeof(to)); 1086 to.sin_family = AF_INET; 1087 to.sin_len = sizeof(to); 1088 to.sin_addr = iface->dhcp_server; 1089 to.sin_port = ntohs(SERVER_PORT); 1090 1091 if (sendto(iface->udpsock, packet, len, 0, (struct sockaddr *)&to, 1092 sizeof(to)) == -1) { 1093 log_warn("sendto"); 1094 return -1; 1095 } 1096 return 0; 1097 } 1098 void 1099 bpf_send_packet(struct iface *iface, uint8_t *packet, ssize_t len) 1100 { 1101 struct iovec iov[4]; 1102 struct ether_header eh; 1103 struct ip ip; 1104 struct udphdr udp; 1105 ssize_t total, result; 1106 int iovcnt = 0, i; 1107 1108 memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); 1109 memcpy(eh.ether_shost, &iface->ifinfo.hw_address, 1110 sizeof(eh.ether_dhost)); 1111 eh.ether_type = htons(ETHERTYPE_IP); 1112 iov[0].iov_base = &eh; 1113 iov[0].iov_len = sizeof(eh); 1114 iovcnt++; 1115 1116 ip.ip_v = 4; 1117 ip.ip_hl = 5; 1118 ip.ip_tos = IPTOS_LOWDELAY; 1119 ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len); 1120 ip.ip_id = 0; 1121 ip.ip_off = 0; 1122 ip.ip_ttl = 128; 1123 ip.ip_p = IPPROTO_UDP; 1124 ip.ip_sum = 0; 1125 ip.ip_src.s_addr = INADDR_ANY; 1126 ip.ip_dst.s_addr = INADDR_BROADCAST; 1127 ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0)); 1128 iov[iovcnt].iov_base = &ip; 1129 iov[iovcnt].iov_len = sizeof(ip); 1130 iovcnt++; 1131 1132 udp.uh_sport = htons(CLIENT_PORT); 1133 udp.uh_dport = htons(SERVER_PORT); 1134 udp.uh_ulen = htons(sizeof(udp) + len); 1135 udp.uh_sum = 0; 1136 udp.uh_sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp), 1137 checksum((unsigned char *)packet, len, 1138 checksum((unsigned char *)&ip.ip_src, 1139 2 * sizeof(ip.ip_src), 1140 IPPROTO_UDP + (uint32_t)ntohs(udp.uh_ulen))))); 1141 iov[iovcnt].iov_base = &udp; 1142 iov[iovcnt].iov_len = sizeof(udp); 1143 iovcnt++; 1144 1145 iov[iovcnt].iov_base = packet; 1146 iov[iovcnt].iov_len = len; 1147 iovcnt++; 1148 1149 total = 0; 1150 for (i = 0; i < iovcnt; i++) 1151 total += iov[i].iov_len; 1152 1153 result = writev(EVENT_FD(&iface->bpfev.ev), iov, iovcnt); 1154 if (result == -1) 1155 log_warn("%s: writev", __func__); 1156 else if (result < total) { 1157 log_warnx("%s, writev: %zd of %zd bytes", __func__, result, 1158 total); 1159 } 1160 } 1161 1162 struct iface* 1163 get_iface_by_id(uint32_t if_index) 1164 { 1165 struct iface *iface; 1166 1167 LIST_FOREACH (iface, &interfaces, entries) { 1168 if (iface->ifinfo.if_index == if_index) 1169 return (iface); 1170 } 1171 1172 return (NULL); 1173 } 1174 1175 void 1176 remove_iface(uint32_t if_index) 1177 { 1178 struct iface *iface; 1179 1180 iface = get_iface_by_id(if_index); 1181 1182 if (iface == NULL) 1183 return; 1184 1185 LIST_REMOVE(iface, entries); 1186 if (event_initialized(&iface->bpfev.ev)) { 1187 event_del(&iface->bpfev.ev); 1188 close(EVENT_FD(&iface->bpfev.ev)); 1189 } 1190 if (iface->udpsock != -1) 1191 close(iface->udpsock); 1192 free(iface); 1193 } 1194 1195 void 1196 set_bpfsock(int bpfsock, uint32_t if_index) 1197 { 1198 struct iface *iface; 1199 1200 iface = get_iface_by_id(if_index); 1201 1202 if (iface == NULL) { 1203 /* 1204 * The interface disappeared while we were waiting for the 1205 * parent process to open the bpf socket. 1206 */ 1207 close(bpfsock); 1208 } else if (event_initialized(&iface->bpfev.ev)) { 1209 /* 1210 * The autoconf flag is flapping and we have multiple bpf sockets in 1211 * flight. We don't need this one because we already got one. 1212 */ 1213 close(bpfsock); 1214 } else { 1215 event_set(&iface->bpfev.ev, bpfsock, EV_READ | 1216 EV_PERSIST, bpf_receive, iface); 1217 event_add(&iface->bpfev.ev, NULL); 1218 if (iface->send_discover) 1219 send_packet(DHCPDISCOVER, iface); 1220 } 1221 } 1222 1223 #ifndef SMALL 1224 struct iface_conf* 1225 find_iface_conf(struct iface_conf_head *head, char *if_name) 1226 { 1227 struct iface_conf *iface_conf; 1228 1229 if (if_name == NULL) 1230 return (NULL); 1231 1232 SIMPLEQ_FOREACH(iface_conf, head, entry) { 1233 if (strcmp(iface_conf->name, if_name) == 0) 1234 return iface_conf; 1235 } 1236 return (NULL); 1237 } 1238 1239 int* 1240 changed_ifaces(struct dhcpleased_conf *oconf, struct dhcpleased_conf *nconf) 1241 { 1242 struct iface_conf *iface_conf, *oiface_conf; 1243 int *ret, if_index, count = 0, i = 0; 1244 1245 /* 1246 * Worst case: All old interfaces replaced with new interfaces. 1247 * This should still be a small number 1248 */ 1249 SIMPLEQ_FOREACH(iface_conf, &oconf->iface_list, entry) 1250 count++; 1251 SIMPLEQ_FOREACH(iface_conf, &nconf->iface_list, entry) 1252 count++; 1253 1254 ret = calloc(count + 1, sizeof(int)); 1255 1256 SIMPLEQ_FOREACH(iface_conf, &nconf->iface_list, entry) { 1257 if ((if_index = if_nametoindex(iface_conf->name)) == 0) 1258 continue; 1259 oiface_conf = find_iface_conf(&oconf->iface_list, 1260 iface_conf->name); 1261 if (oiface_conf == NULL) { 1262 /* new interface added to config */ 1263 ret[i++] = if_index; 1264 } else if (iface_conf_cmp(iface_conf, oiface_conf) != 0) { 1265 /* interface conf changed */ 1266 ret[i++] = if_index; 1267 } 1268 } 1269 SIMPLEQ_FOREACH(oiface_conf, &oconf->iface_list, entry) { 1270 if ((if_index = if_nametoindex(oiface_conf->name)) == 0) 1271 continue; 1272 if (find_iface_conf(&nconf->iface_list, oiface_conf->name) == 1273 NULL) { 1274 /* interface removed from config */ 1275 ret[i++] = if_index; 1276 } 1277 } 1278 return ret; 1279 } 1280 1281 int 1282 iface_conf_cmp(struct iface_conf *a, struct iface_conf *b) 1283 { 1284 if (a->vc_id_len != b->vc_id_len) 1285 return 1; 1286 if (memcmp(a->vc_id, b->vc_id, a->vc_id_len) != 0) 1287 return 1; 1288 if (a->c_id_len != b->c_id_len) 1289 return 1; 1290 if (memcmp(a->c_id, b->c_id, a->c_id_len) != 0) 1291 return 1; 1292 if (a->h_name == NULL || b->h_name == NULL) 1293 return 1; 1294 if (strcmp(a->h_name, b->h_name) != 0) 1295 return 1; 1296 if (a->ignore != b->ignore) 1297 return 1; 1298 if (a->ignore_servers_len != b->ignore_servers_len) 1299 return 1; 1300 if (memcmp(a->ignore_servers, b->ignore_servers, 1301 a->ignore_servers_len * sizeof (struct in_addr)) != 0) 1302 return 1; 1303 return 0; 1304 } 1305 #endif /* SMALL */ 1306