1*b3441518Sflorian /* $OpenBSD: frontend.c,v 1.28 2022/01/04 06:20:37 florian Exp $ */ 257419a7fSflorian 357419a7fSflorian /* 457419a7fSflorian * Copyright (c) 2017, 2021 Florian Obser <florian@openbsd.org> 557419a7fSflorian * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 657419a7fSflorian * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 757419a7fSflorian * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 857419a7fSflorian * 957419a7fSflorian * Permission to use, copy, modify, and distribute this software for any 1057419a7fSflorian * purpose with or without fee is hereby granted, provided that the above 1157419a7fSflorian * copyright notice and this permission notice appear in all copies. 1257419a7fSflorian * 1357419a7fSflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1457419a7fSflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1557419a7fSflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1657419a7fSflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1757419a7fSflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1857419a7fSflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1957419a7fSflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2057419a7fSflorian */ 2157419a7fSflorian #include <sys/types.h> 2257419a7fSflorian #include <sys/ioctl.h> 2357419a7fSflorian #include <sys/queue.h> 2457419a7fSflorian #include <sys/socket.h> 2557419a7fSflorian #include <sys/syslog.h> 2657419a7fSflorian #include <sys/uio.h> 2757419a7fSflorian 2857419a7fSflorian #include <net/bpf.h> 2957419a7fSflorian #include <net/if.h> 3057419a7fSflorian #include <net/if_dl.h> 3157419a7fSflorian #include <net/if_types.h> 3257419a7fSflorian #include <net/route.h> 3357419a7fSflorian 3498b9f859Sclaudio #include <netinet/in.h> 3598b9f859Sclaudio #include <netinet/if_ether.h> 3657419a7fSflorian #include <netinet/ip.h> 3757419a7fSflorian #include <netinet/udp.h> 3857419a7fSflorian 3957419a7fSflorian #include <arpa/inet.h> 4057419a7fSflorian 4157419a7fSflorian #include <errno.h> 4257419a7fSflorian #include <event.h> 4357419a7fSflorian #include <ifaddrs.h> 4457419a7fSflorian #include <imsg.h> 4557419a7fSflorian #include <pwd.h> 4657419a7fSflorian #include <signal.h> 4757419a7fSflorian #include <stdio.h> 4857419a7fSflorian #include <stdlib.h> 4957419a7fSflorian #include <string.h> 5057419a7fSflorian #include <unistd.h> 5157419a7fSflorian 5257419a7fSflorian #include "bpf.h" 5357419a7fSflorian #include "log.h" 5457419a7fSflorian #include "dhcpleased.h" 5557419a7fSflorian #include "frontend.h" 5657419a7fSflorian #include "control.h" 5757419a7fSflorian #include "checksum.h" 5857419a7fSflorian 5957419a7fSflorian #define ROUTE_SOCKET_BUF_SIZE 16384 602d2edb0eSflorian #define BOOTP_MIN_LEN 300 /* fixed bootp packet adds up to 300 */ 6157419a7fSflorian 6257419a7fSflorian struct bpf_ev { 6357419a7fSflorian struct event ev; 6457419a7fSflorian uint8_t buf[BPFLEN]; 6557419a7fSflorian }; 6657419a7fSflorian 6757419a7fSflorian struct iface { 6857419a7fSflorian LIST_ENTRY(iface) entries; 6957419a7fSflorian struct bpf_ev bpfev; 701bbf741cSflorian struct imsg_ifinfo ifinfo; 7157419a7fSflorian int send_discover; 7257419a7fSflorian uint32_t xid; 7382a5f3d7Sflorian struct in_addr ciaddr; 7457419a7fSflorian struct in_addr requested_ip; 7557419a7fSflorian struct in_addr server_identifier; 7657419a7fSflorian struct in_addr dhcp_server; 7757419a7fSflorian int udpsock; 7857419a7fSflorian }; 7957419a7fSflorian 8057419a7fSflorian __dead void frontend_shutdown(void); 8157419a7fSflorian void frontend_sig_handler(int, short, void *); 8248e1b614Sflorian void update_iface(struct if_msghdr *, struct sockaddr_dl *); 8357419a7fSflorian void frontend_startup(void); 841bbf741cSflorian void init_ifaces(void); 8557419a7fSflorian void route_receive(int, short, void *); 8657419a7fSflorian void handle_route_message(struct rt_msghdr *, struct sockaddr **); 8757419a7fSflorian void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 8857419a7fSflorian void bpf_receive(int, short, void *); 8957419a7fSflorian int get_flags(char *); 9057419a7fSflorian int get_xflags(char *); 9157419a7fSflorian struct iface *get_iface_by_id(uint32_t); 9257419a7fSflorian void remove_iface(uint32_t); 9357419a7fSflorian void set_bpfsock(int, uint32_t); 9482a5f3d7Sflorian void iface_data_from_imsg(struct iface*, struct imsg_req_dhcp *); 95a41cc082Sflorian ssize_t build_packet(uint8_t, char *, uint32_t, struct ether_addr *, 9682a5f3d7Sflorian struct in_addr *, struct in_addr *, struct in_addr *); 9782a5f3d7Sflorian void send_packet(uint8_t, struct iface *); 9857419a7fSflorian void bpf_send_packet(struct iface *, uint8_t *, ssize_t); 99c645071eSflorian int udp_send_packet(struct iface *, uint8_t *, ssize_t); 1004eb9756fSflorian #ifndef SMALL 101580befd2Sflorian int iface_conf_cmp(struct iface_conf *, struct iface_conf *); 1024eb9756fSflorian #endif /* SMALL */ 10357419a7fSflorian 10457419a7fSflorian LIST_HEAD(, iface) interfaces; 105a41cc082Sflorian struct dhcpleased_conf *frontend_conf; 10657419a7fSflorian static struct imsgev *iev_main; 10757419a7fSflorian static struct imsgev *iev_engine; 10857419a7fSflorian struct event ev_route; 10957419a7fSflorian int ioctlsock; 11057419a7fSflorian 11157419a7fSflorian uint8_t dhcp_packet[1500]; 11257419a7fSflorian 11357419a7fSflorian void 11457419a7fSflorian frontend_sig_handler(int sig, short event, void *bula) 11557419a7fSflorian { 11657419a7fSflorian /* 11757419a7fSflorian * Normal signal handler rules don't apply because libevent 11857419a7fSflorian * decouples for us. 11957419a7fSflorian */ 12057419a7fSflorian 12157419a7fSflorian switch (sig) { 12257419a7fSflorian case SIGINT: 12357419a7fSflorian case SIGTERM: 12457419a7fSflorian frontend_shutdown(); 12557419a7fSflorian default: 12657419a7fSflorian fatalx("unexpected signal"); 12757419a7fSflorian } 12857419a7fSflorian } 12957419a7fSflorian 13057419a7fSflorian void 13157419a7fSflorian frontend(int debug, int verbose) 13257419a7fSflorian { 13357419a7fSflorian struct event ev_sigint, ev_sigterm; 13457419a7fSflorian struct passwd *pw; 13557419a7fSflorian 136a41cc082Sflorian #ifndef SMALL 137a41cc082Sflorian frontend_conf = config_new_empty(); 138a41cc082Sflorian #endif /* SMALL */ 139a41cc082Sflorian 14057419a7fSflorian log_init(debug, LOG_DAEMON); 14157419a7fSflorian log_setverbose(verbose); 14257419a7fSflorian 14357419a7fSflorian if ((pw = getpwnam(DHCPLEASED_USER)) == NULL) 14457419a7fSflorian fatal("getpwnam"); 14557419a7fSflorian 14657419a7fSflorian if (chdir("/") == -1) 14757419a7fSflorian fatal("chdir(\"/\")"); 14857419a7fSflorian 149c7d84514Sflorian if (unveil("/", "") == -1) 150bc5a8259Sbeck fatal("unveil /"); 151c7d84514Sflorian if (unveil(NULL, NULL) == -1) 152bc5a8259Sbeck fatal("unveil"); 153c7d84514Sflorian 15457419a7fSflorian setproctitle("%s", "frontend"); 15557419a7fSflorian log_procinit("frontend"); 15657419a7fSflorian 15757419a7fSflorian if ((ioctlsock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1) 15857419a7fSflorian fatal("socket"); 15957419a7fSflorian 16057419a7fSflorian if (setgroups(1, &pw->pw_gid) || 16157419a7fSflorian setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 16257419a7fSflorian setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 16357419a7fSflorian fatal("can't drop privileges"); 16457419a7fSflorian 16557419a7fSflorian if (pledge("stdio unix recvfd route", NULL) == -1) 16657419a7fSflorian fatal("pledge"); 16757419a7fSflorian event_init(); 16857419a7fSflorian 16957419a7fSflorian /* Setup signal handler. */ 17057419a7fSflorian signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL); 17157419a7fSflorian signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL); 17257419a7fSflorian signal_add(&ev_sigint, NULL); 17357419a7fSflorian signal_add(&ev_sigterm, NULL); 17457419a7fSflorian signal(SIGPIPE, SIG_IGN); 17557419a7fSflorian signal(SIGHUP, SIG_IGN); 17657419a7fSflorian 17757419a7fSflorian /* Setup pipe and event handler to the parent process. */ 17857419a7fSflorian if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 17957419a7fSflorian fatal(NULL); 18057419a7fSflorian imsg_init(&iev_main->ibuf, 3); 18157419a7fSflorian iev_main->handler = frontend_dispatch_main; 18257419a7fSflorian iev_main->events = EV_READ; 18357419a7fSflorian event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 18457419a7fSflorian iev_main->handler, iev_main); 18557419a7fSflorian event_add(&iev_main->ev, NULL); 18657419a7fSflorian 18757419a7fSflorian LIST_INIT(&interfaces); 18857419a7fSflorian event_dispatch(); 18957419a7fSflorian 19057419a7fSflorian frontend_shutdown(); 19157419a7fSflorian } 19257419a7fSflorian 19357419a7fSflorian __dead void 19457419a7fSflorian frontend_shutdown(void) 19557419a7fSflorian { 19657419a7fSflorian /* Close pipes. */ 19757419a7fSflorian msgbuf_write(&iev_engine->ibuf.w); 19857419a7fSflorian msgbuf_clear(&iev_engine->ibuf.w); 19957419a7fSflorian close(iev_engine->ibuf.fd); 20057419a7fSflorian msgbuf_write(&iev_main->ibuf.w); 20157419a7fSflorian msgbuf_clear(&iev_main->ibuf.w); 20257419a7fSflorian close(iev_main->ibuf.fd); 20357419a7fSflorian 204a41cc082Sflorian #ifndef SMALL 205a41cc082Sflorian config_clear(frontend_conf); 206a41cc082Sflorian #endif /* SMALL */ 207a41cc082Sflorian 20857419a7fSflorian free(iev_engine); 20957419a7fSflorian free(iev_main); 21057419a7fSflorian 21157419a7fSflorian log_info("frontend exiting"); 21257419a7fSflorian exit(0); 21357419a7fSflorian } 21457419a7fSflorian 21557419a7fSflorian int 21657419a7fSflorian frontend_imsg_compose_main(int type, pid_t pid, void *data, 21757419a7fSflorian uint16_t datalen) 21857419a7fSflorian { 21957419a7fSflorian return (imsg_compose_event(iev_main, type, 0, pid, -1, data, 22057419a7fSflorian datalen)); 22157419a7fSflorian } 22257419a7fSflorian 22357419a7fSflorian int 22457419a7fSflorian frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid, 22557419a7fSflorian void *data, uint16_t datalen) 22657419a7fSflorian { 22757419a7fSflorian return (imsg_compose_event(iev_engine, type, peerid, pid, -1, 22857419a7fSflorian data, datalen)); 22957419a7fSflorian } 23057419a7fSflorian 23157419a7fSflorian void 23257419a7fSflorian frontend_dispatch_main(int fd, short event, void *bula) 23357419a7fSflorian { 234a41cc082Sflorian static struct dhcpleased_conf *nconf; 235a41cc082Sflorian static struct iface_conf *iface_conf; 23657419a7fSflorian struct imsg imsg; 23757419a7fSflorian struct imsgev *iev = bula; 23857419a7fSflorian struct imsgbuf *ibuf = &iev->ibuf; 23957419a7fSflorian struct iface *iface; 24057419a7fSflorian ssize_t n; 24157419a7fSflorian int shut = 0, bpfsock, if_index, udpsock; 24257419a7fSflorian 24357419a7fSflorian if (event & EV_READ) { 24457419a7fSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 24557419a7fSflorian fatal("imsg_read error"); 24657419a7fSflorian if (n == 0) /* Connection closed. */ 24757419a7fSflorian shut = 1; 24857419a7fSflorian } 24957419a7fSflorian if (event & EV_WRITE) { 25057419a7fSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 25157419a7fSflorian fatal("msgbuf_write"); 25257419a7fSflorian if (n == 0) /* Connection closed. */ 25357419a7fSflorian shut = 1; 25457419a7fSflorian } 25557419a7fSflorian 25657419a7fSflorian for (;;) { 25757419a7fSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 25857419a7fSflorian fatal("%s: imsg_get error", __func__); 25957419a7fSflorian if (n == 0) /* No more messages. */ 26057419a7fSflorian break; 26157419a7fSflorian 26257419a7fSflorian switch (imsg.hdr.type) { 26357419a7fSflorian case IMSG_SOCKET_IPC: 26457419a7fSflorian /* 26557419a7fSflorian * Setup pipe and event handler to the engine 26657419a7fSflorian * process. 26757419a7fSflorian */ 26857419a7fSflorian if (iev_engine) 26957419a7fSflorian fatalx("%s: received unexpected imsg fd " 27057419a7fSflorian "to frontend", __func__); 27157419a7fSflorian 27257419a7fSflorian if ((fd = imsg.fd) == -1) 27357419a7fSflorian fatalx("%s: expected to receive imsg fd to " 27457419a7fSflorian "frontend but didn't receive any", 27557419a7fSflorian __func__); 27657419a7fSflorian 27757419a7fSflorian iev_engine = malloc(sizeof(struct imsgev)); 27857419a7fSflorian if (iev_engine == NULL) 27957419a7fSflorian fatal(NULL); 28057419a7fSflorian 28157419a7fSflorian imsg_init(&iev_engine->ibuf, fd); 28257419a7fSflorian iev_engine->handler = frontend_dispatch_engine; 28357419a7fSflorian iev_engine->events = EV_READ; 28457419a7fSflorian 28557419a7fSflorian event_set(&iev_engine->ev, iev_engine->ibuf.fd, 28657419a7fSflorian iev_engine->events, iev_engine->handler, iev_engine); 28757419a7fSflorian event_add(&iev_engine->ev, NULL); 28857419a7fSflorian break; 28957419a7fSflorian case IMSG_BPFSOCK: 29057419a7fSflorian if ((bpfsock = imsg.fd) == -1) 29157419a7fSflorian fatalx("%s: expected to receive imsg " 29257419a7fSflorian "bpf fd but didn't receive any", 29357419a7fSflorian __func__); 29457419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 29557419a7fSflorian fatalx("%s: IMSG_BPFSOCK wrong length: " 29657419a7fSflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 29757419a7fSflorian memcpy(&if_index, imsg.data, sizeof(if_index)); 29857419a7fSflorian set_bpfsock(bpfsock, if_index); 29957419a7fSflorian break; 30057419a7fSflorian case IMSG_UDPSOCK: 30157419a7fSflorian if ((udpsock = imsg.fd) == -1) 30257419a7fSflorian fatalx("%s: expected to receive imsg " 30357419a7fSflorian "udpsocket fd but didn't receive any", 30457419a7fSflorian __func__); 30557419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 30657419a7fSflorian fatalx("%s: IMSG_UDPSOCK wrong length: " 30757419a7fSflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 30857419a7fSflorian memcpy(&if_index, imsg.data, sizeof(if_index)); 30957419a7fSflorian if ((iface = get_iface_by_id(if_index)) == NULL) { 31057419a7fSflorian close(fd); 31157419a7fSflorian break; 31257419a7fSflorian } 31357419a7fSflorian if (iface->udpsock != -1) 31457419a7fSflorian fatalx("%s: received unexpected udpsocket", 31557419a7fSflorian __func__); 31657419a7fSflorian iface->udpsock = udpsock; 31757419a7fSflorian break; 31857419a7fSflorian case IMSG_CLOSE_UDPSOCK: 31957419a7fSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 32057419a7fSflorian fatalx("%s: IMSG_UDPSOCK wrong length: " 32157419a7fSflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 32257419a7fSflorian memcpy(&if_index, imsg.data, sizeof(if_index)); 32357419a7fSflorian if ((iface = get_iface_by_id(if_index)) != NULL && 32457419a7fSflorian iface->udpsock != -1) { 32557419a7fSflorian close(iface->udpsock); 32657419a7fSflorian iface->udpsock = -1; 32757419a7fSflorian } 32857419a7fSflorian break; 32957419a7fSflorian case IMSG_ROUTESOCK: 33057419a7fSflorian if ((fd = imsg.fd) == -1) 33157419a7fSflorian fatalx("%s: expected to receive imsg " 33257419a7fSflorian "routesocket fd but didn't receive any", 33357419a7fSflorian __func__); 33457419a7fSflorian event_set(&ev_route, fd, EV_READ | EV_PERSIST, 33557419a7fSflorian route_receive, NULL); 33657419a7fSflorian break; 33757419a7fSflorian case IMSG_STARTUP: 33857419a7fSflorian frontend_startup(); 33957419a7fSflorian break; 34057419a7fSflorian #ifndef SMALL 341a41cc082Sflorian case IMSG_RECONF_CONF: 342a41cc082Sflorian if (nconf != NULL) 343a41cc082Sflorian fatalx("%s: IMSG_RECONF_CONF already in " 344a41cc082Sflorian "progress", __func__); 345a41cc082Sflorian if ((nconf = malloc(sizeof(struct dhcpleased_conf))) == 346a41cc082Sflorian NULL) 347a41cc082Sflorian fatal(NULL); 348a41cc082Sflorian SIMPLEQ_INIT(&nconf->iface_list); 349a41cc082Sflorian break; 350a41cc082Sflorian case IMSG_RECONF_IFACE: 351a41cc082Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(struct 352a41cc082Sflorian iface_conf)) 353a41cc082Sflorian fatalx("%s: IMSG_RECONF_IFACE wrong length: " 354a41cc082Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 355a41cc082Sflorian if ((iface_conf = malloc(sizeof(struct iface_conf))) 356a41cc082Sflorian == NULL) 357a41cc082Sflorian fatal(NULL); 358a41cc082Sflorian memcpy(iface_conf, imsg.data, sizeof(struct 359a41cc082Sflorian iface_conf)); 360a41cc082Sflorian iface_conf->vc_id = NULL; 361a41cc082Sflorian iface_conf->vc_id_len = 0; 362a41cc082Sflorian iface_conf->c_id = NULL; 363a41cc082Sflorian iface_conf->c_id_len = 0; 364*b3441518Sflorian iface_conf->h_name = NULL; 365a41cc082Sflorian SIMPLEQ_INSERT_TAIL(&nconf->iface_list, 366a41cc082Sflorian iface_conf, entry); 367a41cc082Sflorian break; 368a41cc082Sflorian case IMSG_RECONF_VC_ID: 369a41cc082Sflorian if (iface_conf == NULL) 370a41cc082Sflorian fatal("IMSG_RECONF_VC_ID without " 371a41cc082Sflorian "IMSG_RECONF_IFACE"); 372a41cc082Sflorian if (IMSG_DATA_SIZE(imsg) > 255 + 2) 373a41cc082Sflorian fatalx("%s: IMSG_RECONF_VC_ID wrong length: " 374a41cc082Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 375a41cc082Sflorian if ((iface_conf->vc_id = malloc(IMSG_DATA_SIZE(imsg))) 376a41cc082Sflorian == NULL) 377a41cc082Sflorian fatal(NULL); 378a41cc082Sflorian memcpy(iface_conf->vc_id, imsg.data, 379a41cc082Sflorian IMSG_DATA_SIZE(imsg)); 380a41cc082Sflorian iface_conf->vc_id_len = IMSG_DATA_SIZE(imsg); 381a41cc082Sflorian break; 382a41cc082Sflorian case IMSG_RECONF_C_ID: 383a41cc082Sflorian if (iface_conf == NULL) 384a41cc082Sflorian fatal("IMSG_RECONF_C_ID without " 385a41cc082Sflorian "IMSG_RECONF_IFACE"); 386a41cc082Sflorian if (IMSG_DATA_SIZE(imsg) > 255 + 2) 387a41cc082Sflorian fatalx("%s: IMSG_RECONF_C_ID wrong length: " 388a41cc082Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 389a41cc082Sflorian if ((iface_conf->c_id = malloc(IMSG_DATA_SIZE(imsg))) 390a41cc082Sflorian == NULL) 391a41cc082Sflorian fatal(NULL); 392a41cc082Sflorian memcpy(iface_conf->c_id, imsg.data, 393a41cc082Sflorian IMSG_DATA_SIZE(imsg)); 394a41cc082Sflorian iface_conf->c_id_len = IMSG_DATA_SIZE(imsg); 395a41cc082Sflorian break; 396*b3441518Sflorian case IMSG_RECONF_H_NAME: 397*b3441518Sflorian if (iface_conf == NULL) 398*b3441518Sflorian fatal("IMSG_RECONF_H_NAME without " 399*b3441518Sflorian "IMSG_RECONF_IFACE"); 400*b3441518Sflorian if (((char *)imsg.data)[IMSG_DATA_SIZE(imsg) - 1] != 401*b3441518Sflorian '\0') 402*b3441518Sflorian fatalx("Invalid hostname"); 403*b3441518Sflorian if (IMSG_DATA_SIZE(imsg) > 256) 404*b3441518Sflorian fatalx("Invalid hostname"); 405*b3441518Sflorian if ((iface_conf->h_name = strdup(imsg.data)) == NULL) 406*b3441518Sflorian fatal(NULL); 407*b3441518Sflorian break; 408580befd2Sflorian case IMSG_RECONF_END: { 409580befd2Sflorian int i; 410580befd2Sflorian int *ifaces; 411580befd2Sflorian char ifnamebuf[IF_NAMESIZE], *if_name; 412580befd2Sflorian 413a41cc082Sflorian if (nconf == NULL) 414a41cc082Sflorian fatalx("%s: IMSG_RECONF_END without " 415a41cc082Sflorian "IMSG_RECONF_CONF", __func__); 416580befd2Sflorian 417580befd2Sflorian ifaces = changed_ifaces(frontend_conf, nconf); 418a41cc082Sflorian merge_config(frontend_conf, nconf); 419a41cc082Sflorian nconf = NULL; 420580befd2Sflorian for (i = 0; ifaces[i] != 0; i++) { 421580befd2Sflorian if_index = ifaces[i]; 422580befd2Sflorian if_name = if_indextoname(if_index, ifnamebuf); 423580befd2Sflorian log_debug("changed iface: %s[%d]", if_name != 424580befd2Sflorian NULL ? if_name : "<unknown>", if_index); 425580befd2Sflorian frontend_imsg_compose_engine( 426580befd2Sflorian IMSG_REQUEST_REBOOT, 0, 0, &if_index, 427580befd2Sflorian sizeof(if_index)); 428580befd2Sflorian } 429580befd2Sflorian free(ifaces); 430a41cc082Sflorian break; 431580befd2Sflorian } 43257419a7fSflorian case IMSG_CONTROLFD: 43357419a7fSflorian if ((fd = imsg.fd) == -1) 43457419a7fSflorian fatalx("%s: expected to receive imsg " 43557419a7fSflorian "control fd but didn't receive any", 43657419a7fSflorian __func__); 43757419a7fSflorian /* Listen on control socket. */ 43857419a7fSflorian control_listen(fd); 43957419a7fSflorian break; 44057419a7fSflorian case IMSG_CTL_END: 44157419a7fSflorian control_imsg_relay(&imsg); 44257419a7fSflorian break; 44357419a7fSflorian #endif /* SMALL */ 44457419a7fSflorian default: 44557419a7fSflorian log_debug("%s: error handling imsg %d", __func__, 44657419a7fSflorian imsg.hdr.type); 44757419a7fSflorian break; 44857419a7fSflorian } 44957419a7fSflorian imsg_free(&imsg); 45057419a7fSflorian } 45157419a7fSflorian if (!shut) 45257419a7fSflorian imsg_event_add(iev); 45357419a7fSflorian else { 45457419a7fSflorian /* This pipe is dead. Remove its event handler. */ 45557419a7fSflorian event_del(&iev->ev); 45657419a7fSflorian event_loopexit(NULL); 45757419a7fSflorian } 45857419a7fSflorian } 45957419a7fSflorian 46057419a7fSflorian void 46157419a7fSflorian frontend_dispatch_engine(int fd, short event, void *bula) 46257419a7fSflorian { 46357419a7fSflorian struct imsgev *iev = bula; 46457419a7fSflorian struct imsgbuf *ibuf = &iev->ibuf; 46557419a7fSflorian struct imsg imsg; 46657419a7fSflorian struct iface *iface; 46757419a7fSflorian ssize_t n; 46857419a7fSflorian int shut = 0; 46957419a7fSflorian 47057419a7fSflorian if (event & EV_READ) { 47157419a7fSflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 47257419a7fSflorian fatal("imsg_read error"); 47357419a7fSflorian if (n == 0) /* Connection closed. */ 47457419a7fSflorian shut = 1; 47557419a7fSflorian } 47657419a7fSflorian if (event & EV_WRITE) { 47757419a7fSflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 47857419a7fSflorian fatal("msgbuf_write"); 47957419a7fSflorian if (n == 0) /* Connection closed. */ 48057419a7fSflorian shut = 1; 48157419a7fSflorian } 48257419a7fSflorian 48357419a7fSflorian for (;;) { 48457419a7fSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 48557419a7fSflorian fatal("%s: imsg_get error", __func__); 48657419a7fSflorian if (n == 0) /* No more messages. */ 48757419a7fSflorian break; 48857419a7fSflorian 48957419a7fSflorian switch (imsg.hdr.type) { 49057419a7fSflorian #ifndef SMALL 49157419a7fSflorian case IMSG_CTL_END: 49257419a7fSflorian case IMSG_CTL_SHOW_INTERFACE_INFO: 49357419a7fSflorian control_imsg_relay(&imsg); 49457419a7fSflorian break; 49557419a7fSflorian #endif /* SMALL */ 49657419a7fSflorian case IMSG_SEND_DISCOVER: { 49782a5f3d7Sflorian struct imsg_req_dhcp imsg_req_dhcp; 49882a5f3d7Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_dhcp)) 49957419a7fSflorian fatalx("%s: IMSG_SEND_DISCOVER wrong " 50057419a7fSflorian "length: %lu", __func__, 50157419a7fSflorian IMSG_DATA_SIZE(imsg)); 50282a5f3d7Sflorian memcpy(&imsg_req_dhcp, imsg.data, 50382a5f3d7Sflorian sizeof(imsg_req_dhcp)); 50482a5f3d7Sflorian 50582a5f3d7Sflorian iface = get_iface_by_id(imsg_req_dhcp.if_index); 50682a5f3d7Sflorian 50782a5f3d7Sflorian if (iface == NULL) 50882a5f3d7Sflorian break; 50982a5f3d7Sflorian 51082a5f3d7Sflorian iface_data_from_imsg(iface, &imsg_req_dhcp); 51182a5f3d7Sflorian send_packet(DHCPDISCOVER, iface); 51257419a7fSflorian break; 51357419a7fSflorian } 51457419a7fSflorian case IMSG_SEND_REQUEST: { 51582a5f3d7Sflorian struct imsg_req_dhcp imsg_req_dhcp; 51682a5f3d7Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(imsg_req_dhcp)) 51757419a7fSflorian fatalx("%s: IMSG_SEND_REQUEST wrong " 51857419a7fSflorian "length: %lu", __func__, 51957419a7fSflorian IMSG_DATA_SIZE(imsg)); 52082a5f3d7Sflorian memcpy(&imsg_req_dhcp, imsg.data, 52182a5f3d7Sflorian sizeof(imsg_req_dhcp)); 52282a5f3d7Sflorian 52382a5f3d7Sflorian iface = get_iface_by_id(imsg_req_dhcp.if_index); 52482a5f3d7Sflorian 52582a5f3d7Sflorian if (iface == NULL) 52682a5f3d7Sflorian break; 52782a5f3d7Sflorian 52882a5f3d7Sflorian iface_data_from_imsg(iface, &imsg_req_dhcp); 52982a5f3d7Sflorian send_packet(DHCPREQUEST, iface); 53057419a7fSflorian break; 53157419a7fSflorian } 53257419a7fSflorian default: 53357419a7fSflorian log_debug("%s: error handling imsg %d", __func__, 53457419a7fSflorian imsg.hdr.type); 53557419a7fSflorian break; 53657419a7fSflorian } 53757419a7fSflorian imsg_free(&imsg); 53857419a7fSflorian } 53957419a7fSflorian if (!shut) 54057419a7fSflorian imsg_event_add(iev); 54157419a7fSflorian else { 54257419a7fSflorian /* This pipe is dead. Remove its event handler. */ 54357419a7fSflorian event_del(&iev->ev); 54457419a7fSflorian event_loopexit(NULL); 54557419a7fSflorian } 54657419a7fSflorian } 54757419a7fSflorian 54857419a7fSflorian int 54957419a7fSflorian get_flags(char *if_name) 55057419a7fSflorian { 55157419a7fSflorian struct ifreq ifr; 55257419a7fSflorian 55357419a7fSflorian strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 55457419a7fSflorian if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) == -1) { 55557419a7fSflorian log_warn("SIOCGIFFLAGS"); 55657419a7fSflorian return -1; 55757419a7fSflorian } 55857419a7fSflorian return ifr.ifr_flags; 55957419a7fSflorian } 56057419a7fSflorian 56157419a7fSflorian int 56257419a7fSflorian get_xflags(char *if_name) 56357419a7fSflorian { 56457419a7fSflorian struct ifreq ifr; 56557419a7fSflorian 56657419a7fSflorian strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 56757419a7fSflorian if (ioctl(ioctlsock, SIOCGIFXFLAGS, (caddr_t)&ifr) == -1) { 56857419a7fSflorian log_warn("SIOCGIFXFLAGS"); 56957419a7fSflorian return -1; 57057419a7fSflorian } 57157419a7fSflorian return ifr.ifr_flags; 57257419a7fSflorian } 57357419a7fSflorian 57457419a7fSflorian void 57548e1b614Sflorian update_iface(struct if_msghdr *ifm, struct sockaddr_dl *sdl) 57657419a7fSflorian { 57757419a7fSflorian struct iface *iface; 5781bbf741cSflorian struct imsg_ifinfo ifinfo; 5791bbf741cSflorian uint32_t if_index; 58048e1b614Sflorian int flags, xflags; 5811bbf741cSflorian char ifnamebuf[IF_NAMESIZE], *if_name; 58257419a7fSflorian 5831bbf741cSflorian if_index = ifm->ifm_index; 5841bbf741cSflorian 5851bbf741cSflorian flags = ifm->ifm_flags; 5861bbf741cSflorian xflags = ifm->ifm_xflags; 5871bbf741cSflorian 5881bbf741cSflorian iface = get_iface_by_id(if_index); 5891bbf741cSflorian if_name = if_indextoname(if_index, ifnamebuf); 5901bbf741cSflorian 5911bbf741cSflorian if (if_name == NULL) { 5921bbf741cSflorian if (iface != NULL) { 5931bbf741cSflorian log_debug("interface with idx %d removed", if_index); 5941bbf741cSflorian frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 5951bbf741cSflorian &if_index, sizeof(if_index)); 5961bbf741cSflorian remove_iface(if_index); 5971bbf741cSflorian } 59857419a7fSflorian return; 5991bbf741cSflorian } 60057419a7fSflorian 6011bbf741cSflorian if (!(xflags & IFXF_AUTOCONF4)) { 6021bbf741cSflorian if (iface != NULL) { 6031bbf741cSflorian log_info("Removed autoconf flag from %s", if_name); 6041bbf741cSflorian frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 6051bbf741cSflorian &if_index, sizeof(if_index)); 6061bbf741cSflorian remove_iface(if_index); 6071bbf741cSflorian } 60857419a7fSflorian return; 6091bbf741cSflorian } 61057419a7fSflorian 6111bbf741cSflorian memset(&ifinfo, 0, sizeof(ifinfo)); 6121bbf741cSflorian ifinfo.if_index = if_index; 6131bbf741cSflorian ifinfo.link_state = ifm->ifm_data.ifi_link_state; 6141bbf741cSflorian ifinfo.rdomain = ifm->ifm_tableid; 6151bbf741cSflorian ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == 6161bbf741cSflorian (IFF_UP | IFF_RUNNING); 61757419a7fSflorian 618a13fc78dSflorian if (sdl != NULL && (sdl->sdl_type == IFT_ETHER || 619a13fc78dSflorian sdl->sdl_type == IFT_CARP) && sdl->sdl_alen == ETHER_ADDR_LEN) 6201bbf741cSflorian memcpy(ifinfo.hw_address.ether_addr_octet, LLADDR(sdl), 6211bbf741cSflorian ETHER_ADDR_LEN); 62248e1b614Sflorian else if (iface == NULL) { 6231bbf741cSflorian log_warnx("Could not find AF_LINK address for %s.", if_name); 6241bbf741cSflorian return; 6254fd2b0e0Sflorian } 6261bbf741cSflorian 6271bbf741cSflorian if (iface == NULL) { 6284fd2b0e0Sflorian if ((iface = calloc(1, sizeof(*iface))) == NULL) 6294fd2b0e0Sflorian fatal("calloc"); 6304fd2b0e0Sflorian iface->udpsock = -1; 6314fd2b0e0Sflorian LIST_INSERT_HEAD(&interfaces, iface, entries); 6324fd2b0e0Sflorian frontend_imsg_compose_main(IMSG_OPEN_BPFSOCK, 0, 6334fd2b0e0Sflorian &if_index, sizeof(if_index)); 6341bbf741cSflorian } else { 6351bbf741cSflorian if (iface->ifinfo.rdomain != ifinfo.rdomain && 6361bbf741cSflorian iface->udpsock != -1) { 6371bbf741cSflorian close(iface->udpsock); 6381bbf741cSflorian iface->udpsock = -1; 6391bbf741cSflorian } 6404fd2b0e0Sflorian } 6414fd2b0e0Sflorian 6421bbf741cSflorian if (memcmp(&iface->ifinfo, &ifinfo, sizeof(iface->ifinfo)) != 0) { 6431bbf741cSflorian memcpy(&iface->ifinfo, &ifinfo, sizeof(iface->ifinfo)); 6441bbf741cSflorian frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &iface->ifinfo, 6451bbf741cSflorian sizeof(iface->ifinfo)); 6461bbf741cSflorian } 64757419a7fSflorian } 64857419a7fSflorian 64957419a7fSflorian void 65057419a7fSflorian frontend_startup(void) 65157419a7fSflorian { 65257419a7fSflorian if (!event_initialized(&ev_route)) 65357419a7fSflorian fatalx("%s: did not receive a route socket from the main " 65457419a7fSflorian "process", __func__); 65557419a7fSflorian 6561bbf741cSflorian init_ifaces(); 65748e1b614Sflorian if (pledge("stdio unix recvfd", NULL) == -1) 65848e1b614Sflorian fatal("pledge"); 65957419a7fSflorian event_add(&ev_route, NULL); 6601bbf741cSflorian } 6611bbf741cSflorian 6621bbf741cSflorian void 6631bbf741cSflorian init_ifaces(void) 6641bbf741cSflorian { 6651bbf741cSflorian struct iface *iface; 6661bbf741cSflorian struct imsg_ifinfo ifinfo; 6671bbf741cSflorian struct if_nameindex *ifnidxp, *ifnidx; 6681bbf741cSflorian struct ifaddrs *ifap, *ifa; 6691bbf741cSflorian uint32_t if_index; 6701bbf741cSflorian int flags, xflags; 6711bbf741cSflorian char *if_name; 67257419a7fSflorian 67357419a7fSflorian if ((ifnidxp = if_nameindex()) == NULL) 67457419a7fSflorian fatalx("if_nameindex"); 67557419a7fSflorian 6761bbf741cSflorian if (getifaddrs(&ifap) != 0) 6771bbf741cSflorian fatal("getifaddrs"); 67857419a7fSflorian 6791bbf741cSflorian for (ifnidx = ifnidxp; ifnidx->if_index != 0 && ifnidx->if_name != NULL; 6801bbf741cSflorian ifnidx++) { 6811bbf741cSflorian if_index = ifnidx->if_index; 6821bbf741cSflorian if_name = ifnidx->if_name; 6831bbf741cSflorian if ((flags = get_flags(if_name)) == -1) 6841bbf741cSflorian continue; 6851bbf741cSflorian if ((xflags = get_xflags(if_name)) == -1) 6861bbf741cSflorian continue; 6871bbf741cSflorian if (!(xflags & IFXF_AUTOCONF4)) 6881bbf741cSflorian continue; 6891bbf741cSflorian 6901bbf741cSflorian memset(&ifinfo, 0, sizeof(ifinfo)); 6911bbf741cSflorian ifinfo.if_index = if_index; 6921bbf741cSflorian ifinfo.link_state = -1; 6931bbf741cSflorian ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == 6941bbf741cSflorian (IFF_UP | IFF_RUNNING); 6951bbf741cSflorian 6961bbf741cSflorian for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 6971bbf741cSflorian if (strcmp(if_name, ifa->ifa_name) != 0) 6981bbf741cSflorian continue; 6991bbf741cSflorian if (ifa->ifa_addr == NULL) 7001bbf741cSflorian continue; 7011bbf741cSflorian 7021bbf741cSflorian switch (ifa->ifa_addr->sa_family) { 7031bbf741cSflorian case AF_LINK: { 7041bbf741cSflorian struct if_data *if_data; 7051bbf741cSflorian struct sockaddr_dl *sdl; 7061bbf741cSflorian 7071bbf741cSflorian sdl = (struct sockaddr_dl *)ifa->ifa_addr; 708a13fc78dSflorian if ((sdl->sdl_type != IFT_ETHER && 709a13fc78dSflorian sdl->sdl_type != IFT_CARP) || 7101bbf741cSflorian sdl->sdl_alen != ETHER_ADDR_LEN) 7111bbf741cSflorian continue; 7121bbf741cSflorian memcpy(ifinfo.hw_address.ether_addr_octet, 7131bbf741cSflorian LLADDR(sdl), ETHER_ADDR_LEN); 7141bbf741cSflorian 7151bbf741cSflorian if_data = (struct if_data *)ifa->ifa_data; 7161bbf741cSflorian ifinfo.link_state = if_data->ifi_link_state; 7171bbf741cSflorian ifinfo.rdomain = if_data->ifi_rdomain; 7181bbf741cSflorian goto out; 7191bbf741cSflorian } 7201bbf741cSflorian default: 7211bbf741cSflorian break; 7221bbf741cSflorian } 7231bbf741cSflorian } 7241bbf741cSflorian out: 7251bbf741cSflorian if (ifinfo.link_state == -1) 7261bbf741cSflorian /* no AF_LINK found */ 7271bbf741cSflorian continue; 7281bbf741cSflorian 7291bbf741cSflorian if ((iface = calloc(1, sizeof(*iface))) == NULL) 7301bbf741cSflorian fatal("calloc"); 7311bbf741cSflorian iface->udpsock = -1; 7321bbf741cSflorian memcpy(&iface->ifinfo, &ifinfo, sizeof(iface->ifinfo)); 7331bbf741cSflorian LIST_INSERT_HEAD(&interfaces, iface, entries); 7341bbf741cSflorian frontend_imsg_compose_main(IMSG_OPEN_BPFSOCK, 0, 7351bbf741cSflorian &if_index, sizeof(if_index)); 7361bbf741cSflorian frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &iface->ifinfo, 7371bbf741cSflorian sizeof(iface->ifinfo)); 7381bbf741cSflorian } 7391bbf741cSflorian 7401bbf741cSflorian freeifaddrs(ifap); 74157419a7fSflorian if_freenameindex(ifnidxp); 74257419a7fSflorian } 74357419a7fSflorian 74457419a7fSflorian void 74557419a7fSflorian route_receive(int fd, short events, void *arg) 74657419a7fSflorian { 74757419a7fSflorian static uint8_t *buf; 74857419a7fSflorian 74957419a7fSflorian struct rt_msghdr *rtm; 75057419a7fSflorian struct sockaddr *sa, *rti_info[RTAX_MAX]; 75157419a7fSflorian ssize_t n; 75257419a7fSflorian 75357419a7fSflorian if (buf == NULL) { 75457419a7fSflorian buf = malloc(ROUTE_SOCKET_BUF_SIZE); 75557419a7fSflorian if (buf == NULL) 75657419a7fSflorian fatal("malloc"); 75757419a7fSflorian } 75857419a7fSflorian rtm = (struct rt_msghdr *)buf; 75957419a7fSflorian if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) { 76057419a7fSflorian if (errno == EAGAIN || errno == EINTR) 76157419a7fSflorian return; 76257419a7fSflorian log_warn("dispatch_rtmsg: read error"); 76357419a7fSflorian return; 76457419a7fSflorian } 76557419a7fSflorian 76657419a7fSflorian if (n == 0) 76757419a7fSflorian fatal("routing socket closed"); 76857419a7fSflorian 76957419a7fSflorian if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) { 77057419a7fSflorian log_warnx("partial rtm of %zd in buffer", n); 77157419a7fSflorian return; 77257419a7fSflorian } 77357419a7fSflorian 77457419a7fSflorian if (rtm->rtm_version != RTM_VERSION) 77557419a7fSflorian return; 77657419a7fSflorian 77757419a7fSflorian sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen); 77857419a7fSflorian get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 77957419a7fSflorian 78057419a7fSflorian handle_route_message(rtm, rti_info); 78157419a7fSflorian } 78257419a7fSflorian 78357419a7fSflorian void 78457419a7fSflorian handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) 78557419a7fSflorian { 78648e1b614Sflorian struct sockaddr_dl *sdl = NULL; 787d3097762Sflorian struct if_announcemsghdr *ifan; 788d3097762Sflorian uint32_t if_index; 789d3097762Sflorian 79057419a7fSflorian switch (rtm->rtm_type) { 79157419a7fSflorian case RTM_IFINFO: 79248e1b614Sflorian if (rtm->rtm_addrs & RTA_IFP && rti_info[RTAX_IFP]->sa_family 79348e1b614Sflorian == AF_LINK) 79448e1b614Sflorian sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 79548e1b614Sflorian update_iface((struct if_msghdr *)rtm, sdl); 79657419a7fSflorian break; 797d3097762Sflorian case RTM_IFANNOUNCE: 798d3097762Sflorian ifan = (struct if_announcemsghdr *)rtm; 799d3097762Sflorian if_index = ifan->ifan_index; 800d3097762Sflorian if (ifan->ifan_what == IFAN_DEPARTURE) { 801d3097762Sflorian frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0, 802d3097762Sflorian &if_index, sizeof(if_index)); 803d3097762Sflorian remove_iface(if_index); 804d3097762Sflorian } 805d3097762Sflorian break; 80657419a7fSflorian case RTM_PROPOSAL: 80757419a7fSflorian if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) { 80857419a7fSflorian log_debug("RTP_PROPOSAL_SOLICIT"); 80957419a7fSflorian frontend_imsg_compose_engine(IMSG_REPROPOSE_RDNS, 81057419a7fSflorian 0, 0, NULL, 0); 811c7313d44Sflorian } 812c7313d44Sflorian #ifndef SMALL 813c7313d44Sflorian else if (rtm->rtm_flags & RTF_PROTO3) { 814bc837866Sflorian char ifnamebuf[IF_NAMESIZE], *if_name; 815bc837866Sflorian 816bc837866Sflorian if_index = rtm->rtm_index; 817bc837866Sflorian if_name = if_indextoname(if_index, ifnamebuf); 818bc837866Sflorian log_warnx("\"dhclient %s\" ran, requesting new lease", 819bc837866Sflorian if_name != NULL ? if_name : "(unknown)"); 820c7313d44Sflorian frontend_imsg_compose_engine(IMSG_REQUEST_REBOOT, 821bc837866Sflorian 0, 0, &if_index, sizeof(if_index)); 82257419a7fSflorian } 823c7313d44Sflorian #endif /* SMALL */ 82457419a7fSflorian break; 82557419a7fSflorian default: 82657419a7fSflorian log_debug("unexpected RTM: %d", rtm->rtm_type); 82757419a7fSflorian break; 82857419a7fSflorian } 82957419a7fSflorian } 83057419a7fSflorian 83157419a7fSflorian #define ROUNDUP(a) \ 83257419a7fSflorian ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 83357419a7fSflorian 83457419a7fSflorian void 83557419a7fSflorian get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 83657419a7fSflorian { 83757419a7fSflorian int i; 83857419a7fSflorian 83957419a7fSflorian for (i = 0; i < RTAX_MAX; i++) { 84057419a7fSflorian if (addrs & (1 << i)) { 84157419a7fSflorian rti_info[i] = sa; 84257419a7fSflorian sa = (struct sockaddr *)((char *)(sa) + 84357419a7fSflorian ROUNDUP(sa->sa_len)); 84457419a7fSflorian } else 84557419a7fSflorian rti_info[i] = NULL; 84657419a7fSflorian } 84757419a7fSflorian } 84857419a7fSflorian 84957419a7fSflorian void 85057419a7fSflorian bpf_receive(int fd, short events, void *arg) 85157419a7fSflorian { 85257419a7fSflorian struct bpf_hdr *hdr; 85357419a7fSflorian struct imsg_dhcp imsg_dhcp; 85457419a7fSflorian struct iface *iface; 85557419a7fSflorian ssize_t len, rem; 85657419a7fSflorian uint8_t *p; 85757419a7fSflorian 85857419a7fSflorian iface = (struct iface *)arg; 85957419a7fSflorian 86057419a7fSflorian if ((len = read(fd, iface->bpfev.buf, BPFLEN)) == -1) { 86137fb58f6Sflorian log_warn("%s: read", __func__); 86257419a7fSflorian return; 86357419a7fSflorian } 864e998cdbeSflorian 865e998cdbeSflorian if (len == 0) 866e998cdbeSflorian fatal("%s len == 0", __func__); 86757419a7fSflorian 86857419a7fSflorian memset(&imsg_dhcp, 0, sizeof(imsg_dhcp)); 8691bbf741cSflorian imsg_dhcp.if_index = iface->ifinfo.if_index; 87057419a7fSflorian 87157419a7fSflorian rem = len; 87257419a7fSflorian p = iface->bpfev.buf; 87357419a7fSflorian 87457419a7fSflorian while (rem > 0) { 87557419a7fSflorian if ((size_t)rem < sizeof(*hdr)) { 87657419a7fSflorian log_warnx("packet too short"); 87757419a7fSflorian return; 87857419a7fSflorian } 87957419a7fSflorian hdr = (struct bpf_hdr *)p; 88057419a7fSflorian if (hdr->bh_caplen != hdr->bh_datalen) { 88157419a7fSflorian log_warnx("skipping truncated packet"); 88257419a7fSflorian goto cont; 88357419a7fSflorian } 88457419a7fSflorian if (rem < hdr->bh_hdrlen + hdr->bh_caplen) 88557419a7fSflorian /* we are done */ 88657419a7fSflorian break; 88757419a7fSflorian if (hdr->bh_caplen > sizeof(imsg_dhcp.packet)) { 88857419a7fSflorian log_warn("packet too big"); 88957419a7fSflorian goto cont; 89057419a7fSflorian } 89157419a7fSflorian memcpy(&imsg_dhcp.packet, p + hdr->bh_hdrlen, hdr->bh_caplen); 89257419a7fSflorian imsg_dhcp.len = hdr->bh_caplen; 89357419a7fSflorian frontend_imsg_compose_engine(IMSG_DHCP, 0, 0, &imsg_dhcp, 89457419a7fSflorian sizeof(imsg_dhcp)); 89557419a7fSflorian cont: 89657419a7fSflorian p += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen); 89757419a7fSflorian rem -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen); 89857419a7fSflorian 89957419a7fSflorian } 90057419a7fSflorian } 90157419a7fSflorian 90282a5f3d7Sflorian void 90382a5f3d7Sflorian iface_data_from_imsg(struct iface* iface, struct imsg_req_dhcp *imsg) 90482a5f3d7Sflorian { 90582a5f3d7Sflorian iface->xid = imsg->xid; 906b2b40540Sflorian iface->ciaddr = imsg->ciaddr; 907b2b40540Sflorian iface->requested_ip = imsg->requested_ip; 908b2b40540Sflorian iface->server_identifier = imsg->server_identifier; 909b2b40540Sflorian iface->dhcp_server = imsg->dhcp_server; 91082a5f3d7Sflorian } 91182a5f3d7Sflorian 91257419a7fSflorian ssize_t 913a41cc082Sflorian build_packet(uint8_t message_type, char *if_name, uint32_t xid, 91482a5f3d7Sflorian struct ether_addr *hw_address, struct in_addr *ciaddr, struct in_addr 91582a5f3d7Sflorian *requested_ip, struct in_addr *server_identifier) 91657419a7fSflorian { 91757419a7fSflorian static uint8_t dhcp_cookie[] = DHCP_COOKIE; 91857419a7fSflorian static uint8_t dhcp_message_type[] = {DHO_DHCP_MESSAGE_TYPE, 1, 91957419a7fSflorian DHCPDISCOVER}; 920*b3441518Sflorian static uint8_t dhcp_hostname[255 + 2] = {DHO_HOST_NAME, 0 /*, ... */}; 92157419a7fSflorian static uint8_t dhcp_client_id[] = {DHO_DHCP_CLIENT_IDENTIFIER, 7, 92257419a7fSflorian HTYPE_ETHER, 0, 0, 0, 0, 0, 0}; 92357419a7fSflorian static uint8_t dhcp_req_list[] = {DHO_DHCP_PARAMETER_REQUEST_LIST, 924ea86c963Sflorian 8, DHO_SUBNET_MASK, DHO_ROUTERS, DHO_DOMAIN_NAME_SERVERS, 92557419a7fSflorian DHO_HOST_NAME, DHO_DOMAIN_NAME, DHO_BROADCAST_ADDRESS, 926ea86c963Sflorian DHO_DOMAIN_SEARCH, DHO_CLASSLESS_STATIC_ROUTES}; 92757419a7fSflorian static uint8_t dhcp_requested_address[] = {DHO_DHCP_REQUESTED_ADDRESS, 92857419a7fSflorian 4, 0, 0, 0, 0}; 92957419a7fSflorian static uint8_t dhcp_server_identifier[] = {DHO_DHCP_SERVER_IDENTIFIER, 93057419a7fSflorian 4, 0, 0, 0, 0}; 931a41cc082Sflorian #ifndef SMALL 932a41cc082Sflorian struct iface_conf *iface_conf; 933a41cc082Sflorian #endif /* SMALL */ 93457419a7fSflorian struct dhcp_hdr *hdr; 9352d2edb0eSflorian ssize_t len; 93657419a7fSflorian uint8_t *p; 93757419a7fSflorian char *c; 93857419a7fSflorian 939a41cc082Sflorian #ifndef SMALL 940a41cc082Sflorian iface_conf = find_iface_conf(&frontend_conf->iface_list, if_name); 941a41cc082Sflorian #endif /* SMALL */ 942a41cc082Sflorian 94357419a7fSflorian memset(dhcp_packet, 0, sizeof(dhcp_packet)); 94457419a7fSflorian dhcp_message_type[2] = message_type; 94557419a7fSflorian p = dhcp_packet; 94657419a7fSflorian hdr = (struct dhcp_hdr *)p; 94757419a7fSflorian hdr->op = DHCP_BOOTREQUEST; 94857419a7fSflorian hdr->htype = HTYPE_ETHER; 94957419a7fSflorian hdr->hlen = 6; 95057419a7fSflorian hdr->hops = 0; 951c2da98a6Sflorian hdr->xid = htonl(xid); 95257419a7fSflorian hdr->secs = 0; 953b2b40540Sflorian hdr->ciaddr = *ciaddr; 95457419a7fSflorian memcpy(hdr->chaddr, hw_address, sizeof(*hw_address)); 95557419a7fSflorian p += sizeof(struct dhcp_hdr); 95657419a7fSflorian memcpy(p, dhcp_cookie, sizeof(dhcp_cookie)); 95757419a7fSflorian p += sizeof(dhcp_cookie); 95857419a7fSflorian memcpy(p, dhcp_message_type, sizeof(dhcp_message_type)); 95957419a7fSflorian p += sizeof(dhcp_message_type); 960*b3441518Sflorian 961*b3441518Sflorian #ifndef SMALL 962*b3441518Sflorian if (iface_conf != NULL && iface_conf->h_name != NULL) { 963*b3441518Sflorian if (iface_conf->h_name[0] != '\0') { 964*b3441518Sflorian dhcp_hostname[1] = strlen(iface_conf->h_name); 965*b3441518Sflorian memcpy(dhcp_hostname + 2, iface_conf->h_name, 966*b3441518Sflorian strlen(iface_conf->h_name)); 967*b3441518Sflorian memcpy(p, dhcp_hostname, dhcp_hostname[1] + 2); 968*b3441518Sflorian p += dhcp_hostname[1] + 2; 969*b3441518Sflorian } 970*b3441518Sflorian } else 971*b3441518Sflorian #endif /* SMALL */ 972*b3441518Sflorian { 973*b3441518Sflorian if (gethostname(dhcp_hostname + 2, 974*b3441518Sflorian sizeof(dhcp_hostname) - 2) == 0) { 97557419a7fSflorian if ((c = strchr(dhcp_hostname + 2, '.')) != NULL) 97657419a7fSflorian *c = '\0'; 97757419a7fSflorian dhcp_hostname[1] = strlen(dhcp_hostname + 2); 97857419a7fSflorian memcpy(p, dhcp_hostname, dhcp_hostname[1] + 2); 97957419a7fSflorian p += dhcp_hostname[1] + 2; 98057419a7fSflorian } 981*b3441518Sflorian } 982a41cc082Sflorian 983a41cc082Sflorian #ifndef SMALL 984a41cc082Sflorian if (iface_conf != NULL) { 985a41cc082Sflorian if (iface_conf->c_id_len > 0) { 986a41cc082Sflorian /* XXX check space */ 987a41cc082Sflorian memcpy(p, iface_conf->c_id, iface_conf->c_id_len); 988a41cc082Sflorian p += iface_conf->c_id_len; 98990c58abaSflorian } else { 99090c58abaSflorian memcpy(dhcp_client_id + 3, hw_address, sizeof(*hw_address)); 99190c58abaSflorian memcpy(p, dhcp_client_id, sizeof(dhcp_client_id)); 99290c58abaSflorian p += sizeof(dhcp_client_id); 993a41cc082Sflorian } 994a41cc082Sflorian if (iface_conf->vc_id_len > 0) { 995a41cc082Sflorian /* XXX check space */ 996a41cc082Sflorian memcpy(p, iface_conf->vc_id, iface_conf->vc_id_len); 997a41cc082Sflorian p += iface_conf->vc_id_len; 998a41cc082Sflorian } 999a41cc082Sflorian } else 1000a41cc082Sflorian #endif /* SMALL */ 1001a41cc082Sflorian { 100257419a7fSflorian memcpy(dhcp_client_id + 3, hw_address, sizeof(*hw_address)); 100357419a7fSflorian memcpy(p, dhcp_client_id, sizeof(dhcp_client_id)); 100457419a7fSflorian p += sizeof(dhcp_client_id); 1005a41cc082Sflorian } 100657419a7fSflorian memcpy(p, dhcp_req_list, sizeof(dhcp_req_list)); 100757419a7fSflorian p += sizeof(dhcp_req_list); 100857419a7fSflorian 100982a5f3d7Sflorian if (requested_ip->s_addr != INADDR_ANY) { 101057419a7fSflorian memcpy(dhcp_requested_address + 2, requested_ip, 101157419a7fSflorian sizeof(*requested_ip)); 101257419a7fSflorian memcpy(p, dhcp_requested_address, 101357419a7fSflorian sizeof(dhcp_requested_address)); 101457419a7fSflorian p += sizeof(dhcp_requested_address); 101582a5f3d7Sflorian } 101657419a7fSflorian 101757419a7fSflorian if (server_identifier->s_addr != INADDR_ANY) { 101857419a7fSflorian memcpy(dhcp_server_identifier + 2, server_identifier, 101957419a7fSflorian sizeof(*server_identifier)); 102057419a7fSflorian memcpy(p, dhcp_server_identifier, 102157419a7fSflorian sizeof(dhcp_server_identifier)); 102257419a7fSflorian p += sizeof(dhcp_server_identifier); 102357419a7fSflorian } 102457419a7fSflorian 102557419a7fSflorian *p = DHO_END; 102657419a7fSflorian p += 1; 102757419a7fSflorian 10282d2edb0eSflorian len = p - dhcp_packet; 10292d2edb0eSflorian 10302d2edb0eSflorian /* dhcp_packet is initialized with DHO_PADs */ 10312d2edb0eSflorian if (len < BOOTP_MIN_LEN) 10322d2edb0eSflorian len = BOOTP_MIN_LEN; 10332d2edb0eSflorian 10342d2edb0eSflorian return (len); 103557419a7fSflorian } 103657419a7fSflorian 103757419a7fSflorian void 103882a5f3d7Sflorian send_packet(uint8_t message_type, struct iface *iface) 103957419a7fSflorian { 104057419a7fSflorian ssize_t pkt_len; 1041e998cdbeSflorian char ifnamebuf[IF_NAMESIZE], *if_name; 104257419a7fSflorian 104357419a7fSflorian if (!event_initialized(&iface->bpfev.ev)) { 104457419a7fSflorian iface->send_discover = 1; 104557419a7fSflorian return; 104657419a7fSflorian } 104782a5f3d7Sflorian 104857419a7fSflorian iface->send_discover = 0; 1049e998cdbeSflorian 105082a5f3d7Sflorian if ((if_name = if_indextoname(iface->ifinfo.if_index, ifnamebuf)) == NULL) 105182a5f3d7Sflorian return; /* iface went away, nothing to do */ 1052e998cdbeSflorian 105382a5f3d7Sflorian log_debug("%s on %s", message_type == DHCPDISCOVER ? "DHCPDISCOVER" : 105482a5f3d7Sflorian "DHCPREQUEST", if_name); 105557419a7fSflorian 105682a5f3d7Sflorian pkt_len = build_packet(message_type, if_name, iface->xid, 105782a5f3d7Sflorian &iface->ifinfo.hw_address, &iface->ciaddr, &iface->requested_ip, 10581bbf741cSflorian &iface->server_identifier); 1059c645071eSflorian if (iface->dhcp_server.s_addr != INADDR_ANY) { 1060c645071eSflorian if (udp_send_packet(iface, dhcp_packet, pkt_len) == -1) 1061c645071eSflorian bpf_send_packet(iface, dhcp_packet, pkt_len); 1062c645071eSflorian } else 106357419a7fSflorian bpf_send_packet(iface, dhcp_packet, pkt_len); 106457419a7fSflorian } 106557419a7fSflorian 1066c645071eSflorian int 106757419a7fSflorian udp_send_packet(struct iface *iface, uint8_t *packet, ssize_t len) 106857419a7fSflorian { 106957419a7fSflorian struct sockaddr_in to; 107057419a7fSflorian 107157419a7fSflorian memset(&to, 0, sizeof(to)); 107257419a7fSflorian to.sin_family = AF_INET; 107357419a7fSflorian to.sin_len = sizeof(to); 1074b2b40540Sflorian to.sin_addr = iface->dhcp_server; 107557419a7fSflorian to.sin_port = ntohs(SERVER_PORT); 107657419a7fSflorian 107757419a7fSflorian if (sendto(iface->udpsock, packet, len, 0, (struct sockaddr *)&to, 1078c645071eSflorian sizeof(to)) == -1) { 107957419a7fSflorian log_warn("sendto"); 1080c645071eSflorian return -1; 1081c645071eSflorian } 1082c645071eSflorian return 0; 108357419a7fSflorian } 108457419a7fSflorian void 108557419a7fSflorian bpf_send_packet(struct iface *iface, uint8_t *packet, ssize_t len) 108657419a7fSflorian { 108757419a7fSflorian struct iovec iov[4]; 108857419a7fSflorian struct ether_header eh; 108957419a7fSflorian struct ip ip; 109057419a7fSflorian struct udphdr udp; 109157419a7fSflorian ssize_t total, result; 109257419a7fSflorian int iovcnt = 0, i; 109357419a7fSflorian 109457419a7fSflorian memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); 10951bbf741cSflorian memcpy(eh.ether_shost, &iface->ifinfo.hw_address, 10961bbf741cSflorian sizeof(eh.ether_dhost)); 109757419a7fSflorian eh.ether_type = htons(ETHERTYPE_IP); 109857419a7fSflorian iov[0].iov_base = &eh; 109957419a7fSflorian iov[0].iov_len = sizeof(eh); 110057419a7fSflorian iovcnt++; 110157419a7fSflorian 110257419a7fSflorian ip.ip_v = 4; 110357419a7fSflorian ip.ip_hl = 5; 110457419a7fSflorian ip.ip_tos = IPTOS_LOWDELAY; 110557419a7fSflorian ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len); 110657419a7fSflorian ip.ip_id = 0; 110757419a7fSflorian ip.ip_off = 0; 110857419a7fSflorian ip.ip_ttl = 128; 110957419a7fSflorian ip.ip_p = IPPROTO_UDP; 111057419a7fSflorian ip.ip_sum = 0; 1111b2b40540Sflorian ip.ip_src.s_addr = INADDR_ANY; 111257419a7fSflorian ip.ip_dst.s_addr = INADDR_BROADCAST; 111357419a7fSflorian ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0)); 111457419a7fSflorian iov[iovcnt].iov_base = &ip; 111557419a7fSflorian iov[iovcnt].iov_len = sizeof(ip); 111657419a7fSflorian iovcnt++; 111757419a7fSflorian 111857419a7fSflorian udp.uh_sport = htons(CLIENT_PORT); 111957419a7fSflorian udp.uh_dport = htons(SERVER_PORT); 112057419a7fSflorian udp.uh_ulen = htons(sizeof(udp) + len); 112157419a7fSflorian udp.uh_sum = 0; 112257419a7fSflorian udp.uh_sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp), 112357419a7fSflorian checksum((unsigned char *)packet, len, 112457419a7fSflorian checksum((unsigned char *)&ip.ip_src, 112557419a7fSflorian 2 * sizeof(ip.ip_src), 112657419a7fSflorian IPPROTO_UDP + (uint32_t)ntohs(udp.uh_ulen))))); 112757419a7fSflorian iov[iovcnt].iov_base = &udp; 112857419a7fSflorian iov[iovcnt].iov_len = sizeof(udp); 112957419a7fSflorian iovcnt++; 113057419a7fSflorian 113157419a7fSflorian iov[iovcnt].iov_base = packet; 113257419a7fSflorian iov[iovcnt].iov_len = len; 113357419a7fSflorian iovcnt++; 113457419a7fSflorian 113557419a7fSflorian total = 0; 113657419a7fSflorian for (i = 0; i < iovcnt; i++) 113757419a7fSflorian total += iov[i].iov_len; 113857419a7fSflorian 113957419a7fSflorian result = writev(EVENT_FD(&iface->bpfev.ev), iov, iovcnt); 114057419a7fSflorian if (result == -1) 114157419a7fSflorian log_warn("%s: writev", __func__); 114257419a7fSflorian else if (result < total) { 114357419a7fSflorian log_warnx("%s, writev: %zd of %zd bytes", __func__, result, 114457419a7fSflorian total); 114557419a7fSflorian } 114657419a7fSflorian } 114757419a7fSflorian 114857419a7fSflorian struct iface* 114957419a7fSflorian get_iface_by_id(uint32_t if_index) 115057419a7fSflorian { 115157419a7fSflorian struct iface *iface; 115257419a7fSflorian 115357419a7fSflorian LIST_FOREACH (iface, &interfaces, entries) { 11541bbf741cSflorian if (iface->ifinfo.if_index == if_index) 115557419a7fSflorian return (iface); 115657419a7fSflorian } 115757419a7fSflorian 115857419a7fSflorian return (NULL); 115957419a7fSflorian } 116057419a7fSflorian 116157419a7fSflorian void 116257419a7fSflorian remove_iface(uint32_t if_index) 116357419a7fSflorian { 116457419a7fSflorian struct iface *iface; 116557419a7fSflorian 116657419a7fSflorian iface = get_iface_by_id(if_index); 116757419a7fSflorian 116857419a7fSflorian if (iface == NULL) 116957419a7fSflorian return; 117057419a7fSflorian 117157419a7fSflorian LIST_REMOVE(iface, entries); 117257419a7fSflorian event_del(&iface->bpfev.ev); 117357419a7fSflorian close(EVENT_FD(&iface->bpfev.ev)); 117457419a7fSflorian if (iface->udpsock != -1) 117557419a7fSflorian close(iface->udpsock); 117657419a7fSflorian free(iface); 117757419a7fSflorian } 117857419a7fSflorian 117957419a7fSflorian void 118057419a7fSflorian set_bpfsock(int bpfsock, uint32_t if_index) 118157419a7fSflorian { 118257419a7fSflorian struct iface *iface; 118357419a7fSflorian 118457419a7fSflorian if ((iface = get_iface_by_id(if_index)) == NULL) { 118557419a7fSflorian /* 118657419a7fSflorian * The interface disappeared while we were waiting for the 118757419a7fSflorian * parent process to open the raw socket. 118857419a7fSflorian */ 118957419a7fSflorian close(bpfsock); 119057419a7fSflorian } else { 119157419a7fSflorian event_set(&iface->bpfev.ev, bpfsock, EV_READ | 119257419a7fSflorian EV_PERSIST, bpf_receive, iface); 119357419a7fSflorian event_add(&iface->bpfev.ev, NULL); 119457419a7fSflorian if (iface->send_discover) 119582a5f3d7Sflorian send_packet(DHCPDISCOVER, iface); 119657419a7fSflorian } 119757419a7fSflorian } 1198a41cc082Sflorian 1199a41cc082Sflorian #ifndef SMALL 1200a41cc082Sflorian struct iface_conf* 1201a41cc082Sflorian find_iface_conf(struct iface_conf_head *head, char *if_name) 1202a41cc082Sflorian { 1203a41cc082Sflorian struct iface_conf *iface_conf; 1204a41cc082Sflorian 1205a41cc082Sflorian if (if_name == NULL) 1206a41cc082Sflorian return (NULL); 1207a41cc082Sflorian 1208a41cc082Sflorian SIMPLEQ_FOREACH(iface_conf, head, entry) { 1209a41cc082Sflorian if (strcmp(iface_conf->name, if_name) == 0) 1210a41cc082Sflorian return iface_conf; 1211a41cc082Sflorian } 1212a41cc082Sflorian return (NULL); 1213a41cc082Sflorian } 1214580befd2Sflorian 1215580befd2Sflorian int* 1216580befd2Sflorian changed_ifaces(struct dhcpleased_conf *oconf, struct dhcpleased_conf *nconf) 1217580befd2Sflorian { 1218580befd2Sflorian struct iface_conf *iface_conf, *oiface_conf; 1219580befd2Sflorian int *ret, if_index, count = 0, i = 0; 1220580befd2Sflorian 1221580befd2Sflorian /* 1222580befd2Sflorian * Worst case: All old interfaces replaced with new interfaces. 1223580befd2Sflorian * This should still be a small number 1224580befd2Sflorian */ 1225580befd2Sflorian SIMPLEQ_FOREACH(iface_conf, &oconf->iface_list, entry) 1226580befd2Sflorian count++; 1227580befd2Sflorian SIMPLEQ_FOREACH(iface_conf, &nconf->iface_list, entry) 1228580befd2Sflorian count++; 1229580befd2Sflorian 1230580befd2Sflorian ret = calloc(count + 1, sizeof(int)); 1231580befd2Sflorian 1232580befd2Sflorian SIMPLEQ_FOREACH(iface_conf, &nconf->iface_list, entry) { 1233580befd2Sflorian if ((if_index = if_nametoindex(iface_conf->name)) == 0) 1234580befd2Sflorian continue; 1235580befd2Sflorian oiface_conf = find_iface_conf(&oconf->iface_list, 1236580befd2Sflorian iface_conf->name); 1237580befd2Sflorian if (oiface_conf == NULL) { 1238580befd2Sflorian /* new interface added to config */ 1239580befd2Sflorian ret[i++] = if_index; 1240580befd2Sflorian } else if (iface_conf_cmp(iface_conf, oiface_conf) != 0) { 1241580befd2Sflorian /* interface conf changed */ 1242580befd2Sflorian ret[i++] = if_index; 1243580befd2Sflorian } 1244580befd2Sflorian } 1245580befd2Sflorian SIMPLEQ_FOREACH(oiface_conf, &oconf->iface_list, entry) { 1246580befd2Sflorian if ((if_index = if_nametoindex(oiface_conf->name)) == 0) 1247580befd2Sflorian continue; 1248580befd2Sflorian if (find_iface_conf(&nconf->iface_list, oiface_conf->name) == 1249580befd2Sflorian NULL) { 1250580befd2Sflorian /* interface removed from config */ 1251580befd2Sflorian ret[i++] = if_index; 1252580befd2Sflorian } 1253580befd2Sflorian } 1254580befd2Sflorian return ret; 1255580befd2Sflorian } 1256580befd2Sflorian 1257580befd2Sflorian int 1258580befd2Sflorian iface_conf_cmp(struct iface_conf *a, struct iface_conf *b) 1259580befd2Sflorian { 1260580befd2Sflorian if (a->vc_id_len != b->vc_id_len) 1261580befd2Sflorian return 1; 1262580befd2Sflorian if (memcmp(a->vc_id, b->vc_id, a->vc_id_len) != 0) 1263580befd2Sflorian return 1; 1264580befd2Sflorian if (a->c_id_len != b->c_id_len) 1265580befd2Sflorian return 1; 1266580befd2Sflorian if (memcmp(a->c_id, b->c_id, a->c_id_len) != 0) 1267580befd2Sflorian return 1; 1268*b3441518Sflorian if (a->h_name == NULL || b->h_name == NULL) 1269*b3441518Sflorian return 1; 1270*b3441518Sflorian if (strcmp(a->h_name, b->h_name) != 0) 1271*b3441518Sflorian return 1; 1272c2bc6c6dSflorian if (a->ignore != b->ignore) 1273c2bc6c6dSflorian return 1; 1274c2bc6c6dSflorian if (a->ignore_servers_len != b->ignore_servers_len) 1275c2bc6c6dSflorian return 1; 1276c2bc6c6dSflorian if (memcmp(a->ignore_servers, b->ignore_servers, 1277c2bc6c6dSflorian a->ignore_servers_len * sizeof (struct in_addr)) != 0) 1278c2bc6c6dSflorian return 1; 1279580befd2Sflorian return 0; 1280580befd2Sflorian } 1281a41cc082Sflorian #endif /* SMALL */ 1282