1*0c40990eSflorian /* $OpenBSD: engine.c,v 1.4 2018/07/11 14:03:13 florian Exp $ */ 253293e44Sflorian 353293e44Sflorian /* 453293e44Sflorian * Copyright (c) 2018 Florian Obser <florian@openbsd.org> 553293e44Sflorian * Copyright (c) 2004, 2005 Claudio Jeker <claudio@openbsd.org> 653293e44Sflorian * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 753293e44Sflorian * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 853293e44Sflorian * 953293e44Sflorian * Permission to use, copy, modify, and distribute this software for any 1053293e44Sflorian * purpose with or without fee is hereby granted, provided that the above 1153293e44Sflorian * copyright notice and this permission notice appear in all copies. 1253293e44Sflorian * 1353293e44Sflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1453293e44Sflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1553293e44Sflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1653293e44Sflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1753293e44Sflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1853293e44Sflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1953293e44Sflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 2053293e44Sflorian */ 2153293e44Sflorian 2253293e44Sflorian #include <sys/types.h> 2353293e44Sflorian #include <sys/queue.h> 2453293e44Sflorian #include <sys/socket.h> 2553293e44Sflorian #include <sys/syslog.h> 2653293e44Sflorian #include <sys/uio.h> 2753293e44Sflorian 2853293e44Sflorian #include <netinet/in.h> 2953293e44Sflorian #include <net/if.h> 3053293e44Sflorian #include <arpa/inet.h> 3153293e44Sflorian #include <netinet/icmp6.h> 3253293e44Sflorian 3353293e44Sflorian #include <errno.h> 3453293e44Sflorian #include <event.h> 3553293e44Sflorian #include <imsg.h> 3653293e44Sflorian #include <signal.h> 3753293e44Sflorian #include <stdlib.h> 3853293e44Sflorian #include <string.h> 3953293e44Sflorian #include <pwd.h> 4053293e44Sflorian #include <unistd.h> 4153293e44Sflorian 4253293e44Sflorian #include "log.h" 4353293e44Sflorian #include "rad.h" 4453293e44Sflorian #include "engine.h" 4553293e44Sflorian 46*0c40990eSflorian #define MAX_RTR_ADV_INTERVAL 600 47*0c40990eSflorian #define MIN_RTR_ADV_INTERVAL 200 48*0c40990eSflorian 49*0c40990eSflorian struct engine_iface { 50*0c40990eSflorian TAILQ_ENTRY(engine_iface) entry; 51*0c40990eSflorian struct event timer; 52*0c40990eSflorian uint32_t if_index; 53*0c40990eSflorian }; 54*0c40990eSflorian 55*0c40990eSflorian TAILQ_HEAD(, engine_iface) engine_interfaces; 56*0c40990eSflorian 57*0c40990eSflorian 5853293e44Sflorian __dead void engine_shutdown(void); 5953293e44Sflorian void engine_sig_handler(int sig, short, void *); 6053293e44Sflorian void engine_dispatch_frontend(int, short, void *); 6153293e44Sflorian void engine_dispatch_main(int, short, void *); 6253293e44Sflorian void parse_ra_rs(struct imsg_ra_rs *); 6353293e44Sflorian void parse_ra(struct imsg_ra_rs *); 6453293e44Sflorian void parse_rs(struct imsg_ra_rs *); 65*0c40990eSflorian void update_iface(uint32_t); 66*0c40990eSflorian struct engine_iface *find_engine_iface_by_id(uint32_t); 67*0c40990eSflorian void iface_timeout(int, short, void *); 6853293e44Sflorian 6953293e44Sflorian struct rad_conf *engine_conf; 7053293e44Sflorian struct imsgev *iev_frontend; 7153293e44Sflorian struct imsgev *iev_main; 7253293e44Sflorian struct sockaddr_in6 all_nodes; 7353293e44Sflorian 7453293e44Sflorian void 7553293e44Sflorian engine_sig_handler(int sig, short event, void *arg) 7653293e44Sflorian { 7753293e44Sflorian /* 7853293e44Sflorian * Normal signal handler rules don't apply because libevent 7953293e44Sflorian * decouples for us. 8053293e44Sflorian */ 8153293e44Sflorian 8253293e44Sflorian switch (sig) { 8353293e44Sflorian case SIGINT: 8453293e44Sflorian case SIGTERM: 8553293e44Sflorian engine_shutdown(); 8653293e44Sflorian default: 8753293e44Sflorian fatalx("unexpected signal"); 8853293e44Sflorian } 8953293e44Sflorian } 9053293e44Sflorian 9153293e44Sflorian void 9253293e44Sflorian engine(int debug, int verbose) 9353293e44Sflorian { 9453293e44Sflorian struct event ev_sigint, ev_sigterm; 9553293e44Sflorian struct passwd *pw; 9653293e44Sflorian 9753293e44Sflorian engine_conf = config_new_empty(); 9853293e44Sflorian 9953293e44Sflorian log_init(debug, LOG_DAEMON); 10053293e44Sflorian log_setverbose(verbose); 10153293e44Sflorian 10253293e44Sflorian if ((pw = getpwnam(RAD_USER)) == NULL) 10353293e44Sflorian fatal("getpwnam"); 10453293e44Sflorian 10553293e44Sflorian if (chroot(pw->pw_dir) == -1) 10653293e44Sflorian fatal("chroot"); 10753293e44Sflorian if (chdir("/") == -1) 10853293e44Sflorian fatal("chdir(\"/\")"); 10953293e44Sflorian 11053293e44Sflorian rad_process = PROC_ENGINE; 11153293e44Sflorian setproctitle("%s", log_procnames[rad_process]); 11253293e44Sflorian log_procinit(log_procnames[rad_process]); 11353293e44Sflorian 11453293e44Sflorian if (setgroups(1, &pw->pw_gid) || 11553293e44Sflorian setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 11653293e44Sflorian setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 11753293e44Sflorian fatal("can't drop privileges"); 11853293e44Sflorian 11953293e44Sflorian if (pledge("stdio recvfd", NULL) == -1) 12053293e44Sflorian fatal("pledge"); 12153293e44Sflorian 12253293e44Sflorian event_init(); 12353293e44Sflorian 12453293e44Sflorian /* Setup signal handler(s). */ 12553293e44Sflorian signal_set(&ev_sigint, SIGINT, engine_sig_handler, NULL); 12653293e44Sflorian signal_set(&ev_sigterm, SIGTERM, engine_sig_handler, NULL); 12753293e44Sflorian signal_add(&ev_sigint, NULL); 12853293e44Sflorian signal_add(&ev_sigterm, NULL); 12953293e44Sflorian signal(SIGPIPE, SIG_IGN); 13053293e44Sflorian signal(SIGHUP, SIG_IGN); 13153293e44Sflorian 13253293e44Sflorian /* Setup pipe and event handler to the main process. */ 13353293e44Sflorian if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 13453293e44Sflorian fatal(NULL); 13553293e44Sflorian 13653293e44Sflorian imsg_init(&iev_main->ibuf, 3); 13753293e44Sflorian iev_main->handler = engine_dispatch_main; 13853293e44Sflorian 13953293e44Sflorian /* Setup event handlers. */ 14053293e44Sflorian iev_main->events = EV_READ; 14153293e44Sflorian event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 14253293e44Sflorian iev_main->handler, iev_main); 14353293e44Sflorian event_add(&iev_main->ev, NULL); 14453293e44Sflorian 14553293e44Sflorian all_nodes.sin6_len = sizeof(all_nodes); 14653293e44Sflorian all_nodes.sin6_family = AF_INET6; 14753293e44Sflorian if (inet_pton(AF_INET6, "ff02::1", &all_nodes.sin6_addr) != 1) 14853293e44Sflorian fatal("inet_pton"); 14953293e44Sflorian 15053293e44Sflorian event_dispatch(); 15153293e44Sflorian 15253293e44Sflorian engine_shutdown(); 15353293e44Sflorian } 15453293e44Sflorian 15553293e44Sflorian __dead void 15653293e44Sflorian engine_shutdown(void) 15753293e44Sflorian { 15853293e44Sflorian /* Close pipes. */ 15953293e44Sflorian msgbuf_clear(&iev_frontend->ibuf.w); 16053293e44Sflorian close(iev_frontend->ibuf.fd); 16153293e44Sflorian msgbuf_clear(&iev_main->ibuf.w); 16253293e44Sflorian close(iev_main->ibuf.fd); 16353293e44Sflorian 16453293e44Sflorian config_clear(engine_conf); 16553293e44Sflorian 16653293e44Sflorian free(iev_frontend); 16753293e44Sflorian free(iev_main); 16853293e44Sflorian 16953293e44Sflorian log_info("engine exiting"); 17053293e44Sflorian exit(0); 17153293e44Sflorian } 17253293e44Sflorian 17353293e44Sflorian int 17453293e44Sflorian engine_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) 17553293e44Sflorian { 17653293e44Sflorian return (imsg_compose_event(iev_frontend, type, 0, pid, -1, 17753293e44Sflorian data, datalen)); 17853293e44Sflorian } 17953293e44Sflorian 18053293e44Sflorian void 18153293e44Sflorian engine_dispatch_frontend(int fd, short event, void *bula) 18253293e44Sflorian { 18353293e44Sflorian struct imsgev *iev = bula; 18453293e44Sflorian struct imsgbuf *ibuf; 18553293e44Sflorian struct imsg imsg; 18653293e44Sflorian struct imsg_ra_rs ra_rs; 18753293e44Sflorian ssize_t n; 188*0c40990eSflorian uint32_t if_index; 18953293e44Sflorian int shut = 0, verbose; 19053293e44Sflorian 19153293e44Sflorian ibuf = &iev->ibuf; 19253293e44Sflorian 19353293e44Sflorian if (event & EV_READ) { 19453293e44Sflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 19553293e44Sflorian fatal("imsg_read error"); 19653293e44Sflorian if (n == 0) /* Connection closed. */ 19753293e44Sflorian shut = 1; 19853293e44Sflorian } 19953293e44Sflorian if (event & EV_WRITE) { 20053293e44Sflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 20153293e44Sflorian fatal("msgbuf_write"); 20253293e44Sflorian if (n == 0) /* Connection closed. */ 20353293e44Sflorian shut = 1; 20453293e44Sflorian } 20553293e44Sflorian 20653293e44Sflorian for (;;) { 20753293e44Sflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 20853293e44Sflorian fatal("%s: imsg_get error", __func__); 20953293e44Sflorian if (n == 0) /* No more messages. */ 21053293e44Sflorian break; 21153293e44Sflorian 21253293e44Sflorian switch (imsg.hdr.type) { 21353293e44Sflorian case IMSG_RA_RS: 21453293e44Sflorian if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(ra_rs)) 21553293e44Sflorian fatal("%s: IMSG_RA_RS wrong length: %d", 21653293e44Sflorian __func__, imsg.hdr.len); 21753293e44Sflorian memcpy(&ra_rs, imsg.data, sizeof(ra_rs)); 21853293e44Sflorian parse_ra_rs(&ra_rs); 21953293e44Sflorian break; 220*0c40990eSflorian case IMSG_UPDATE_IF: 221*0c40990eSflorian if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(if_index)) 222*0c40990eSflorian fatal("%s: IMSG_UPDATE_IF wrong length: %d", 223*0c40990eSflorian __func__, imsg.hdr.len); 224*0c40990eSflorian memcpy(&if_index, imsg.data, sizeof(if_index)); 225*0c40990eSflorian update_iface(if_index); 226*0c40990eSflorian break; 22753293e44Sflorian case IMSG_CTL_LOG_VERBOSE: 22853293e44Sflorian /* Already checked by frontend. */ 22953293e44Sflorian memcpy(&verbose, imsg.data, sizeof(verbose)); 23053293e44Sflorian log_setverbose(verbose); 23153293e44Sflorian break; 23253293e44Sflorian default: 23353293e44Sflorian log_debug("%s: unexpected imsg %d", __func__, 23453293e44Sflorian imsg.hdr.type); 23553293e44Sflorian break; 23653293e44Sflorian } 23753293e44Sflorian imsg_free(&imsg); 23853293e44Sflorian } 23953293e44Sflorian if (!shut) 24053293e44Sflorian imsg_event_add(iev); 24153293e44Sflorian else { 24253293e44Sflorian /* This pipe is dead. Remove its event handler. */ 24353293e44Sflorian event_del(&iev->ev); 24453293e44Sflorian event_loopexit(NULL); 24553293e44Sflorian } 24653293e44Sflorian } 24753293e44Sflorian 24853293e44Sflorian void 24953293e44Sflorian engine_dispatch_main(int fd, short event, void *bula) 25053293e44Sflorian { 25153293e44Sflorian static struct rad_conf *nconf; 25253293e44Sflorian static struct ra_iface_conf *ra_iface_conf; 25353293e44Sflorian struct imsg imsg; 25453293e44Sflorian struct imsgev *iev = bula; 25553293e44Sflorian struct imsgbuf *ibuf; 25653293e44Sflorian struct ra_prefix_conf *ra_prefix_conf; 25753293e44Sflorian ssize_t n; 25853293e44Sflorian int shut = 0; 25953293e44Sflorian 26053293e44Sflorian ibuf = &iev->ibuf; 26153293e44Sflorian 26253293e44Sflorian if (event & EV_READ) { 26353293e44Sflorian if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 26453293e44Sflorian fatal("imsg_read error"); 26553293e44Sflorian if (n == 0) /* Connection closed. */ 26653293e44Sflorian shut = 1; 26753293e44Sflorian } 26853293e44Sflorian if (event & EV_WRITE) { 26953293e44Sflorian if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) 27053293e44Sflorian fatal("msgbuf_write"); 27153293e44Sflorian if (n == 0) /* Connection closed. */ 27253293e44Sflorian shut = 1; 27353293e44Sflorian } 27453293e44Sflorian 27553293e44Sflorian for (;;) { 27653293e44Sflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 27753293e44Sflorian fatal("%s: imsg_get error", __func__); 27853293e44Sflorian if (n == 0) /* No more messages. */ 27953293e44Sflorian break; 28053293e44Sflorian 28153293e44Sflorian switch (imsg.hdr.type) { 28253293e44Sflorian case IMSG_SOCKET_IPC: 28353293e44Sflorian /* 28453293e44Sflorian * Setup pipe and event handler to the frontend 28553293e44Sflorian * process. 28653293e44Sflorian */ 28753293e44Sflorian if (iev_frontend) { 28853293e44Sflorian log_warnx("%s: received unexpected imsg fd " 28953293e44Sflorian "to engine", __func__); 29053293e44Sflorian break; 29153293e44Sflorian } 29253293e44Sflorian if ((fd = imsg.fd) == -1) { 29353293e44Sflorian log_warnx("%s: expected to receive imsg fd to " 29453293e44Sflorian "engine but didn't receive any", __func__); 29553293e44Sflorian break; 29653293e44Sflorian } 29753293e44Sflorian 29853293e44Sflorian iev_frontend = malloc(sizeof(struct imsgev)); 29953293e44Sflorian if (iev_frontend == NULL) 30053293e44Sflorian fatal(NULL); 30153293e44Sflorian 30253293e44Sflorian imsg_init(&iev_frontend->ibuf, fd); 30353293e44Sflorian iev_frontend->handler = engine_dispatch_frontend; 30453293e44Sflorian iev_frontend->events = EV_READ; 30553293e44Sflorian 30653293e44Sflorian event_set(&iev_frontend->ev, iev_frontend->ibuf.fd, 30753293e44Sflorian iev_frontend->events, iev_frontend->handler, 30853293e44Sflorian iev_frontend); 30953293e44Sflorian event_add(&iev_frontend->ev, NULL); 31053293e44Sflorian break; 31153293e44Sflorian case IMSG_RECONF_CONF: 31253293e44Sflorian if ((nconf = malloc(sizeof(struct rad_conf))) == NULL) 31353293e44Sflorian fatal(NULL); 31453293e44Sflorian memcpy(nconf, imsg.data, sizeof(struct rad_conf)); 31553293e44Sflorian SIMPLEQ_INIT(&nconf->ra_iface_list); 31653293e44Sflorian break; 31753293e44Sflorian case IMSG_RECONF_RA_IFACE: 31853293e44Sflorian if ((ra_iface_conf = malloc(sizeof(struct 31953293e44Sflorian ra_iface_conf))) == NULL) 32053293e44Sflorian fatal(NULL); 32153293e44Sflorian memcpy(ra_iface_conf, imsg.data, 32253293e44Sflorian sizeof(struct ra_iface_conf)); 32353293e44Sflorian ra_iface_conf->autoprefix = NULL; 32453293e44Sflorian SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list); 32553293e44Sflorian SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list, 32653293e44Sflorian ra_iface_conf, entry); 32753293e44Sflorian break; 32853293e44Sflorian case IMSG_RECONF_RA_AUTOPREFIX: 32953293e44Sflorian if ((ra_iface_conf->autoprefix = malloc(sizeof(struct 33053293e44Sflorian ra_prefix_conf))) == NULL) 33153293e44Sflorian fatal(NULL); 33253293e44Sflorian memcpy(ra_iface_conf->autoprefix, imsg.data, 33353293e44Sflorian sizeof(struct ra_prefix_conf)); 33453293e44Sflorian break; 33553293e44Sflorian case IMSG_RECONF_RA_PREFIX: 33653293e44Sflorian if ((ra_prefix_conf = malloc(sizeof(struct 33753293e44Sflorian ra_prefix_conf))) == NULL) 33853293e44Sflorian fatal(NULL); 33953293e44Sflorian memcpy(ra_prefix_conf, imsg.data, sizeof(struct 34053293e44Sflorian ra_prefix_conf)); 34153293e44Sflorian SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, 34253293e44Sflorian ra_prefix_conf, entry); 34353293e44Sflorian break; 34453293e44Sflorian case IMSG_RECONF_END: 34553293e44Sflorian merge_config(engine_conf, nconf); 34653293e44Sflorian nconf = NULL; 34753293e44Sflorian break; 34853293e44Sflorian default: 34953293e44Sflorian log_debug("%s: unexpected imsg %d", __func__, 35053293e44Sflorian imsg.hdr.type); 35153293e44Sflorian break; 35253293e44Sflorian } 35353293e44Sflorian imsg_free(&imsg); 35453293e44Sflorian } 35553293e44Sflorian if (!shut) 35653293e44Sflorian imsg_event_add(iev); 35753293e44Sflorian else { 35853293e44Sflorian /* This pipe is dead. Remove its event handler. */ 35953293e44Sflorian event_del(&iev->ev); 36053293e44Sflorian event_loopexit(NULL); 36153293e44Sflorian } 36253293e44Sflorian } 36353293e44Sflorian 36453293e44Sflorian 36553293e44Sflorian void 36653293e44Sflorian parse_ra_rs(struct imsg_ra_rs *ra_rs) 36753293e44Sflorian { 36853293e44Sflorian char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 36953293e44Sflorian struct icmp6_hdr *hdr; 37053293e44Sflorian 37153293e44Sflorian hdr = (struct icmp6_hdr *) ra_rs->packet; 37253293e44Sflorian 37353293e44Sflorian switch (hdr->icmp6_type) { 37453293e44Sflorian case ND_ROUTER_ADVERT: 37553293e44Sflorian parse_ra(ra_rs); 37653293e44Sflorian break; 37753293e44Sflorian case ND_ROUTER_SOLICIT: 37853293e44Sflorian parse_rs(ra_rs); 37953293e44Sflorian break; 38053293e44Sflorian default: 38153293e44Sflorian log_warnx("unexpected icmp6_type: %d from %s on %s", 38253293e44Sflorian hdr->icmp6_type, inet_ntop(AF_INET6, &ra_rs->from.sin6_addr, 38353293e44Sflorian ntopbuf, INET6_ADDRSTRLEN), if_indextoname(ra_rs->if_index, 38453293e44Sflorian ifnamebuf)); 38553293e44Sflorian break; 38653293e44Sflorian } 38753293e44Sflorian } 38853293e44Sflorian 38953293e44Sflorian void 39053293e44Sflorian parse_ra(struct imsg_ra_rs *ra) 39153293e44Sflorian { 39253293e44Sflorian char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 39353293e44Sflorian log_debug("got RA from %s on %s", 39453293e44Sflorian inet_ntop(AF_INET6, &ra->from.sin6_addr, ntopbuf, 39553293e44Sflorian INET6_ADDRSTRLEN), if_indextoname(ra->if_index, 39653293e44Sflorian ifnamebuf)); 39753293e44Sflorian /* XXX not yet */ 39853293e44Sflorian } 39953293e44Sflorian 40053293e44Sflorian void 40153293e44Sflorian parse_rs(struct imsg_ra_rs *rs) 40253293e44Sflorian { 40353293e44Sflorian struct nd_router_solicit *nd_rs; 40453293e44Sflorian struct imsg_send_ra send_ra; 40553293e44Sflorian ssize_t len; 40653293e44Sflorian const char *hbuf; 40753293e44Sflorian char ifnamebuf[IFNAMSIZ]; 40853293e44Sflorian uint8_t *p; 40953293e44Sflorian 41053293e44Sflorian hbuf = sin6_to_str(&rs->from); 41153293e44Sflorian 41253293e44Sflorian send_ra.if_index = rs->if_index; 41353293e44Sflorian memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); 41453293e44Sflorian 41553293e44Sflorian log_debug("got RS from %s on %s", hbuf, if_indextoname(rs->if_index, 41653293e44Sflorian ifnamebuf)); 41753293e44Sflorian 41853293e44Sflorian len = rs->len; 41953293e44Sflorian 42053293e44Sflorian if (!IN6_IS_ADDR_LINKLOCAL(&rs->from.sin6_addr)) { 42153293e44Sflorian log_warnx("RA from non link local address %s", hbuf); 42253293e44Sflorian return; 42353293e44Sflorian } 42453293e44Sflorian 42553293e44Sflorian if ((size_t)len < sizeof(struct nd_router_solicit)) { 42653293e44Sflorian log_warnx("received too short message (%ld) from %s", len, 42753293e44Sflorian hbuf); 42853293e44Sflorian return; 42953293e44Sflorian } 43053293e44Sflorian 43153293e44Sflorian p = rs->packet; 43253293e44Sflorian nd_rs = (struct nd_router_solicit *)p; 43353293e44Sflorian len -= sizeof(struct nd_router_solicit); 43453293e44Sflorian p += sizeof(struct nd_router_solicit); 43553293e44Sflorian 43653293e44Sflorian if (nd_rs->nd_rs_code != 0) { 43753293e44Sflorian log_warnx("invalid ICMPv6 code (%d) from %s", nd_rs->nd_rs_code, 43853293e44Sflorian hbuf); 43953293e44Sflorian return; 44053293e44Sflorian } 44153293e44Sflorian while ((size_t)len >= sizeof(struct nd_opt_hdr)) { 44253293e44Sflorian struct nd_opt_hdr *nd_opt_hdr = (struct nd_opt_hdr *)p; 44353293e44Sflorian 44453293e44Sflorian len -= sizeof(struct nd_opt_hdr); 44553293e44Sflorian p += sizeof(struct nd_opt_hdr); 44653293e44Sflorian 44753293e44Sflorian if (nd_opt_hdr->nd_opt_len * 8 - 2 > len) { 44853293e44Sflorian log_warnx("invalid option len: %u > %ld", 44953293e44Sflorian nd_opt_hdr->nd_opt_len, len); 45053293e44Sflorian return; 45153293e44Sflorian } 45253293e44Sflorian switch (nd_opt_hdr->nd_opt_type) { 45353293e44Sflorian case ND_OPT_SOURCE_LINKADDR: 45453293e44Sflorian log_debug("got RS with source linkaddr option"); 45553293e44Sflorian memcpy(&send_ra.to, &rs->from, sizeof(send_ra.to)); 45653293e44Sflorian break; 45753293e44Sflorian default: 45853293e44Sflorian log_debug("\t\tUNKNOWN: %d", nd_opt_hdr->nd_opt_type); 45953293e44Sflorian break; 46053293e44Sflorian } 46153293e44Sflorian len -= nd_opt_hdr->nd_opt_len * 8 - 2; 46253293e44Sflorian p += nd_opt_hdr->nd_opt_len * 8 - 2; 46353293e44Sflorian } 46453293e44Sflorian engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, 46553293e44Sflorian sizeof(send_ra)); 46653293e44Sflorian } 467*0c40990eSflorian 468*0c40990eSflorian struct engine_iface* 469*0c40990eSflorian find_engine_iface_by_id(uint32_t if_index) 470*0c40990eSflorian { 471*0c40990eSflorian struct engine_iface *engine_iface; 472*0c40990eSflorian 473*0c40990eSflorian TAILQ_FOREACH(engine_iface, &engine_interfaces, entry) { 474*0c40990eSflorian if (engine_iface->if_index == if_index) 475*0c40990eSflorian return engine_iface; 476*0c40990eSflorian } 477*0c40990eSflorian return (NULL); 478*0c40990eSflorian } 479*0c40990eSflorian 480*0c40990eSflorian void 481*0c40990eSflorian update_iface(uint32_t if_index) 482*0c40990eSflorian { 483*0c40990eSflorian struct engine_iface *engine_iface; 484*0c40990eSflorian struct timeval tv; 485*0c40990eSflorian 486*0c40990eSflorian if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL) { 487*0c40990eSflorian engine_iface = calloc(1, sizeof(*engine_iface)); 488*0c40990eSflorian engine_iface->if_index = if_index; 489*0c40990eSflorian evtimer_set(&engine_iface->timer, iface_timeout, engine_iface); 490*0c40990eSflorian } 491*0c40990eSflorian 492*0c40990eSflorian tv.tv_sec = 0; 493*0c40990eSflorian tv.tv_usec = arc4random_uniform(1000000); 494*0c40990eSflorian evtimer_add(&engine_iface->timer, &tv); 495*0c40990eSflorian } 496*0c40990eSflorian 497*0c40990eSflorian void 498*0c40990eSflorian iface_timeout(int fd, short events, void *arg) 499*0c40990eSflorian { 500*0c40990eSflorian struct engine_iface *engine_iface = (struct engine_iface *)arg; 501*0c40990eSflorian struct imsg_send_ra send_ra; 502*0c40990eSflorian struct timeval tv; 503*0c40990eSflorian 504*0c40990eSflorian 505*0c40990eSflorian tv.tv_sec = MIN_RTR_ADV_INTERVAL + 506*0c40990eSflorian arc4random_uniform(MAX_RTR_ADV_INTERVAL - MIN_RTR_ADV_INTERVAL); 507*0c40990eSflorian tv.tv_usec = arc4random_uniform(1000000); 508*0c40990eSflorian 509*0c40990eSflorian log_debug("%s new timeout in %lld", __func__, tv.tv_sec); 510*0c40990eSflorian 511*0c40990eSflorian evtimer_add(&engine_iface->timer, &tv); 512*0c40990eSflorian 513*0c40990eSflorian send_ra.if_index = engine_iface->if_index; 514*0c40990eSflorian memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to)); 515*0c40990eSflorian engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra, 516*0c40990eSflorian sizeof(send_ra)); 517*0c40990eSflorian } 518