1*f1b790a5Sclaudio /* $OpenBSD: frontend.c,v 1.55 2024/11/21 13:38:15 claudio Exp $ */ 253293e44Sflorian 353293e44Sflorian /* 453293e44Sflorian * Copyright (c) 2018 Florian Obser <florian@openbsd.org> 553293e44Sflorian * Copyright (c) 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 /* 2353293e44Sflorian * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 2453293e44Sflorian * All rights reserved. 2553293e44Sflorian * 2653293e44Sflorian * Redistribution and use in source and binary forms, with or without 2753293e44Sflorian * modification, are permitted provided that the following conditions 2853293e44Sflorian * are met: 2953293e44Sflorian * 1. Redistributions of source code must retain the above copyright 3053293e44Sflorian * notice, this list of conditions and the following disclaimer. 3153293e44Sflorian * 2. Redistributions in binary form must reproduce the above copyright 3253293e44Sflorian * notice, this list of conditions and the following disclaimer in the 3353293e44Sflorian * documentation and/or other materials provided with the distribution. 3453293e44Sflorian * 3. Neither the name of the project nor the names of its contributors 3553293e44Sflorian * may be used to endorse or promote products derived from this software 3653293e44Sflorian * without specific prior written permission. 3753293e44Sflorian * 3853293e44Sflorian * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 3953293e44Sflorian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4053293e44Sflorian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4153293e44Sflorian * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 4253293e44Sflorian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4353293e44Sflorian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4453293e44Sflorian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4553293e44Sflorian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4653293e44Sflorian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 4753293e44Sflorian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 4853293e44Sflorian * SUCH DAMAGE. 4953293e44Sflorian */ 5053293e44Sflorian 5153293e44Sflorian #include <sys/types.h> 5253293e44Sflorian #include <sys/ioctl.h> 5353293e44Sflorian #include <sys/queue.h> 5453293e44Sflorian #include <sys/socket.h> 5553293e44Sflorian #include <sys/syslog.h> 5653293e44Sflorian #include <sys/uio.h> 5753293e44Sflorian 5853293e44Sflorian #include <net/if.h> 5930ca3407Sflorian #include <net/if_dl.h> 6053293e44Sflorian #include <net/if_types.h> 6153293e44Sflorian #include <net/route.h> 6253293e44Sflorian 6353293e44Sflorian #include <arpa/inet.h> 6453293e44Sflorian 6553293e44Sflorian #include <netinet/in.h> 6653293e44Sflorian #include <netinet/if_ether.h> 6753293e44Sflorian #include <netinet6/nd6.h> 6853293e44Sflorian #include <netinet6/in6_var.h> 6953293e44Sflorian #include <netinet/ip6.h> 7053293e44Sflorian #include <netinet/icmp6.h> 7153293e44Sflorian 7292f66a25Sreyk #include <ctype.h> 7353293e44Sflorian #include <errno.h> 7453293e44Sflorian #include <event.h> 7553293e44Sflorian #include <ifaddrs.h> 7653293e44Sflorian #include <imsg.h> 7753293e44Sflorian #include <pwd.h> 7853293e44Sflorian #include <signal.h> 7953293e44Sflorian #include <stdio.h> 8053293e44Sflorian #include <stdlib.h> 8153293e44Sflorian #include <string.h> 8253293e44Sflorian #include <unistd.h> 8353293e44Sflorian 8453293e44Sflorian #include "log.h" 8553293e44Sflorian #include "rad.h" 8653293e44Sflorian #include "frontend.h" 8753293e44Sflorian #include "control.h" 8853293e44Sflorian 890c40990eSflorian #define RA_MAX_SIZE 1500 9048e174fdSflorian #define ROUTE_SOCKET_BUF_SIZE 16384 910c40990eSflorian 9253293e44Sflorian struct icmp6_ev { 9353293e44Sflorian struct event ev; 9453293e44Sflorian uint8_t answer[1500]; 9553293e44Sflorian struct msghdr rcvmhdr; 9653293e44Sflorian struct iovec rcviov[1]; 9753293e44Sflorian struct sockaddr_in6 from; 98e88dba76Sflorian int refcnt; 99e88dba76Sflorian }; 10053293e44Sflorian 10153293e44Sflorian struct ra_iface { 10253293e44Sflorian TAILQ_ENTRY(ra_iface) entry; 103e88dba76Sflorian struct icmp6_ev *icmp6ev; 10453293e44Sflorian struct ra_prefix_conf_head prefixes; 105c358c7e3Sflorian struct ether_addr hw_addr; 10653293e44Sflorian char name[IF_NAMESIZE]; 10792f66a25Sreyk char conf_name[IF_NAMESIZE]; 10853293e44Sflorian uint32_t if_index; 109e88dba76Sflorian int rdomain; 11053293e44Sflorian int removed; 111abcf5f52Sflorian int link_state; 11253293e44Sflorian int prefix_count; 11320fc6e8eSflorian int ltime_decaying; 11453293e44Sflorian size_t datalen; 1150c40990eSflorian uint8_t data[RA_MAX_SIZE]; 11653293e44Sflorian }; 11753293e44Sflorian 1185207bb19Sflorian #define ND_OPT_PREF64 38 1195207bb19Sflorian struct nd_opt_pref64 { 1205207bb19Sflorian u_int8_t nd_opt_pref64_type; 1215207bb19Sflorian u_int8_t nd_opt_pref64_len; 1225207bb19Sflorian u_int16_t nd_opt_pref64_sltime_plc; 1235207bb19Sflorian u_int8_t nd_opt_pref64[12]; 1245207bb19Sflorian }; 1255207bb19Sflorian 12630ca3407Sflorian struct nd_opt_source_link_addr { 12730ca3407Sflorian u_int8_t nd_opt_source_link_addr_type; 12830ca3407Sflorian u_int8_t nd_opt_source_link_addr_len; 12930ca3407Sflorian struct ether_addr nd_opt_source_link_addr_hw_addr; 13030ca3407Sflorian }; 13130ca3407Sflorian 13253293e44Sflorian TAILQ_HEAD(, ra_iface) ra_interfaces; 13353293e44Sflorian 13453293e44Sflorian __dead void frontend_shutdown(void); 13553293e44Sflorian void frontend_sig_handler(int, short, void *); 13653293e44Sflorian void frontend_startup(void); 13753293e44Sflorian void icmp6_receive(int, short, void *); 13853293e44Sflorian void join_all_routers_mcast_group(struct ra_iface *); 13953293e44Sflorian void leave_all_routers_mcast_group(struct ra_iface *); 140e88dba76Sflorian int get_ifrdomain(char *); 141c358c7e3Sflorian void merge_ra_interface(char *, char *, struct ifaddrs *); 14253293e44Sflorian void merge_ra_interfaces(void); 14353293e44Sflorian struct ra_iface *find_ra_iface_by_id(uint32_t); 14453293e44Sflorian struct ra_iface *find_ra_iface_by_name(char *); 14553293e44Sflorian struct ra_iface_conf *find_ra_iface_conf(struct ra_iface_conf_head *, 14653293e44Sflorian char *); 14753293e44Sflorian struct ra_prefix_conf *find_ra_prefix_conf(struct ra_prefix_conf_head*, 14853293e44Sflorian struct in6_addr *, int); 149e88dba76Sflorian struct icmp6_ev *get_icmp6ev_by_rdomain(int); 150e88dba76Sflorian void unref_icmp6ev(struct ra_iface *); 151e88dba76Sflorian void set_icmp6sock(int, int); 15253293e44Sflorian void add_new_prefix_to_ra_iface(struct ra_iface *r, 15320fc6e8eSflorian struct in6_addr *, int, struct ra_prefix_conf *, 15420fc6e8eSflorian uint32_t, uint32_t); 15553293e44Sflorian void free_ra_iface(struct ra_iface *); 15653293e44Sflorian int in6_mask2prefixlen(struct in6_addr *); 15753293e44Sflorian void get_interface_prefixes(struct ra_iface *, 158c358c7e3Sflorian struct ra_prefix_conf *, struct ifaddrs *); 15920fc6e8eSflorian int build_packet(struct ra_iface *); 1608c9b05a6Sflorian void build_leaving_packet(struct ra_iface *); 16153293e44Sflorian void ra_output(struct ra_iface *, struct sockaddr_in6 *); 16248e174fdSflorian void get_rtaddrs(int, struct sockaddr *, 16348e174fdSflorian struct sockaddr **); 16448e174fdSflorian void route_receive(int, short, void *); 16548e174fdSflorian void handle_route_message(struct rt_msghdr *, 16648e174fdSflorian struct sockaddr **); 16753293e44Sflorian 16853293e44Sflorian struct rad_conf *frontend_conf; 169032fa683Sflorian static struct imsgev *iev_main; 170032fa683Sflorian static struct imsgev *iev_engine; 17148e174fdSflorian struct event ev_route; 172e88dba76Sflorian int ioctlsock = -1, routesock = -1; 17353293e44Sflorian struct ipv6_mreq all_routers; 17453293e44Sflorian struct msghdr sndmhdr; 17553293e44Sflorian struct iovec sndiov[2]; 17653293e44Sflorian 17753293e44Sflorian void 17853293e44Sflorian frontend_sig_handler(int sig, short event, void *bula) 17953293e44Sflorian { 18053293e44Sflorian /* 18153293e44Sflorian * Normal signal handler rules don't apply because libevent 18253293e44Sflorian * decouples for us. 18353293e44Sflorian */ 18453293e44Sflorian 18553293e44Sflorian switch (sig) { 18653293e44Sflorian case SIGINT: 18753293e44Sflorian case SIGTERM: 18853293e44Sflorian frontend_shutdown(); 18953293e44Sflorian default: 19053293e44Sflorian fatalx("unexpected signal"); 19153293e44Sflorian } 19253293e44Sflorian } 19353293e44Sflorian 19453293e44Sflorian void 195a778af8bSflorian frontend(int debug, int verbose) 19653293e44Sflorian { 19753293e44Sflorian struct event ev_sigint, ev_sigterm; 19853293e44Sflorian struct passwd *pw; 199e88dba76Sflorian size_t sndcmsgbuflen; 20053293e44Sflorian uint8_t *sndcmsgbuf = NULL; 20153293e44Sflorian 20253293e44Sflorian frontend_conf = config_new_empty(); 20353293e44Sflorian 20453293e44Sflorian log_init(debug, LOG_DAEMON); 20553293e44Sflorian log_setverbose(verbose); 20653293e44Sflorian 20753293e44Sflorian if ((pw = getpwnam(RAD_USER)) == NULL) 20853293e44Sflorian fatal("getpwnam"); 20953293e44Sflorian 21053293e44Sflorian if (chroot(pw->pw_dir) == -1) 21153293e44Sflorian fatal("chroot"); 21253293e44Sflorian if (chdir("/") == -1) 21353293e44Sflorian fatal("chdir(\"/\")"); 21453293e44Sflorian 2153c6be478Sflorian setproctitle("%s", "frontend"); 2163c6be478Sflorian log_procinit("frontend"); 21753293e44Sflorian 21853293e44Sflorian if (setgroups(1, &pw->pw_gid) || 21953293e44Sflorian setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 22053293e44Sflorian setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 22153293e44Sflorian fatal("can't drop privileges"); 22253293e44Sflorian 22353293e44Sflorian /* XXX pass in from main */ 224df69c215Sderaadt if ((ioctlsock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1) 22553293e44Sflorian fatal("socket"); 22653293e44Sflorian 22753293e44Sflorian if (pledge("stdio inet unix recvfd route mcast", NULL) == -1) 22853293e44Sflorian fatal("pledge"); 22953293e44Sflorian 23053293e44Sflorian event_init(); 23153293e44Sflorian 23253293e44Sflorian /* Setup signal handler. */ 23353293e44Sflorian signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL); 23453293e44Sflorian signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL); 23553293e44Sflorian signal_add(&ev_sigint, NULL); 23653293e44Sflorian signal_add(&ev_sigterm, NULL); 23753293e44Sflorian signal(SIGPIPE, SIG_IGN); 23853293e44Sflorian signal(SIGHUP, SIG_IGN); 23953293e44Sflorian 24053293e44Sflorian /* Setup pipe and event handler to the parent process. */ 24153293e44Sflorian if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 24253293e44Sflorian fatal(NULL); 243*f1b790a5Sclaudio if (imsgbuf_init(&iev_main->ibuf, 3) == -1) 244*f1b790a5Sclaudio fatal(NULL); 245*f1b790a5Sclaudio imsgbuf_allow_fdpass(&iev_main->ibuf); 24653293e44Sflorian iev_main->handler = frontend_dispatch_main; 24753293e44Sflorian iev_main->events = EV_READ; 24853293e44Sflorian event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 24953293e44Sflorian iev_main->handler, iev_main); 25053293e44Sflorian event_add(&iev_main->ev, NULL); 25153293e44Sflorian 25253293e44Sflorian if (inet_pton(AF_INET6, "ff02::2", 25353293e44Sflorian &all_routers.ipv6mr_multiaddr.s6_addr) == -1) 25453293e44Sflorian fatal("inet_pton"); 25553293e44Sflorian 25653293e44Sflorian sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + 25753293e44Sflorian CMSG_SPACE(sizeof(int)); 25853293e44Sflorian if ((sndcmsgbuf = malloc(sndcmsgbuflen)) == NULL) 25953293e44Sflorian fatal("%s", __func__); 26053293e44Sflorian 26153293e44Sflorian sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); 26253293e44Sflorian sndmhdr.msg_iov = sndiov; 26353293e44Sflorian sndmhdr.msg_iovlen = 1; 26453293e44Sflorian sndmhdr.msg_control = sndcmsgbuf; 26553293e44Sflorian sndmhdr.msg_controllen = sndcmsgbuflen; 26653293e44Sflorian 26753293e44Sflorian TAILQ_INIT(&ra_interfaces); 26853293e44Sflorian 26953293e44Sflorian event_dispatch(); 27053293e44Sflorian 27153293e44Sflorian frontend_shutdown(); 27253293e44Sflorian } 27353293e44Sflorian 27453293e44Sflorian __dead void 27553293e44Sflorian frontend_shutdown(void) 27653293e44Sflorian { 27753293e44Sflorian /* Close pipes. */ 278dd7efffeSclaudio imsgbuf_write(&iev_engine->ibuf); 2799cbf9e90Sclaudio imsgbuf_clear(&iev_engine->ibuf); 28053293e44Sflorian close(iev_engine->ibuf.fd); 281dd7efffeSclaudio imsgbuf_write(&iev_main->ibuf); 2829cbf9e90Sclaudio imsgbuf_clear(&iev_main->ibuf); 28353293e44Sflorian close(iev_main->ibuf.fd); 28453293e44Sflorian 28553293e44Sflorian config_clear(frontend_conf); 28653293e44Sflorian 28753293e44Sflorian free(iev_engine); 28853293e44Sflorian free(iev_main); 28953293e44Sflorian 29053293e44Sflorian log_info("frontend exiting"); 29153293e44Sflorian exit(0); 29253293e44Sflorian } 29353293e44Sflorian 29453293e44Sflorian int 29553293e44Sflorian frontend_imsg_compose_main(int type, pid_t pid, void *data, uint16_t datalen) 29653293e44Sflorian { 29753293e44Sflorian return (imsg_compose_event(iev_main, type, 0, pid, -1, data, 29853293e44Sflorian datalen)); 29953293e44Sflorian } 30053293e44Sflorian 30153293e44Sflorian int 30253293e44Sflorian frontend_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen) 30353293e44Sflorian { 30453293e44Sflorian return (imsg_compose_event(iev_engine, type, 0, pid, -1, data, 30553293e44Sflorian datalen)); 30653293e44Sflorian } 30753293e44Sflorian 30853293e44Sflorian void 30953293e44Sflorian frontend_dispatch_main(int fd, short event, void *bula) 31053293e44Sflorian { 31153293e44Sflorian static struct rad_conf *nconf; 31253293e44Sflorian static struct ra_iface_conf *ra_iface_conf; 3138815eebdSflorian static struct ra_options_conf *ra_options; 31453293e44Sflorian struct imsg imsg; 31553293e44Sflorian struct imsgev *iev = bula; 31653293e44Sflorian struct imsgbuf *ibuf = &iev->ibuf; 31753293e44Sflorian struct ra_prefix_conf *ra_prefix_conf; 3184c40b7e8Sflorian struct ra_rdnss_conf *ra_rdnss_conf; 3194c40b7e8Sflorian struct ra_dnssl_conf *ra_dnssl_conf; 3205207bb19Sflorian struct ra_pref64_conf *pref64; 321e88dba76Sflorian int n, shut = 0, icmp6sock, rdomain; 32253293e44Sflorian 32353293e44Sflorian if (event & EV_READ) { 324668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 325dd7efffeSclaudio fatal("imsgbuf_read error"); 32653293e44Sflorian if (n == 0) /* Connection closed. */ 32753293e44Sflorian shut = 1; 32853293e44Sflorian } 32953293e44Sflorian if (event & EV_WRITE) { 330dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 331c1aa9554Sclaudio if (errno == EPIPE) /* connection closed */ 33253293e44Sflorian shut = 1; 333c1aa9554Sclaudio else 334dd7efffeSclaudio fatal("imsgbuf_write"); 335c1aa9554Sclaudio } 33653293e44Sflorian } 33753293e44Sflorian 33853293e44Sflorian for (;;) { 33953293e44Sflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 34053293e44Sflorian fatal("%s: imsg_get error", __func__); 34153293e44Sflorian if (n == 0) /* No more messages. */ 34253293e44Sflorian break; 34353293e44Sflorian 34453293e44Sflorian switch (imsg.hdr.type) { 34553293e44Sflorian case IMSG_SOCKET_IPC: 34653293e44Sflorian /* 34753293e44Sflorian * Setup pipe and event handler to the engine 34853293e44Sflorian * process. 34953293e44Sflorian */ 3500eb5c43bSpamela if (iev_engine) 3510eb5c43bSpamela fatalx("%s: received unexpected imsg fd to " 3520eb5c43bSpamela "frontend", __func__); 353d9be77f0Sclaudio if ((fd = imsg_get_fd(&imsg)) == -1) 3540eb5c43bSpamela fatalx("%s: expected to receive imsg fd to " 35553293e44Sflorian "frontend but didn't receive any", 35653293e44Sflorian __func__); 35753293e44Sflorian 35853293e44Sflorian iev_engine = malloc(sizeof(struct imsgev)); 35953293e44Sflorian if (iev_engine == NULL) 36053293e44Sflorian fatal(NULL); 36153293e44Sflorian 362*f1b790a5Sclaudio if (imsgbuf_init(&iev_engine->ibuf, fd) == -1) 363*f1b790a5Sclaudio fatal(NULL); 36453293e44Sflorian iev_engine->handler = frontend_dispatch_engine; 36553293e44Sflorian iev_engine->events = EV_READ; 36653293e44Sflorian 36753293e44Sflorian event_set(&iev_engine->ev, iev_engine->ibuf.fd, 36853293e44Sflorian iev_engine->events, iev_engine->handler, iev_engine); 36953293e44Sflorian event_add(&iev_engine->ev, NULL); 37053293e44Sflorian break; 37153293e44Sflorian case IMSG_RECONF_CONF: 3722b2996d8Sflorian if (nconf != NULL) 3732b2996d8Sflorian fatalx("%s: IMSG_RECONF_CONF already in " 3742b2996d8Sflorian "progress", __func__); 3750eb5c43bSpamela if (IMSG_DATA_SIZE(imsg) != sizeof(struct rad_conf)) 3760eb5c43bSpamela fatalx("%s: IMSG_RECONF_CONF wrong length: %lu", 3770eb5c43bSpamela __func__, IMSG_DATA_SIZE(imsg)); 37853293e44Sflorian if ((nconf = malloc(sizeof(struct rad_conf))) == 37953293e44Sflorian NULL) 38053293e44Sflorian fatal(NULL); 38153293e44Sflorian memcpy(nconf, imsg.data, sizeof(struct rad_conf)); 38253293e44Sflorian SIMPLEQ_INIT(&nconf->ra_iface_list); 3838815eebdSflorian SIMPLEQ_INIT(&nconf->ra_options.ra_rdnss_list); 3848815eebdSflorian SIMPLEQ_INIT(&nconf->ra_options.ra_dnssl_list); 3855207bb19Sflorian SIMPLEQ_INIT(&nconf->ra_options.ra_pref64_list); 3868815eebdSflorian ra_options = &nconf->ra_options; 38753293e44Sflorian break; 38853293e44Sflorian case IMSG_RECONF_RA_IFACE: 3890eb5c43bSpamela if (IMSG_DATA_SIZE(imsg) != sizeof(struct 3900eb5c43bSpamela ra_iface_conf)) 3910eb5c43bSpamela fatalx("%s: IMSG_RECONF_RA_IFACE wrong length: " 3920eb5c43bSpamela "%lu", __func__, IMSG_DATA_SIZE(imsg)); 39353293e44Sflorian if ((ra_iface_conf = malloc(sizeof(struct 39453293e44Sflorian ra_iface_conf))) == NULL) 39553293e44Sflorian fatal(NULL); 39653293e44Sflorian memcpy(ra_iface_conf, imsg.data, sizeof(struct 39753293e44Sflorian ra_iface_conf)); 39853293e44Sflorian ra_iface_conf->autoprefix = NULL; 39953293e44Sflorian SIMPLEQ_INIT(&ra_iface_conf->ra_prefix_list); 4008815eebdSflorian SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_rdnss_list); 4018815eebdSflorian SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_dnssl_list); 4025207bb19Sflorian SIMPLEQ_INIT(&ra_iface_conf->ra_options.ra_pref64_list); 40353293e44Sflorian SIMPLEQ_INSERT_TAIL(&nconf->ra_iface_list, 40453293e44Sflorian ra_iface_conf, entry); 4058815eebdSflorian ra_options = &ra_iface_conf->ra_options; 40653293e44Sflorian break; 40753293e44Sflorian case IMSG_RECONF_RA_AUTOPREFIX: 4080eb5c43bSpamela if (IMSG_DATA_SIZE(imsg) != sizeof(struct 4090eb5c43bSpamela ra_prefix_conf)) 4100eb5c43bSpamela fatalx("%s: IMSG_RECONF_RA_AUTOPREFIX wrong " 4110eb5c43bSpamela "length: %lu", __func__, 4120eb5c43bSpamela IMSG_DATA_SIZE(imsg)); 41353293e44Sflorian if ((ra_iface_conf->autoprefix = malloc(sizeof(struct 41453293e44Sflorian ra_prefix_conf))) == NULL) 41553293e44Sflorian fatal(NULL); 41653293e44Sflorian memcpy(ra_iface_conf->autoprefix, imsg.data, 41753293e44Sflorian sizeof(struct ra_prefix_conf)); 41853293e44Sflorian break; 41953293e44Sflorian case IMSG_RECONF_RA_PREFIX: 4200eb5c43bSpamela if (IMSG_DATA_SIZE(imsg) != sizeof(struct 4210eb5c43bSpamela ra_prefix_conf)) 4220eb5c43bSpamela fatalx("%s: IMSG_RECONF_RA_PREFIX wrong " 4230eb5c43bSpamela "length: %lu", __func__, 4240eb5c43bSpamela IMSG_DATA_SIZE(imsg)); 42553293e44Sflorian if ((ra_prefix_conf = malloc(sizeof(struct 42653293e44Sflorian ra_prefix_conf))) == NULL) 42753293e44Sflorian fatal(NULL); 42853293e44Sflorian memcpy(ra_prefix_conf, imsg.data, 42953293e44Sflorian sizeof(struct ra_prefix_conf)); 43053293e44Sflorian SIMPLEQ_INSERT_TAIL(&ra_iface_conf->ra_prefix_list, 43153293e44Sflorian ra_prefix_conf, entry); 43253293e44Sflorian break; 4334c40b7e8Sflorian case IMSG_RECONF_RA_RDNSS: 4340eb5c43bSpamela if (IMSG_DATA_SIZE(imsg) != sizeof(struct 4350eb5c43bSpamela ra_rdnss_conf)) 4360eb5c43bSpamela fatalx("%s: IMSG_RECONF_RA_RDNSS wrong length: " 4370eb5c43bSpamela "%lu", __func__, IMSG_DATA_SIZE(imsg)); 4384c40b7e8Sflorian if ((ra_rdnss_conf = malloc(sizeof(struct 4394c40b7e8Sflorian ra_rdnss_conf))) == NULL) 4404c40b7e8Sflorian fatal(NULL); 4414c40b7e8Sflorian memcpy(ra_rdnss_conf, imsg.data, sizeof(struct 4424c40b7e8Sflorian ra_rdnss_conf)); 4438815eebdSflorian SIMPLEQ_INSERT_TAIL(&ra_options->ra_rdnss_list, 4444c40b7e8Sflorian ra_rdnss_conf, entry); 4454c40b7e8Sflorian break; 4464c40b7e8Sflorian case IMSG_RECONF_RA_DNSSL: 4470eb5c43bSpamela if (IMSG_DATA_SIZE(imsg) != sizeof(struct 4480eb5c43bSpamela ra_dnssl_conf)) 4490eb5c43bSpamela fatalx("%s: IMSG_RECONF_RA_DNSSL wrong length: " 4500eb5c43bSpamela "%lu", __func__, IMSG_DATA_SIZE(imsg)); 4514c40b7e8Sflorian if ((ra_dnssl_conf = malloc(sizeof(struct 4524c40b7e8Sflorian ra_dnssl_conf))) == NULL) 4534c40b7e8Sflorian fatal(NULL); 4544c40b7e8Sflorian memcpy(ra_dnssl_conf, imsg.data, sizeof(struct 4554c40b7e8Sflorian ra_dnssl_conf)); 4568815eebdSflorian SIMPLEQ_INSERT_TAIL(&ra_options->ra_dnssl_list, 4574c40b7e8Sflorian ra_dnssl_conf, entry); 4584c40b7e8Sflorian break; 4595207bb19Sflorian case IMSG_RECONF_RA_PREF64: 4605207bb19Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(struct 4615207bb19Sflorian ra_pref64_conf)) 4625207bb19Sflorian fatalx("%s: IMSG_RECONF_RA_PREF64 wrong length: " 4635207bb19Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 4645207bb19Sflorian if ((pref64 = malloc(sizeof(struct ra_pref64_conf))) == 4655207bb19Sflorian NULL) 4665207bb19Sflorian fatal(NULL); 4675207bb19Sflorian memcpy(pref64, imsg.data, sizeof(struct ra_pref64_conf)); 4685207bb19Sflorian SIMPLEQ_INSERT_TAIL(&ra_options->ra_pref64_list, pref64, 4695207bb19Sflorian entry); 4705207bb19Sflorian break; 47153293e44Sflorian case IMSG_RECONF_END: 4722b2996d8Sflorian if (nconf == NULL) 4732b2996d8Sflorian fatalx("%s: IMSG_RECONF_END without " 4742b2996d8Sflorian "IMSG_RECONF_CONF", __func__); 47553293e44Sflorian merge_config(frontend_conf, nconf); 47653293e44Sflorian merge_ra_interfaces(); 47753293e44Sflorian nconf = NULL; 47853293e44Sflorian break; 47953293e44Sflorian case IMSG_ICMP6SOCK: 480d9be77f0Sclaudio if ((icmp6sock = imsg_get_fd(&imsg)) == -1) 48153293e44Sflorian fatalx("%s: expected to receive imsg " 48253293e44Sflorian "ICMPv6 fd but didn't receive any", 48353293e44Sflorian __func__); 484e88dba76Sflorian if (IMSG_DATA_SIZE(imsg) != sizeof(rdomain)) 485e88dba76Sflorian fatalx("%s: IMSG_ICMP6SOCK wrong length: " 486e88dba76Sflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 487e88dba76Sflorian memcpy(&rdomain, imsg.data, sizeof(rdomain)); 488e88dba76Sflorian set_icmp6sock(icmp6sock, rdomain); 489eb9f9513Sflorian break; 49048e174fdSflorian case IMSG_ROUTESOCK: 491eb9f9513Sflorian if (routesock != -1) 492eb9f9513Sflorian fatalx("%s: received unexpected routesock fd", 493eb9f9513Sflorian __func__); 494d9be77f0Sclaudio if ((routesock = imsg_get_fd(&imsg)) == -1) 49548e174fdSflorian fatalx("%s: expected to receive imsg " 49648e174fdSflorian "routesocket fd but didn't receive any", 49748e174fdSflorian __func__); 498b542a0d7Sflorian event_set(&ev_route, routesock, EV_READ | EV_PERSIST, 49948e174fdSflorian route_receive, NULL); 50048e174fdSflorian break; 50153293e44Sflorian case IMSG_STARTUP: 50253293e44Sflorian frontend_startup(); 50353293e44Sflorian break; 504a778af8bSflorian case IMSG_CONTROLFD: 505d9be77f0Sclaudio if ((fd = imsg_get_fd(&imsg)) == -1) 506a778af8bSflorian fatalx("%s: expected to receive imsg " 507a778af8bSflorian "control fd but didn't receive any", 508a778af8bSflorian __func__); 509a778af8bSflorian /* Listen on control socket. */ 510d258785eSflorian control_listen(fd); 511a778af8bSflorian break; 51253293e44Sflorian default: 51353293e44Sflorian log_debug("%s: error handling imsg %d", __func__, 51453293e44Sflorian imsg.hdr.type); 51553293e44Sflorian break; 51653293e44Sflorian } 51753293e44Sflorian imsg_free(&imsg); 51853293e44Sflorian } 51953293e44Sflorian if (!shut) 52053293e44Sflorian imsg_event_add(iev); 52153293e44Sflorian else { 52253293e44Sflorian /* This pipe is dead. Remove its event handler. */ 52353293e44Sflorian event_del(&iev->ev); 52453293e44Sflorian event_loopexit(NULL); 52553293e44Sflorian } 52653293e44Sflorian } 52753293e44Sflorian 52853293e44Sflorian void 52953293e44Sflorian frontend_dispatch_engine(int fd, short event, void *bula) 53053293e44Sflorian { 53153293e44Sflorian struct imsgev *iev = bula; 53253293e44Sflorian struct imsgbuf *ibuf = &iev->ibuf; 53353293e44Sflorian struct imsg imsg; 53453293e44Sflorian struct imsg_send_ra send_ra; 53553293e44Sflorian struct ra_iface *ra_iface; 5364a78c7cfSflorian uint32_t if_index; 53753293e44Sflorian int n, shut = 0; 53853293e44Sflorian 53953293e44Sflorian if (event & EV_READ) { 540668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 541dd7efffeSclaudio fatal("imsgbuf_read error"); 54253293e44Sflorian if (n == 0) /* Connection closed. */ 54353293e44Sflorian shut = 1; 54453293e44Sflorian } 54553293e44Sflorian if (event & EV_WRITE) { 546dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 547c1aa9554Sclaudio if (errno == EPIPE) /* connection closed */ 54853293e44Sflorian shut = 1; 549c1aa9554Sclaudio else 550dd7efffeSclaudio fatal("imsgbuf_write"); 551c1aa9554Sclaudio } 55253293e44Sflorian } 55353293e44Sflorian 55453293e44Sflorian for (;;) { 55553293e44Sflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 55653293e44Sflorian fatal("%s: imsg_get error", __func__); 55753293e44Sflorian if (n == 0) /* No more messages. */ 55853293e44Sflorian break; 55953293e44Sflorian 56053293e44Sflorian switch (imsg.hdr.type) { 56153293e44Sflorian case IMSG_SEND_RA: 562b17c900dSpamela if (IMSG_DATA_SIZE(imsg) != sizeof(send_ra)) 56351a61992Spamela fatalx("%s: IMSG_SEND_RA wrong length: %lu", 564b17c900dSpamela __func__, IMSG_DATA_SIZE(imsg)); 56553293e44Sflorian memcpy(&send_ra, imsg.data, sizeof(send_ra)); 56653293e44Sflorian ra_iface = find_ra_iface_by_id(send_ra.if_index); 56753293e44Sflorian if (ra_iface) 56853293e44Sflorian ra_output(ra_iface, &send_ra.to); 56953293e44Sflorian break; 5704a78c7cfSflorian case IMSG_REMOVE_IF: 571b17c900dSpamela if (IMSG_DATA_SIZE(imsg) != sizeof(if_index)) 57251a61992Spamela fatalx("%s: IMSG_REMOVE_IF wrong length: %lu", 573b17c900dSpamela __func__, IMSG_DATA_SIZE(imsg)); 5744a78c7cfSflorian memcpy(&if_index, imsg.data, sizeof(if_index)); 5754a78c7cfSflorian ra_iface = find_ra_iface_by_id(if_index); 5764a78c7cfSflorian if (ra_iface) { 5774a78c7cfSflorian TAILQ_REMOVE(&ra_interfaces, ra_iface, entry); 5784a78c7cfSflorian free_ra_iface(ra_iface); 5794a78c7cfSflorian } 5804a78c7cfSflorian break; 58153293e44Sflorian default: 58253293e44Sflorian log_debug("%s: error handling imsg %d", __func__, 58353293e44Sflorian imsg.hdr.type); 58453293e44Sflorian break; 58553293e44Sflorian } 58653293e44Sflorian imsg_free(&imsg); 58753293e44Sflorian } 58853293e44Sflorian if (!shut) 58953293e44Sflorian imsg_event_add(iev); 59053293e44Sflorian else { 59153293e44Sflorian /* This pipe is dead. Remove its event handler. */ 59253293e44Sflorian event_del(&iev->ev); 59353293e44Sflorian event_loopexit(NULL); 59453293e44Sflorian } 59553293e44Sflorian } 59653293e44Sflorian 59753293e44Sflorian void 59853293e44Sflorian frontend_startup(void) 59953293e44Sflorian { 60053293e44Sflorian if (!event_initialized(&ev_route)) 60153293e44Sflorian fatalx("%s: did not receive a route socket from the main " 60253293e44Sflorian "process", __func__); 60353293e44Sflorian 60453293e44Sflorian event_add(&ev_route, NULL); 60553293e44Sflorian } 60653293e44Sflorian 60753293e44Sflorian 60853293e44Sflorian void 60953293e44Sflorian icmp6_receive(int fd, short events, void *arg) 61053293e44Sflorian { 611e88dba76Sflorian struct icmp6_ev *icmp6ev; 612e88dba76Sflorian struct icmp6_hdr *icmp6_hdr; 61353293e44Sflorian struct imsg_ra_rs ra_rs; 61453293e44Sflorian struct in6_pktinfo *pi = NULL; 61553293e44Sflorian struct cmsghdr *cm; 61653293e44Sflorian ssize_t len; 61753293e44Sflorian int if_index = 0, *hlimp = NULL; 61853293e44Sflorian char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; 61953293e44Sflorian 620e88dba76Sflorian icmp6ev = arg; 621e88dba76Sflorian if ((len = recvmsg(fd, &icmp6ev->rcvmhdr, 0)) == -1) { 62253293e44Sflorian log_warn("recvmsg"); 62353293e44Sflorian return; 62453293e44Sflorian } 62553293e44Sflorian 626e88dba76Sflorian if ((size_t)len < sizeof(struct icmp6_hdr)) 627e88dba76Sflorian return; 628e88dba76Sflorian 629e88dba76Sflorian icmp6_hdr = (struct icmp6_hdr *)icmp6ev->answer; 630e88dba76Sflorian if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT && 631e88dba76Sflorian icmp6_hdr->icmp6_type != ND_ROUTER_SOLICIT) 632e88dba76Sflorian return; 633e88dba76Sflorian 63453293e44Sflorian /* extract optional information via Advanced API */ 635e88dba76Sflorian for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev->rcvmhdr); cm; 636e88dba76Sflorian cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev->rcvmhdr, cm)) { 63753293e44Sflorian if (cm->cmsg_level == IPPROTO_IPV6 && 63853293e44Sflorian cm->cmsg_type == IPV6_PKTINFO && 63953293e44Sflorian cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { 64053293e44Sflorian pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 64153293e44Sflorian if_index = pi->ipi6_ifindex; 64253293e44Sflorian } 64353293e44Sflorian if (cm->cmsg_level == IPPROTO_IPV6 && 64453293e44Sflorian cm->cmsg_type == IPV6_HOPLIMIT && 64553293e44Sflorian cm->cmsg_len == CMSG_LEN(sizeof(int))) 64653293e44Sflorian hlimp = (int *)CMSG_DATA(cm); 64753293e44Sflorian } 64853293e44Sflorian 64953293e44Sflorian if (if_index == 0) { 65053293e44Sflorian log_warnx("failed to get receiving interface"); 65153293e44Sflorian return; 65253293e44Sflorian } 65353293e44Sflorian 65453293e44Sflorian if (hlimp == NULL) { 65553293e44Sflorian log_warnx("failed to get receiving hop limit"); 65653293e44Sflorian return; 65753293e44Sflorian } 65853293e44Sflorian 65953293e44Sflorian if (*hlimp != 255) { 66053293e44Sflorian log_warnx("invalid RA or RS with hop limit of %d from %s on %s", 661e88dba76Sflorian *hlimp, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr, 66253293e44Sflorian ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index, 66353293e44Sflorian ifnamebuf)); 66453293e44Sflorian return; 66553293e44Sflorian } 66653293e44Sflorian 66793fdf396Sflorian log_debug("RA or RS with hop limit of %d from %s on %s", 668e88dba76Sflorian *hlimp, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr, 66953293e44Sflorian ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index, 67053293e44Sflorian ifnamebuf)); 67153293e44Sflorian 67253293e44Sflorian if ((size_t)len > sizeof(ra_rs.packet)) { 67353293e44Sflorian log_warnx("invalid RA or RS with size %ld from %s on %s", 674e88dba76Sflorian len, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr, 67553293e44Sflorian ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index, 67653293e44Sflorian ifnamebuf)); 67753293e44Sflorian return; 67853293e44Sflorian } 67953293e44Sflorian 68053293e44Sflorian ra_rs.if_index = if_index; 681e88dba76Sflorian memcpy(&ra_rs.from, &icmp6ev->from, sizeof(ra_rs.from)); 68253293e44Sflorian ra_rs.len = len; 683e88dba76Sflorian memcpy(ra_rs.packet, icmp6ev->answer, len); 68453293e44Sflorian 68553293e44Sflorian frontend_imsg_compose_engine(IMSG_RA_RS, 0, &ra_rs, sizeof(ra_rs)); 68653293e44Sflorian } 68753293e44Sflorian 68853293e44Sflorian void 68953293e44Sflorian join_all_routers_mcast_group(struct ra_iface *ra_iface) 69053293e44Sflorian { 691e88dba76Sflorian if (!event_initialized(&ra_iface->icmp6ev->ev)) 692e88dba76Sflorian return; 69353293e44Sflorian log_debug("joining multicast group on %s", ra_iface->name); 69453293e44Sflorian all_routers.ipv6mr_interface = ra_iface->if_index; 695e88dba76Sflorian if (setsockopt(EVENT_FD(&ra_iface->icmp6ev->ev), IPPROTO_IPV6, 696e88dba76Sflorian IPV6_JOIN_GROUP, &all_routers, sizeof(all_routers)) == -1) 69753293e44Sflorian fatal("IPV6_JOIN_GROUP(%s)", ra_iface->name); 69853293e44Sflorian } 69953293e44Sflorian 70053293e44Sflorian void 70153293e44Sflorian leave_all_routers_mcast_group(struct ra_iface *ra_iface) 70253293e44Sflorian { 703e88dba76Sflorian if (!event_initialized(&ra_iface->icmp6ev->ev)) 704e88dba76Sflorian return; 70553293e44Sflorian log_debug("leaving multicast group on %s", ra_iface->name); 70653293e44Sflorian all_routers.ipv6mr_interface = ra_iface->if_index; 707e88dba76Sflorian setsockopt(EVENT_FD(&ra_iface->icmp6ev->ev), IPPROTO_IPV6, 708e88dba76Sflorian IPV6_LEAVE_GROUP, &all_routers, sizeof(all_routers)); 70953293e44Sflorian } 71053293e44Sflorian 71153293e44Sflorian struct ra_iface* 71292e6ccd1Sreyk find_ra_iface_by_id(uint32_t if_index) 71392e6ccd1Sreyk { 71453293e44Sflorian struct ra_iface *ra_iface; 71553293e44Sflorian 71653293e44Sflorian TAILQ_FOREACH(ra_iface, &ra_interfaces, entry) { 71753293e44Sflorian if (ra_iface->if_index == if_index) 71853293e44Sflorian return ra_iface; 71953293e44Sflorian } 72053293e44Sflorian return (NULL); 72153293e44Sflorian } 72253293e44Sflorian 72353293e44Sflorian struct ra_iface* 72453293e44Sflorian find_ra_iface_by_name(char *if_name) 72553293e44Sflorian { 72653293e44Sflorian struct ra_iface *ra_iface; 72753293e44Sflorian 72853293e44Sflorian TAILQ_FOREACH(ra_iface, &ra_interfaces, entry) { 72953293e44Sflorian if (strcmp(ra_iface->name, if_name) == 0) 73053293e44Sflorian return ra_iface; 73153293e44Sflorian } 73253293e44Sflorian return (NULL); 73353293e44Sflorian } 73453293e44Sflorian 73553293e44Sflorian struct ra_iface_conf* 73653293e44Sflorian find_ra_iface_conf(struct ra_iface_conf_head *head, char *if_name) 73753293e44Sflorian { 73853293e44Sflorian struct ra_iface_conf *ra_iface_conf; 73953293e44Sflorian 74053293e44Sflorian SIMPLEQ_FOREACH(ra_iface_conf, head, entry) { 74153293e44Sflorian if (strcmp(ra_iface_conf->name, if_name) == 0) 74253293e44Sflorian return ra_iface_conf; 74353293e44Sflorian } 74453293e44Sflorian return (NULL); 74553293e44Sflorian } 74653293e44Sflorian 747abcf5f52Sflorian int 748e88dba76Sflorian get_ifrdomain(char *if_name) 749e88dba76Sflorian { 750e88dba76Sflorian struct ifreq ifr; 751e88dba76Sflorian 752e88dba76Sflorian strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); 753e88dba76Sflorian if (ioctl(ioctlsock, SIOCGIFRDOMAIN, (caddr_t)&ifr) == -1) { 754e88dba76Sflorian log_warn("SIOCGIFRDOMAIN"); 755e88dba76Sflorian return -1; 756e88dba76Sflorian } 757e88dba76Sflorian return ifr.ifr_rdomainid; 758e88dba76Sflorian } 759e88dba76Sflorian 76053293e44Sflorian void 761c358c7e3Sflorian merge_ra_interface(char *if_name, char *conf_name, struct ifaddrs *ifap) 76292f66a25Sreyk { 76392f66a25Sreyk struct ra_iface *ra_iface; 764c358c7e3Sflorian struct ifaddrs *ifa; 765c358c7e3Sflorian struct sockaddr_in6 *sin6; 766c358c7e3Sflorian struct in6_ifreq ifr6; 767c358c7e3Sflorian struct sockaddr_dl *sdl; 768c358c7e3Sflorian struct ether_addr hw_addr; 76992f66a25Sreyk uint32_t if_index; 770c358c7e3Sflorian int link_state = LINK_STATE_UNKNOWN; 771c358c7e3Sflorian int has_linklocal = 0, ifrdomain; 772c358c7e3Sflorian int has_hw_addr = 0; 773abcf5f52Sflorian 774c358c7e3Sflorian for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 775c358c7e3Sflorian if (ifa->ifa_addr == NULL) 776c358c7e3Sflorian continue; 777c358c7e3Sflorian if (ifa->ifa_addr->sa_family != AF_LINK && 778c358c7e3Sflorian ifa->ifa_addr->sa_family != AF_INET6) 779c358c7e3Sflorian continue; 780c358c7e3Sflorian if (strcmp(if_name, ifa->ifa_name) != 0) 781c358c7e3Sflorian continue; 78292f66a25Sreyk 783c358c7e3Sflorian if (ifa->ifa_addr->sa_family == AF_LINK) { 784c358c7e3Sflorian link_state = 785c358c7e3Sflorian ((struct if_data*)ifa->ifa_data)->ifi_link_state; 786c358c7e3Sflorian sdl = (struct sockaddr_dl *)ifa->ifa_addr; 78711d38187Sflorian if (sdl != NULL && (sdl->sdl_type == IFT_ETHER || 78811d38187Sflorian sdl->sdl_type == IFT_CARP) && sdl->sdl_alen == 78911d38187Sflorian ETHER_ADDR_LEN) { 790c358c7e3Sflorian has_hw_addr = 1; 791c358c7e3Sflorian memcpy(&hw_addr, LLADDR(sdl), ETHER_ADDR_LEN); 792c358c7e3Sflorian } 793c358c7e3Sflorian } else if (ifa->ifa_addr->sa_family == AF_INET6) { 794c358c7e3Sflorian sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 795c358c7e3Sflorian 796c358c7e3Sflorian if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 797c358c7e3Sflorian continue; 798c358c7e3Sflorian 799c358c7e3Sflorian memset(&ifr6, 0, sizeof(ifr6)); 800c358c7e3Sflorian strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name)); 801c358c7e3Sflorian memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); 802c358c7e3Sflorian if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, 803c358c7e3Sflorian (caddr_t)&ifr6) == -1) { 804c358c7e3Sflorian log_warn("SIOCGIFAFLAG_IN6"); 805c358c7e3Sflorian continue; 806c358c7e3Sflorian } 807c358c7e3Sflorian 808c358c7e3Sflorian if (ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_TENTATIVE | 809c358c7e3Sflorian IN6_IFF_DUPLICATED)) 810c358c7e3Sflorian continue; 811c358c7e3Sflorian has_linklocal = 1; 812c358c7e3Sflorian } 813c358c7e3Sflorian } 814c358c7e3Sflorian 815c358c7e3Sflorian ifrdomain = get_ifrdomain(if_name); 816c358c7e3Sflorian 817c358c7e3Sflorian if ((ra_iface = find_ra_iface_by_name(if_name)) != NULL) { 818abcf5f52Sflorian ra_iface->link_state = link_state; 819abcf5f52Sflorian if (!LINK_STATE_IS_UP(link_state)) { 820c358c7e3Sflorian log_debug("%s down, removing", if_name); 821e71a3804Sflorian ra_iface->removed = 1; 822e71a3804Sflorian } else if (!has_linklocal) { 823e71a3804Sflorian log_debug("%s has no IPv6 link-local address, " 824c358c7e3Sflorian "removing", if_name); 825abcf5f52Sflorian ra_iface->removed = 1; 826e88dba76Sflorian } else if (ifrdomain == -1) { 827c358c7e3Sflorian log_debug("can't get rdomain for %s, removing", if_name); 828c358c7e3Sflorian ra_iface->removed = 1; 829c358c7e3Sflorian } else if (!has_hw_addr) { 830c358c7e3Sflorian log_debug("%s has no mac address, removing", if_name); 831e88dba76Sflorian ra_iface->removed = 1; 832e88dba76Sflorian } else if (ra_iface->rdomain != ifrdomain) { 833e88dba76Sflorian leave_all_routers_mcast_group(ra_iface); 834e88dba76Sflorian unref_icmp6ev(ra_iface); 835e88dba76Sflorian ra_iface->rdomain = ifrdomain; 836e88dba76Sflorian ra_iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain); 837e88dba76Sflorian join_all_routers_mcast_group(ra_iface); 838e88dba76Sflorian ra_iface->removed = 0; 839abcf5f52Sflorian } else { 840c358c7e3Sflorian log_debug("keeping interface %s", if_name); 84192f66a25Sreyk ra_iface->removed = 0; 842abcf5f52Sflorian } 843c358c7e3Sflorian memcpy(&ra_iface->hw_addr, &hw_addr, sizeof(hw_addr)); 844abcf5f52Sflorian return; 845abcf5f52Sflorian } 846abcf5f52Sflorian 847abcf5f52Sflorian if (!LINK_STATE_IS_UP(link_state)) { 848c358c7e3Sflorian log_debug("%s down, ignoring", if_name); 84992f66a25Sreyk return; 85092f66a25Sreyk } 85192f66a25Sreyk 852e71a3804Sflorian if (!has_linklocal) { 853c358c7e3Sflorian log_debug("%s has no IPv6 link-local address, ignoring", 854c358c7e3Sflorian if_name); 855e71a3804Sflorian return; 856e71a3804Sflorian } 857e71a3804Sflorian 858c358c7e3Sflorian if (ifrdomain == -1) { 859c358c7e3Sflorian log_debug("can't get rdomain for %s, ignoring", if_name); 860c358c7e3Sflorian return; 861c358c7e3Sflorian } 862c358c7e3Sflorian 863c358c7e3Sflorian if (!has_hw_addr) { 864c358c7e3Sflorian log_debug("%s has no mac address, ignoring", if_name); 865c358c7e3Sflorian return; 866c358c7e3Sflorian } 867c358c7e3Sflorian 868c358c7e3Sflorian log_debug("new interface %s", if_name); 869c358c7e3Sflorian if ((if_index = if_nametoindex(if_name)) == 0) 87092f66a25Sreyk return; 871abcf5f52Sflorian 872c358c7e3Sflorian log_debug("adding interface %s", if_name); 87392f66a25Sreyk if ((ra_iface = calloc(1, sizeof(*ra_iface))) == NULL) 87492f66a25Sreyk fatal("%s", __func__); 87592f66a25Sreyk 876c358c7e3Sflorian strlcpy(ra_iface->name, if_name, sizeof(ra_iface->name)); 87792f66a25Sreyk strlcpy(ra_iface->conf_name, conf_name, 87892f66a25Sreyk sizeof(ra_iface->conf_name)); 87992f66a25Sreyk 88092f66a25Sreyk ra_iface->if_index = if_index; 881e88dba76Sflorian ra_iface->rdomain = ifrdomain; 882c358c7e3Sflorian memcpy(&ra_iface->hw_addr, &hw_addr, sizeof(hw_addr)); 88392f66a25Sreyk SIMPLEQ_INIT(&ra_iface->prefixes); 884e88dba76Sflorian 885e88dba76Sflorian ra_iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain); 88692f66a25Sreyk join_all_routers_mcast_group(ra_iface); 887e88dba76Sflorian TAILQ_INSERT_TAIL(&ra_interfaces, ra_iface, entry); 88892f66a25Sreyk } 88992f66a25Sreyk 89092f66a25Sreyk void 89153293e44Sflorian merge_ra_interfaces(void) 89253293e44Sflorian { 89353293e44Sflorian struct ra_iface_conf *ra_iface_conf; 89453293e44Sflorian struct ra_prefix_conf *ra_prefix_conf; 8954a78c7cfSflorian struct ra_iface *ra_iface; 89692f66a25Sreyk struct ifgroupreq ifgr; 89792f66a25Sreyk struct ifg_req *ifg; 898c358c7e3Sflorian struct ifaddrs *ifap; 89992f66a25Sreyk char *conf_name; 90092f66a25Sreyk unsigned int len; 90153293e44Sflorian 902c358c7e3Sflorian if (getifaddrs(&ifap) != 0) { 903c358c7e3Sflorian log_warn("getifaddrs"); 904c358c7e3Sflorian return; 905c358c7e3Sflorian } 906c358c7e3Sflorian 90753293e44Sflorian TAILQ_FOREACH(ra_iface, &ra_interfaces, entry) 90853293e44Sflorian ra_iface->removed = 1; 90953293e44Sflorian 91053293e44Sflorian SIMPLEQ_FOREACH(ra_iface_conf, &frontend_conf->ra_iface_list, entry) { 91192f66a25Sreyk conf_name = ra_iface_conf->name; 91253293e44Sflorian 91392f66a25Sreyk /* check if network interface or group */ 91492f66a25Sreyk if (isdigit((unsigned char)conf_name[strlen(conf_name) - 1])) { 915c358c7e3Sflorian merge_ra_interface(conf_name, conf_name, ifap); 91653293e44Sflorian } else { 91792f66a25Sreyk log_debug("interface group %s", conf_name); 91892f66a25Sreyk 91992f66a25Sreyk memset(&ifgr, 0, sizeof(ifgr)); 92092f66a25Sreyk strlcpy(ifgr.ifgr_name, conf_name, 92192f66a25Sreyk sizeof(ifgr.ifgr_name)); 92292f66a25Sreyk if (ioctl(ioctlsock, SIOCGIFGMEMB, 92392f66a25Sreyk (caddr_t)&ifgr) == -1) 92492f66a25Sreyk continue; 92592f66a25Sreyk 92692f66a25Sreyk len = ifgr.ifgr_len; 92792f66a25Sreyk if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) 92892f66a25Sreyk fatal("%s: calloc", __func__); 92992f66a25Sreyk if (ioctl(ioctlsock, SIOCGIFGMEMB, 93092f66a25Sreyk (caddr_t)&ifgr) == -1) { 93192f66a25Sreyk log_debug("group %s without members", 93292f66a25Sreyk conf_name); 93392f66a25Sreyk free(ifgr.ifgr_groups); 93492f66a25Sreyk continue; 93592f66a25Sreyk } 93692f66a25Sreyk 93792f66a25Sreyk for (ifg = ifgr.ifgr_groups; 93892f66a25Sreyk (ifg != NULL) && (len >= sizeof(struct ifg_req)); 93992f66a25Sreyk ifg++) { 94092f66a25Sreyk len -= sizeof(struct ifg_req); 94192f66a25Sreyk merge_ra_interface(ifg->ifgrq_member, 942c358c7e3Sflorian conf_name, ifap); 94392f66a25Sreyk } 94492f66a25Sreyk free(ifgr.ifgr_groups); 94553293e44Sflorian } 94653293e44Sflorian } 94753293e44Sflorian 94853293e44Sflorian TAILQ_FOREACH(ra_iface, &ra_interfaces, entry) { 94953293e44Sflorian while ((ra_prefix_conf = SIMPLEQ_FIRST(&ra_iface->prefixes)) 95053293e44Sflorian != NULL) { 95153293e44Sflorian SIMPLEQ_REMOVE_HEAD(&ra_iface->prefixes, 95253293e44Sflorian entry); 95353293e44Sflorian free(ra_prefix_conf); 95453293e44Sflorian } 95553293e44Sflorian ra_iface->prefix_count = 0; 95653293e44Sflorian 9574a78c7cfSflorian if (ra_iface->removed) { 9584a78c7cfSflorian log_debug("iface removed: %s", ra_iface->name); 9598c9b05a6Sflorian build_leaving_packet(ra_iface); 9604a78c7cfSflorian frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 9614a78c7cfSflorian &ra_iface->if_index, sizeof(ra_iface->if_index)); 9624a78c7cfSflorian continue; 9634a78c7cfSflorian } 9644a78c7cfSflorian 96553293e44Sflorian ra_iface_conf = find_ra_iface_conf( 96692f66a25Sreyk &frontend_conf->ra_iface_list, ra_iface->conf_name); 96753293e44Sflorian 96853293e44Sflorian log_debug("add static prefixes for %s", ra_iface->name); 96953293e44Sflorian 97053293e44Sflorian SIMPLEQ_FOREACH(ra_prefix_conf, &ra_iface_conf->ra_prefix_list, 97153293e44Sflorian entry) { 97253293e44Sflorian add_new_prefix_to_ra_iface(ra_iface, 97353293e44Sflorian &ra_prefix_conf->prefix, 97420fc6e8eSflorian ra_prefix_conf->prefixlen, ra_prefix_conf, 97520fc6e8eSflorian ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME); 97653293e44Sflorian } 977e3774183Sflorian 978e3774183Sflorian if (ra_iface_conf->autoprefix) 979e3774183Sflorian get_interface_prefixes(ra_iface, 980c358c7e3Sflorian ra_iface_conf->autoprefix, ifap); 981e3774183Sflorian 98220fc6e8eSflorian if (build_packet(ra_iface)) { 98320fc6e8eSflorian /* packet changed; send new advertisements */ 98420fc6e8eSflorian if (event_initialized(&ra_iface->icmp6ev->ev)) 98520fc6e8eSflorian frontend_imsg_compose_engine(IMSG_UPDATE_IF, 0, 98620fc6e8eSflorian &ra_iface->if_index, 98720fc6e8eSflorian sizeof(ra_iface->if_index)); 98820fc6e8eSflorian } 98953293e44Sflorian } 990c358c7e3Sflorian freeifaddrs(ifap); 99153293e44Sflorian } 99253293e44Sflorian 99353293e44Sflorian void 99453293e44Sflorian free_ra_iface(struct ra_iface *ra_iface) 99553293e44Sflorian { 99653293e44Sflorian struct ra_prefix_conf *prefix; 99753293e44Sflorian 99853293e44Sflorian leave_all_routers_mcast_group(ra_iface); 99953293e44Sflorian 100053293e44Sflorian while ((prefix = SIMPLEQ_FIRST(&ra_iface->prefixes)) != NULL) { 100153293e44Sflorian SIMPLEQ_REMOVE_HEAD(&ra_iface->prefixes, entry); 100253293e44Sflorian free(prefix); 100353293e44Sflorian } 100453293e44Sflorian 1005e88dba76Sflorian unref_icmp6ev(ra_iface); 100653293e44Sflorian free(ra_iface); 100753293e44Sflorian } 100853293e44Sflorian 100953293e44Sflorian /* from kame via ifconfig, where it's called prefix() */ 101053293e44Sflorian int 101153293e44Sflorian in6_mask2prefixlen(struct in6_addr *in6) 101253293e44Sflorian { 101353293e44Sflorian u_char *nam = (u_char *)in6; 101453293e44Sflorian int byte, bit, plen = 0, size = sizeof(struct in6_addr); 101553293e44Sflorian 101653293e44Sflorian for (byte = 0; byte < size; byte++, plen += 8) 101753293e44Sflorian if (nam[byte] != 0xff) 101853293e44Sflorian break; 101953293e44Sflorian if (byte == size) 102053293e44Sflorian return (plen); 102153293e44Sflorian for (bit = 7; bit != 0; bit--, plen++) 102253293e44Sflorian if (!(nam[byte] & (1 << bit))) 102353293e44Sflorian break; 102453293e44Sflorian for (; bit != 0; bit--) 102553293e44Sflorian if (nam[byte] & (1 << bit)) 102653293e44Sflorian return (0); 102753293e44Sflorian byte++; 102853293e44Sflorian for (; byte < size; byte++) 102953293e44Sflorian if (nam[byte]) 103053293e44Sflorian return (0); 103153293e44Sflorian return (plen); 103253293e44Sflorian } 103353293e44Sflorian 103453293e44Sflorian void 103553293e44Sflorian get_interface_prefixes(struct ra_iface *ra_iface, struct ra_prefix_conf 103620fc6e8eSflorian *autoprefix_conf, struct ifaddrs *ifap) 103753293e44Sflorian { 103853293e44Sflorian struct in6_ifreq ifr6; 1039c358c7e3Sflorian struct ifaddrs *ifa; 104053293e44Sflorian struct sockaddr_in6 *sin6; 104120fc6e8eSflorian uint32_t decaying_vltime, decaying_pltime; 104253293e44Sflorian int prefixlen; 104353293e44Sflorian 104453293e44Sflorian for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 104540019487Sbenno if (ifa->ifa_addr == NULL || 104640019487Sbenno ifa->ifa_addr->sa_family != AF_INET6) 104753293e44Sflorian continue; 104853293e44Sflorian 104920fc6e8eSflorian if (strcmp(ra_iface->name, ifa->ifa_name) != 0) 105020fc6e8eSflorian continue; 105120fc6e8eSflorian 105253293e44Sflorian sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 105353293e44Sflorian 105453293e44Sflorian if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 105553293e44Sflorian continue; 105653293e44Sflorian 105753293e44Sflorian memset(&ifr6, 0, sizeof(ifr6)); 1058d131c648Sflorian strlcpy(ifr6.ifr_name, ra_iface->name, sizeof(ifr6.ifr_name)); 105953293e44Sflorian memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); 106053293e44Sflorian 106120fc6e8eSflorian decaying_vltime = ND6_INFINITE_LIFETIME; 106220fc6e8eSflorian decaying_pltime = ND6_INFINITE_LIFETIME; 106320fc6e8eSflorian 106420fc6e8eSflorian if (ioctl(ioctlsock, SIOCGIFALIFETIME_IN6, 106520fc6e8eSflorian (caddr_t)&ifr6) != -1) { 106620fc6e8eSflorian struct in6_addrlifetime *lifetime; 106720fc6e8eSflorian 106820fc6e8eSflorian lifetime = &ifr6.ifr_ifru.ifru_lifetime; 106920fc6e8eSflorian if (lifetime->ia6t_preferred) 107020fc6e8eSflorian decaying_pltime = lifetime->ia6t_preferred; 107120fc6e8eSflorian if (lifetime->ia6t_expire) 107220fc6e8eSflorian decaying_vltime = lifetime->ia6t_expire; 107320fc6e8eSflorian } 107420fc6e8eSflorian 107520fc6e8eSflorian memset(&ifr6, 0, sizeof(ifr6)); 107620fc6e8eSflorian strlcpy(ifr6.ifr_name, ra_iface->name, sizeof(ifr6.ifr_name)); 107720fc6e8eSflorian memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); 107820fc6e8eSflorian 1079df69c215Sderaadt if (ioctl(ioctlsock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) == -1) 10801347ce87Sflorian continue; /* addr got deleted while we were looking */ 108153293e44Sflorian 108253293e44Sflorian prefixlen = in6_mask2prefixlen(&((struct sockaddr_in6 *) 108353293e44Sflorian &ifr6.ifr_addr)->sin6_addr); 108453293e44Sflorian 108553293e44Sflorian if (prefixlen == 128) 108653293e44Sflorian continue; 108753293e44Sflorian 108853293e44Sflorian mask_prefix(&sin6->sin6_addr, prefixlen); 108953293e44Sflorian 109053293e44Sflorian add_new_prefix_to_ra_iface(ra_iface, &sin6->sin6_addr, 109120fc6e8eSflorian prefixlen, autoprefix_conf, decaying_vltime, 109220fc6e8eSflorian decaying_pltime); 109353293e44Sflorian } 109453293e44Sflorian } 109553293e44Sflorian 109653293e44Sflorian struct ra_prefix_conf* 109753293e44Sflorian find_ra_prefix_conf(struct ra_prefix_conf_head* head, struct in6_addr *prefix, 109853293e44Sflorian int prefixlen) 109953293e44Sflorian { 110053293e44Sflorian struct ra_prefix_conf *ra_prefix_conf; 110153293e44Sflorian 110253293e44Sflorian SIMPLEQ_FOREACH(ra_prefix_conf, head, entry) { 110353293e44Sflorian if (ra_prefix_conf->prefixlen == prefixlen && 110453293e44Sflorian memcmp(&ra_prefix_conf->prefix, prefix, sizeof(*prefix)) == 110553293e44Sflorian 0) 110653293e44Sflorian return (ra_prefix_conf); 110753293e44Sflorian } 110853293e44Sflorian return (NULL); 110953293e44Sflorian } 111053293e44Sflorian 111153293e44Sflorian void 111253293e44Sflorian add_new_prefix_to_ra_iface(struct ra_iface *ra_iface, struct in6_addr *addr, 111320fc6e8eSflorian int prefixlen, struct ra_prefix_conf *ra_prefix_conf, 111420fc6e8eSflorian uint32_t decaying_vltime, uint32_t decaying_pltime) 111553293e44Sflorian { 111653293e44Sflorian struct ra_prefix_conf *new_ra_prefix_conf; 111753293e44Sflorian 111820fc6e8eSflorian if ((new_ra_prefix_conf = find_ra_prefix_conf(&ra_iface->prefixes, addr, 111920fc6e8eSflorian prefixlen)) != NULL) { 112020fc6e8eSflorian if (decaying_vltime != ND6_INFINITE_LIFETIME || 112120fc6e8eSflorian decaying_pltime != ND6_INFINITE_LIFETIME) { 112220fc6e8eSflorian ra_iface->ltime_decaying = 1; 112320fc6e8eSflorian new_ra_prefix_conf->ltime_decaying = 0; 112420fc6e8eSflorian if (decaying_vltime != ND6_INFINITE_LIFETIME) { 112520fc6e8eSflorian new_ra_prefix_conf->vltime = decaying_vltime; 112620fc6e8eSflorian new_ra_prefix_conf->ltime_decaying |= 112720fc6e8eSflorian VLTIME_DECAYING; 112820fc6e8eSflorian } 112920fc6e8eSflorian if (decaying_pltime != ND6_INFINITE_LIFETIME) { 113020fc6e8eSflorian new_ra_prefix_conf->pltime = decaying_pltime; 113120fc6e8eSflorian new_ra_prefix_conf->ltime_decaying |= 113220fc6e8eSflorian PLTIME_DECAYING; 113320fc6e8eSflorian } 113420fc6e8eSflorian } else if (new_ra_prefix_conf->ltime_decaying) { 113520fc6e8eSflorian struct ra_prefix_conf *pc; 113620fc6e8eSflorian 113720fc6e8eSflorian new_ra_prefix_conf->ltime_decaying = 0; 113820fc6e8eSflorian ra_iface->ltime_decaying = 0; 113920fc6e8eSflorian SIMPLEQ_FOREACH(pc, &ra_iface->prefixes, entry) { 114020fc6e8eSflorian if (pc->ltime_decaying) { 114120fc6e8eSflorian ra_iface->ltime_decaying = 1; 114220fc6e8eSflorian break; 114320fc6e8eSflorian } 114420fc6e8eSflorian } 114520fc6e8eSflorian } else 114653293e44Sflorian log_debug("ignoring duplicate %s/%d prefix", 114753293e44Sflorian in6_to_str(addr), prefixlen); 114853293e44Sflorian return; 114953293e44Sflorian } 115053293e44Sflorian 115153293e44Sflorian log_debug("adding %s/%d prefix", in6_to_str(addr), prefixlen); 115253293e44Sflorian 115353293e44Sflorian if ((new_ra_prefix_conf = calloc(1, sizeof(*ra_prefix_conf))) == NULL) 115453293e44Sflorian fatal("%s", __func__); 115553293e44Sflorian new_ra_prefix_conf->prefix = *addr; 115653293e44Sflorian new_ra_prefix_conf->prefixlen = prefixlen; 115753293e44Sflorian new_ra_prefix_conf->vltime = ra_prefix_conf->vltime; 115853293e44Sflorian new_ra_prefix_conf->pltime = ra_prefix_conf->pltime; 115920fc6e8eSflorian if (decaying_vltime != ND6_INFINITE_LIFETIME || 116020fc6e8eSflorian decaying_pltime != ND6_INFINITE_LIFETIME) { 116120fc6e8eSflorian ra_iface->ltime_decaying = 1; 116220fc6e8eSflorian if (decaying_vltime != ND6_INFINITE_LIFETIME) { 116320fc6e8eSflorian new_ra_prefix_conf->vltime = decaying_vltime; 116420fc6e8eSflorian new_ra_prefix_conf->ltime_decaying |= VLTIME_DECAYING; 116520fc6e8eSflorian } 116620fc6e8eSflorian if (decaying_pltime != ND6_INFINITE_LIFETIME) { 116720fc6e8eSflorian new_ra_prefix_conf->pltime = decaying_pltime; 116820fc6e8eSflorian new_ra_prefix_conf->ltime_decaying |= PLTIME_DECAYING; 116920fc6e8eSflorian } 117020fc6e8eSflorian } 117153293e44Sflorian new_ra_prefix_conf->aflag = ra_prefix_conf->aflag; 117253293e44Sflorian new_ra_prefix_conf->lflag = ra_prefix_conf->lflag; 117353293e44Sflorian SIMPLEQ_INSERT_TAIL(&ra_iface->prefixes, new_ra_prefix_conf, entry); 117453293e44Sflorian ra_iface->prefix_count++; 117553293e44Sflorian } 117653293e44Sflorian 117720fc6e8eSflorian int 11788c9b05a6Sflorian build_packet(struct ra_iface *ra_iface) 117953293e44Sflorian { 118053293e44Sflorian struct nd_router_advert *ra; 118130ca3407Sflorian struct nd_opt_source_link_addr *ndopt_source_link_addr; 1182cea17583Sbket struct nd_opt_mtu *ndopt_mtu; 118353293e44Sflorian struct nd_opt_prefix_info *ndopt_pi; 118453293e44Sflorian struct ra_iface_conf *ra_iface_conf; 118553293e44Sflorian struct ra_options_conf *ra_options_conf; 118653293e44Sflorian struct ra_prefix_conf *ra_prefix_conf; 11874c40b7e8Sflorian struct nd_opt_rdnss *ndopt_rdnss; 11884c40b7e8Sflorian struct nd_opt_dnssl *ndopt_dnssl; 11895207bb19Sflorian struct nd_opt_pref64 *ndopt_pref64; 11904c40b7e8Sflorian struct ra_rdnss_conf *ra_rdnss; 11914c40b7e8Sflorian struct ra_dnssl_conf *ra_dnssl; 11925207bb19Sflorian struct ra_pref64_conf *pref64; 11934c40b7e8Sflorian size_t len, label_len; 119420fc6e8eSflorian time_t t; 119520fc6e8eSflorian uint32_t vltime, pltime; 11960c40990eSflorian uint8_t *p, buf[RA_MAX_SIZE]; 11974c40b7e8Sflorian char *label_start, *label_end; 119853293e44Sflorian 119953293e44Sflorian ra_iface_conf = find_ra_iface_conf(&frontend_conf->ra_iface_list, 120092f66a25Sreyk ra_iface->conf_name); 120153293e44Sflorian ra_options_conf = &ra_iface_conf->ra_options; 120220fc6e8eSflorian t = time(NULL); 12030c40990eSflorian len = sizeof(*ra); 120430ca3407Sflorian if (ra_iface_conf->ra_options.source_link_addr) 120530ca3407Sflorian len += sizeof(*ndopt_source_link_addr); 1206cea17583Sbket if (ra_options_conf->mtu > 0) 1207cea17583Sbket len += sizeof(*ndopt_mtu); 12080c40990eSflorian len += sizeof(*ndopt_pi) * ra_iface->prefix_count; 12098815eebdSflorian if (ra_iface_conf->ra_options.rdnss_count > 0) 12108815eebdSflorian len += sizeof(*ndopt_rdnss) + 12118815eebdSflorian ra_iface_conf->ra_options.rdnss_count * 12124c40b7e8Sflorian sizeof(struct in6_addr); 12134c40b7e8Sflorian 12148815eebdSflorian if (ra_iface_conf->ra_options.dnssl_len > 0) 12154c40b7e8Sflorian /* round up to 8 byte boundary */ 12168815eebdSflorian len += sizeof(*ndopt_dnssl) + 12178815eebdSflorian ((ra_iface_conf->ra_options.dnssl_len + 7) & ~7); 121853293e44Sflorian 12195207bb19Sflorian SIMPLEQ_FOREACH(pref64, &ra_iface_conf->ra_options.ra_pref64_list, 12205207bb19Sflorian entry) 12215207bb19Sflorian len += sizeof(struct nd_opt_pref64); 12225207bb19Sflorian 12230c40990eSflorian if (len > sizeof(ra_iface->data)) 122451a61992Spamela fatalx("%s: packet too big", __func__); /* XXX send multiple */ 122553293e44Sflorian 12260c40990eSflorian p = buf; 122753293e44Sflorian 12280c40990eSflorian ra = (struct nd_router_advert *)p; 122953293e44Sflorian 123053293e44Sflorian memset(ra, 0, sizeof(*ra)); 123153293e44Sflorian 123253293e44Sflorian ra->nd_ra_type = ND_ROUTER_ADVERT; 123353293e44Sflorian ra->nd_ra_curhoplimit = ra_options_conf->cur_hl; 123453293e44Sflorian if (ra_options_conf->m_flag) 123553293e44Sflorian ra->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; 123653293e44Sflorian if (ra_options_conf->o_flag) 123753293e44Sflorian ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER; 12380c40990eSflorian if (ra_iface->removed) 12390c40990eSflorian /* tell clients that we are no longer a default router */ 12400c40990eSflorian ra->nd_ra_router_lifetime = 0; 12410c40990eSflorian else if (ra_options_conf->dfr) { 124253293e44Sflorian ra->nd_ra_router_lifetime = 124353293e44Sflorian htons(ra_options_conf->router_lifetime); 1244639a58baSflorian /* 1245639a58baSflorian * RFC 4191 1246639a58baSflorian * If the Router Lifetime is zero, the preference value MUST be 1247639a58baSflorian * set to (00) by the sender and MUST be ignored by the 1248639a58baSflorian * receiver. 1249639a58baSflorian */ 1250639a58baSflorian if (ra_options_conf->router_lifetime > 0) 1251639a58baSflorian ra->nd_ra_flags_reserved |= ra_options_conf->rtpref; 12520c40990eSflorian } 125353293e44Sflorian ra->nd_ra_reachable = htonl(ra_options_conf->reachable_time); 125453293e44Sflorian ra->nd_ra_retransmit = htonl(ra_options_conf->retrans_timer); 12550c40990eSflorian p += sizeof(*ra); 125653293e44Sflorian 125730ca3407Sflorian if (ra_iface_conf->ra_options.source_link_addr) { 125830ca3407Sflorian ndopt_source_link_addr = (struct nd_opt_source_link_addr *)p; 125930ca3407Sflorian ndopt_source_link_addr->nd_opt_source_link_addr_type = 126030ca3407Sflorian ND_OPT_SOURCE_LINKADDR; 126130ca3407Sflorian ndopt_source_link_addr->nd_opt_source_link_addr_len = 1; 1262c358c7e3Sflorian memcpy(&ndopt_source_link_addr->nd_opt_source_link_addr_hw_addr, 1263c358c7e3Sflorian &ra_iface->hw_addr, ETHER_ADDR_LEN); 126430ca3407Sflorian p += sizeof(*ndopt_source_link_addr); 126530ca3407Sflorian } 126630ca3407Sflorian 1267cea17583Sbket if (ra_options_conf->mtu > 0) { 1268cea17583Sbket ndopt_mtu = (struct nd_opt_mtu *)p; 1269cea17583Sbket ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; 1270cea17583Sbket ndopt_mtu->nd_opt_mtu_len = 1; 1271cea17583Sbket ndopt_mtu->nd_opt_mtu_reserved = 0; 1272cea17583Sbket ndopt_mtu->nd_opt_mtu_mtu = htonl(ra_options_conf->mtu); 1273cea17583Sbket p += sizeof(*ndopt_mtu); 1274cea17583Sbket } 1275cea17583Sbket 127653293e44Sflorian SIMPLEQ_FOREACH(ra_prefix_conf, &ra_iface->prefixes, entry) { 12770c40990eSflorian ndopt_pi = (struct nd_opt_prefix_info *)p; 127853293e44Sflorian memset(ndopt_pi, 0, sizeof(*ndopt_pi)); 127953293e44Sflorian ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 128053293e44Sflorian ndopt_pi->nd_opt_pi_len = 4; 128153293e44Sflorian ndopt_pi->nd_opt_pi_prefix_len = ra_prefix_conf->prefixlen; 128253293e44Sflorian if (ra_prefix_conf->lflag) 128353293e44Sflorian ndopt_pi->nd_opt_pi_flags_reserved |= 128453293e44Sflorian ND_OPT_PI_FLAG_ONLINK; 128553293e44Sflorian if (ra_prefix_conf->aflag) 128653293e44Sflorian ndopt_pi->nd_opt_pi_flags_reserved |= 128753293e44Sflorian ND_OPT_PI_FLAG_AUTO; 128820fc6e8eSflorian 128920fc6e8eSflorian if (ra_prefix_conf->ltime_decaying & VLTIME_DECAYING) 129020fc6e8eSflorian vltime = ra_prefix_conf->vltime < t ? 0 : 129120fc6e8eSflorian ra_prefix_conf->vltime - t; 129220fc6e8eSflorian else 129320fc6e8eSflorian vltime = ra_prefix_conf->vltime; 129420fc6e8eSflorian if (ra_prefix_conf->ltime_decaying & PLTIME_DECAYING) 129520fc6e8eSflorian pltime = ra_prefix_conf->pltime < t ? 0 : 129620fc6e8eSflorian ra_prefix_conf->pltime - t; 129720fc6e8eSflorian else 129820fc6e8eSflorian pltime = ra_prefix_conf->pltime; 129920fc6e8eSflorian 130020fc6e8eSflorian ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); 130120fc6e8eSflorian ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); 130253293e44Sflorian ndopt_pi->nd_opt_pi_prefix = ra_prefix_conf->prefix; 130353293e44Sflorian 13040c40990eSflorian p += sizeof(*ndopt_pi); 13050c40990eSflorian } 13060c40990eSflorian 13078815eebdSflorian if (ra_iface_conf->ra_options.rdnss_count > 0) { 13084c40b7e8Sflorian ndopt_rdnss = (struct nd_opt_rdnss *)p; 13094c40b7e8Sflorian ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS; 13104c40b7e8Sflorian ndopt_rdnss->nd_opt_rdnss_len = 1 + 13118815eebdSflorian ra_iface_conf->ra_options.rdnss_count * 2; 13124c40b7e8Sflorian ndopt_rdnss->nd_opt_rdnss_reserved = 0; 13134c40b7e8Sflorian ndopt_rdnss->nd_opt_rdnss_lifetime = 13148815eebdSflorian htonl(ra_iface_conf->ra_options.rdns_lifetime); 13154c40b7e8Sflorian p += sizeof(struct nd_opt_rdnss); 13168815eebdSflorian SIMPLEQ_FOREACH(ra_rdnss, 13178815eebdSflorian &ra_iface_conf->ra_options.ra_rdnss_list, entry) { 13184c40b7e8Sflorian memcpy(p, &ra_rdnss->rdnss, sizeof(ra_rdnss->rdnss)); 13194c40b7e8Sflorian p += sizeof(ra_rdnss->rdnss); 13204c40b7e8Sflorian } 13214c40b7e8Sflorian } 13224c40b7e8Sflorian 13238815eebdSflorian if (ra_iface_conf->ra_options.dnssl_len > 0) { 13244c40b7e8Sflorian ndopt_dnssl = (struct nd_opt_dnssl *)p; 13254c40b7e8Sflorian ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL; 13264c40b7e8Sflorian /* round up to 8 byte boundary */ 13274c40b7e8Sflorian ndopt_dnssl->nd_opt_dnssl_len = 1 + 13288815eebdSflorian ((ra_iface_conf->ra_options.dnssl_len + 7) & ~7) / 8; 13294c40b7e8Sflorian ndopt_dnssl->nd_opt_dnssl_reserved = 0; 13304c40b7e8Sflorian ndopt_dnssl->nd_opt_dnssl_lifetime = 13318815eebdSflorian htonl(ra_iface_conf->ra_options.rdns_lifetime); 13324c40b7e8Sflorian p += sizeof(struct nd_opt_dnssl); 13334c40b7e8Sflorian 13348815eebdSflorian SIMPLEQ_FOREACH(ra_dnssl, 13358815eebdSflorian &ra_iface_conf->ra_options.ra_dnssl_list, entry) { 13364c40b7e8Sflorian label_start = ra_dnssl->search; 13374c40b7e8Sflorian while ((label_end = strchr(label_start, '.')) != NULL) { 13384c40b7e8Sflorian label_len = label_end - label_start; 13394c40b7e8Sflorian *p++ = label_len; 13404c40b7e8Sflorian memcpy(p, label_start, label_len); 13414c40b7e8Sflorian p += label_len; 13424c40b7e8Sflorian label_start = label_end + 1; 13434c40b7e8Sflorian } 13444c40b7e8Sflorian *p++ = '\0'; /* last dot */ 13454c40b7e8Sflorian } 13464c40b7e8Sflorian /* zero pad */ 13474c40b7e8Sflorian while (((uintptr_t)p) % 8 != 0) 13484c40b7e8Sflorian *p++ = '\0'; 13494c40b7e8Sflorian } 13504c40b7e8Sflorian 13515207bb19Sflorian SIMPLEQ_FOREACH(pref64, &ra_iface_conf->ra_options.ra_pref64_list, 13525207bb19Sflorian entry) { 13535207bb19Sflorian uint16_t sltime_plc; 13545207bb19Sflorian 13555207bb19Sflorian /* scaled lifetime in units of 8 seconds */ 13565207bb19Sflorian sltime_plc = pref64->ltime / 8; 13575207bb19Sflorian sltime_plc = sltime_plc << 3; 13583a50f0a9Sjmc /* encode prefix length in lower 3 bits */ 13595207bb19Sflorian switch (pref64->prefixlen) { 13605207bb19Sflorian case 96: 13615207bb19Sflorian sltime_plc |= 0; 13625207bb19Sflorian break; 13635207bb19Sflorian case 64: 13645207bb19Sflorian sltime_plc |= 1; 13655207bb19Sflorian break; 13665207bb19Sflorian case 56: 13675207bb19Sflorian sltime_plc |= 2; 13685207bb19Sflorian break; 13695207bb19Sflorian case 48: 13705207bb19Sflorian sltime_plc |= 3; 13715207bb19Sflorian break; 13725207bb19Sflorian case 40: 13735207bb19Sflorian sltime_plc |= 4; 13745207bb19Sflorian break; 13755207bb19Sflorian case 32: 13765207bb19Sflorian sltime_plc |= 5; 13775207bb19Sflorian break; 13785207bb19Sflorian default: 13795207bb19Sflorian fatalx("%s: invalid pref64 length: %d", __func__, 13805207bb19Sflorian pref64->prefixlen); 13815207bb19Sflorian } 13825207bb19Sflorian ndopt_pref64 = (struct nd_opt_pref64 *)p; 13835207bb19Sflorian ndopt_pref64->nd_opt_pref64_type = ND_OPT_PREF64; 13845207bb19Sflorian ndopt_pref64->nd_opt_pref64_len = 2; 13855207bb19Sflorian ndopt_pref64->nd_opt_pref64_sltime_plc = htons(sltime_plc); 13865207bb19Sflorian memcpy(ndopt_pref64->nd_opt_pref64, &pref64->prefix, 13875207bb19Sflorian sizeof(ndopt_pref64->nd_opt_pref64)); 13885207bb19Sflorian p += sizeof(struct nd_opt_pref64); 13895207bb19Sflorian } 13905207bb19Sflorian 13910c40990eSflorian if (len != ra_iface->datalen || memcmp(buf, ra_iface->data, len) 13920c40990eSflorian != 0) { 13930c40990eSflorian memcpy(ra_iface->data, buf, len); 13940c40990eSflorian ra_iface->datalen = len; 139520fc6e8eSflorian return 1; 139653293e44Sflorian } 139720fc6e8eSflorian return 0; 139853293e44Sflorian } 139953293e44Sflorian 140053293e44Sflorian void 14018c9b05a6Sflorian build_leaving_packet(struct ra_iface *ra_iface) 14024a78c7cfSflorian { 14034a78c7cfSflorian struct nd_router_advert ra; 14044a78c7cfSflorian 14054a78c7cfSflorian memset(&ra, 0, sizeof(ra)); 14064a78c7cfSflorian 14074a78c7cfSflorian ra.nd_ra_type = ND_ROUTER_ADVERT; 14084a78c7cfSflorian 14094a78c7cfSflorian memcpy(ra_iface->data, &ra, sizeof(ra)); 14104a78c7cfSflorian ra_iface->datalen = sizeof(ra); 14114a78c7cfSflorian } 14124a78c7cfSflorian 14134a78c7cfSflorian void 141453293e44Sflorian ra_output(struct ra_iface *ra_iface, struct sockaddr_in6 *to) 141553293e44Sflorian { 141653293e44Sflorian 141753293e44Sflorian struct cmsghdr *cm; 141853293e44Sflorian struct in6_pktinfo *pi; 141953293e44Sflorian ssize_t len; 142053293e44Sflorian int hoplimit = 255; 142153293e44Sflorian 1422abcf5f52Sflorian if (!LINK_STATE_IS_UP(ra_iface->link_state)) 1423abcf5f52Sflorian return; 1424abcf5f52Sflorian 142520fc6e8eSflorian if (ra_iface->ltime_decaying) 142620fc6e8eSflorian /* update vltime & pltime */ 142720fc6e8eSflorian build_packet(ra_iface); 142820fc6e8eSflorian 142953293e44Sflorian sndmhdr.msg_name = to; 143053293e44Sflorian sndmhdr.msg_iov[0].iov_base = ra_iface->data; 143153293e44Sflorian sndmhdr.msg_iov[0].iov_len = ra_iface->datalen; 143253293e44Sflorian 143353293e44Sflorian cm = CMSG_FIRSTHDR(&sndmhdr); 143453293e44Sflorian /* specify the outgoing interface */ 143553293e44Sflorian cm->cmsg_level = IPPROTO_IPV6; 143653293e44Sflorian cm->cmsg_type = IPV6_PKTINFO; 143753293e44Sflorian cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 143853293e44Sflorian pi = (struct in6_pktinfo *)CMSG_DATA(cm); 143953293e44Sflorian memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); 144053293e44Sflorian pi->ipi6_ifindex = ra_iface->if_index; 144153293e44Sflorian 144253293e44Sflorian /* specify the hop limit of the packet */ 144353293e44Sflorian cm = CMSG_NXTHDR(&sndmhdr, cm); 144453293e44Sflorian cm->cmsg_level = IPPROTO_IPV6; 144553293e44Sflorian cm->cmsg_type = IPV6_HOPLIMIT; 144653293e44Sflorian cm->cmsg_len = CMSG_LEN(sizeof(int)); 144753293e44Sflorian memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); 144853293e44Sflorian 144953293e44Sflorian log_debug("send RA on %s", ra_iface->name); 145053293e44Sflorian 1451e88dba76Sflorian len = sendmsg(EVENT_FD(&ra_iface->icmp6ev->ev), &sndmhdr, 0); 1452df69c215Sderaadt if (len == -1) 145353293e44Sflorian log_warn("sendmsg on %s", ra_iface->name); 145453293e44Sflorian 145553293e44Sflorian } 145648e174fdSflorian 145748e174fdSflorian #define ROUNDUP(a) \ 145848e174fdSflorian ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 145948e174fdSflorian 146048e174fdSflorian void 146148e174fdSflorian get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 146248e174fdSflorian { 146348e174fdSflorian int i; 146448e174fdSflorian 146548e174fdSflorian for (i = 0; i < RTAX_MAX; i++) { 146648e174fdSflorian if (addrs & (1 << i)) { 146748e174fdSflorian rti_info[i] = sa; 146848e174fdSflorian sa = (struct sockaddr *)((char *)(sa) + 146948e174fdSflorian ROUNDUP(sa->sa_len)); 147048e174fdSflorian } else 147148e174fdSflorian rti_info[i] = NULL; 147248e174fdSflorian } 147348e174fdSflorian } 147448e174fdSflorian 147548e174fdSflorian void 147648e174fdSflorian route_receive(int fd, short events, void *arg) 147748e174fdSflorian { 147848e174fdSflorian static uint8_t *buf; 147948e174fdSflorian 148048e174fdSflorian struct rt_msghdr *rtm; 148148e174fdSflorian struct sockaddr *sa, *rti_info[RTAX_MAX]; 148248e174fdSflorian ssize_t n; 148348e174fdSflorian 148448e174fdSflorian if (buf == NULL) { 148548e174fdSflorian buf = malloc(ROUTE_SOCKET_BUF_SIZE); 148648e174fdSflorian if (buf == NULL) 148748e174fdSflorian fatal("malloc"); 148848e174fdSflorian } 148948e174fdSflorian rtm = (struct rt_msghdr *)buf; 149048e174fdSflorian if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) { 149148e174fdSflorian if (errno == EAGAIN || errno == EINTR) 149248e174fdSflorian return; 149348e174fdSflorian log_warn("dispatch_rtmsg: read error"); 149448e174fdSflorian return; 149548e174fdSflorian } 149648e174fdSflorian 149748e174fdSflorian if (n == 0) 149848e174fdSflorian fatal("routing socket closed"); 149948e174fdSflorian 150048e174fdSflorian if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) { 150148e174fdSflorian log_warnx("partial rtm of %zd in buffer", n); 150248e174fdSflorian return; 150348e174fdSflorian } 150448e174fdSflorian 150548e174fdSflorian if (rtm->rtm_version != RTM_VERSION) 150648e174fdSflorian return; 150748e174fdSflorian 150848e174fdSflorian sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen); 150948e174fdSflorian get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 151048e174fdSflorian 151148e174fdSflorian handle_route_message(rtm, rti_info); 151248e174fdSflorian } 151348e174fdSflorian 151448e174fdSflorian void 151548e174fdSflorian handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) 151648e174fdSflorian { 15172ccdd6f1Sflorian switch (rtm->rtm_type) { 15182ccdd6f1Sflorian case RTM_IFINFO: 15192ccdd6f1Sflorian case RTM_NEWADDR: 15202ccdd6f1Sflorian case RTM_DELADDR: 1521e88dba76Sflorian case RTM_CHGADDRATTR: 15222ccdd6f1Sflorian /* 15232ccdd6f1Sflorian * do the same thing as after a config reload when interfaces 15242ccdd6f1Sflorian * change or IPv6 addresses show up / disappear 15252ccdd6f1Sflorian */ 15262ccdd6f1Sflorian merge_ra_interfaces(); 15272ccdd6f1Sflorian break; 15282ccdd6f1Sflorian default: 15292ccdd6f1Sflorian log_debug("unexpected RTM: %d", rtm->rtm_type); 15302ccdd6f1Sflorian break; 15312ccdd6f1Sflorian } 153248e174fdSflorian } 1533e88dba76Sflorian 1534e88dba76Sflorian struct icmp6_ev* 1535e88dba76Sflorian get_icmp6ev_by_rdomain(int rdomain) 1536e88dba76Sflorian { 1537e88dba76Sflorian struct ra_iface *ra_iface; 1538e88dba76Sflorian struct icmp6_ev *icmp6ev = NULL; 1539e88dba76Sflorian 1540e88dba76Sflorian TAILQ_FOREACH (ra_iface, &ra_interfaces, entry) { 1541e88dba76Sflorian if (ra_iface->rdomain == rdomain) { 1542e88dba76Sflorian icmp6ev = ra_iface->icmp6ev; 1543e88dba76Sflorian break; 1544e88dba76Sflorian } 1545e88dba76Sflorian } 1546e88dba76Sflorian 1547e88dba76Sflorian if (icmp6ev == NULL) { 1548e88dba76Sflorian if ((icmp6ev = calloc(1, sizeof(*icmp6ev))) == NULL) 1549e88dba76Sflorian fatal("calloc"); 1550e88dba76Sflorian 1551e88dba76Sflorian icmp6ev->rcviov[0].iov_base = (caddr_t)icmp6ev->answer; 1552e88dba76Sflorian icmp6ev->rcviov[0].iov_len = sizeof(icmp6ev->answer); 1553e88dba76Sflorian icmp6ev->rcvmhdr.msg_name = (caddr_t)&icmp6ev->from; 1554e88dba76Sflorian icmp6ev->rcvmhdr.msg_namelen = sizeof(icmp6ev->from); 1555e88dba76Sflorian icmp6ev->rcvmhdr.msg_iov = icmp6ev->rcviov; 1556e88dba76Sflorian icmp6ev->rcvmhdr.msg_iovlen = 1; 1557e88dba76Sflorian icmp6ev->rcvmhdr.msg_controllen = 1558e88dba76Sflorian CMSG_SPACE(sizeof(struct in6_pktinfo)) + 1559e88dba76Sflorian CMSG_SPACE(sizeof(int)); 1560e88dba76Sflorian if ((icmp6ev->rcvmhdr.msg_control = malloc(icmp6ev-> 1561e88dba76Sflorian rcvmhdr.msg_controllen)) == NULL) 1562e88dba76Sflorian fatal("malloc"); 1563e88dba76Sflorian frontend_imsg_compose_main(IMSG_OPEN_ICMP6SOCK, 0, 1564e88dba76Sflorian &rdomain, sizeof(rdomain)); 1565e88dba76Sflorian } 1566e88dba76Sflorian 1567e88dba76Sflorian icmp6ev->refcnt++; 1568e88dba76Sflorian return (icmp6ev); 1569e88dba76Sflorian } 1570e88dba76Sflorian 1571e88dba76Sflorian void 1572e88dba76Sflorian unref_icmp6ev(struct ra_iface *ra_iface) 1573e88dba76Sflorian { 1574e88dba76Sflorian struct icmp6_ev *icmp6ev = ra_iface->icmp6ev; 1575e88dba76Sflorian 1576e88dba76Sflorian ra_iface->icmp6ev = NULL; 1577e88dba76Sflorian 1578e88dba76Sflorian if (icmp6ev != NULL) { 1579e88dba76Sflorian icmp6ev->refcnt--; 1580e88dba76Sflorian if (icmp6ev->refcnt == 0) { 1581e88dba76Sflorian event_del(&icmp6ev->ev); 1582e88dba76Sflorian close(EVENT_FD(&icmp6ev->ev)); 1583e88dba76Sflorian free(icmp6ev); 1584e88dba76Sflorian } 1585e88dba76Sflorian } 1586e88dba76Sflorian } 1587e88dba76Sflorian 1588e88dba76Sflorian void 1589e88dba76Sflorian set_icmp6sock(int icmp6sock, int rdomain) 1590e88dba76Sflorian { 1591e88dba76Sflorian struct ra_iface *ra_iface; 1592e88dba76Sflorian 1593e88dba76Sflorian TAILQ_FOREACH (ra_iface, &ra_interfaces, entry) { 1594e88dba76Sflorian if (!event_initialized(&ra_iface->icmp6ev->ev) && 1595e88dba76Sflorian ra_iface->rdomain == rdomain) { 1596e88dba76Sflorian event_set(&ra_iface->icmp6ev->ev, icmp6sock, EV_READ | 1597e88dba76Sflorian EV_PERSIST, icmp6_receive, ra_iface->icmp6ev); 1598e88dba76Sflorian event_add(&ra_iface->icmp6ev->ev, NULL); 1599e88dba76Sflorian icmp6sock = -1; 1600e88dba76Sflorian break; 1601e88dba76Sflorian } 1602e88dba76Sflorian } 1603e88dba76Sflorian 1604e88dba76Sflorian if (icmp6sock != -1) { 1605e88dba76Sflorian /* 1606e88dba76Sflorian * The interface disappeared or changed rdomain while we were 1607e88dba76Sflorian * waiting for the parent process to open the raw socket. 1608e88dba76Sflorian */ 1609e88dba76Sflorian close(icmp6sock); 1610e88dba76Sflorian return; 1611e88dba76Sflorian } 1612e88dba76Sflorian 1613e88dba76Sflorian TAILQ_FOREACH (ra_iface, &ra_interfaces, entry) { 1614e88dba76Sflorian if (ra_iface->rdomain == rdomain) { 1615e88dba76Sflorian join_all_routers_mcast_group(ra_iface); 1616e88dba76Sflorian frontend_imsg_compose_engine(IMSG_UPDATE_IF, 0, 1617e88dba76Sflorian &ra_iface->if_index, sizeof(ra_iface->if_index)); 1618e88dba76Sflorian } 1619e88dba76Sflorian } 1620e88dba76Sflorian } 1621