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