On Sun, Nov 29, 2020 at 12:20:31PM +0100, Florian Obser wrote: > > Let rad(8) handle all rdomains in a single daemon, similar to previous > work in slaacd. > > Suggested / requested by tb who showed me previous work by reyk which > unfortunately predated my work in slaacd and followed a different > pattern. > > There has already been a fair bit of testing and input from tb on > previous iterations. > > More tests, OKs? >
Updated diff after some testing by tb@ - our AF_ROUTE socket needs a RTABLE_ANY ROUTE_TABLEFILTER otherwise we don't see link-local addresses arriving in rdomains != 0. - check if the arriving link-local address is tentative (or a douplicate) and ignore it because we can't use it and sendmsg failes. Monitor RTM_CHGADDRATTR messages to see when the link-local address becomes valid diff --git frontend.c frontend.c index 8947f616e73..c9c63b0cb6b 100644 --- frontend.c +++ frontend.c @@ -95,19 +95,22 @@ struct icmp6_ev { struct msghdr rcvmhdr; struct iovec rcviov[1]; struct sockaddr_in6 from; -} icmp6ev; + int refcnt; +}; struct ra_iface { - TAILQ_ENTRY(ra_iface) entry; - struct ra_prefix_conf_head prefixes; - char name[IF_NAMESIZE]; - char conf_name[IF_NAMESIZE]; - uint32_t if_index; - int removed; - int link_state; - int prefix_count; - size_t datalen; - uint8_t data[RA_MAX_SIZE]; + TAILQ_ENTRY(ra_iface) entry; + struct icmp6_ev *icmp6ev; + struct ra_prefix_conf_head prefixes; + char name[IF_NAMESIZE]; + char conf_name[IF_NAMESIZE]; + uint32_t if_index; + int rdomain; + int removed; + int link_state; + int prefix_count; + size_t datalen; + uint8_t data[RA_MAX_SIZE]; }; TAILQ_HEAD(, ra_iface) ra_interfaces; @@ -119,6 +122,7 @@ void icmp6_receive(int, short, void *); void join_all_routers_mcast_group(struct ra_iface *); void leave_all_routers_mcast_group(struct ra_iface *); int get_link_state(char *); +int get_ifrdomain(char *); void merge_ra_interface(char *, char *); void merge_ra_interfaces(void); struct ra_iface *find_ra_iface_by_id(uint32_t); @@ -127,6 +131,9 @@ struct ra_iface_conf *find_ra_iface_conf(struct ra_iface_conf_head *, char *); struct ra_prefix_conf *find_ra_prefix_conf(struct ra_prefix_conf_head*, struct in6_addr *, int); +struct icmp6_ev *get_icmp6ev_by_rdomain(int); +void unref_icmp6ev(struct ra_iface *); +void set_icmp6sock(int, int); void add_new_prefix_to_ra_iface(struct ra_iface *r, struct in6_addr *, int, struct ra_prefix_conf *); void free_ra_iface(struct ra_iface *); @@ -147,7 +154,7 @@ struct rad_conf *frontend_conf; struct imsgev *iev_main; struct imsgev *iev_engine; struct event ev_route; -int icmp6sock = -1, ioctlsock = -1, routesock = -1; +int ioctlsock = -1, routesock = -1; struct ipv6_mreq all_routers; struct sockaddr_in6 all_nodes; struct msghdr sndmhdr; @@ -175,8 +182,7 @@ frontend(int debug, int verbose) { struct event ev_sigint, ev_sigterm; struct passwd *pw; - size_t rcvcmsglen, sndcmsgbuflen; - uint8_t *rcvcmsgbuf; + size_t sndcmsgbuflen; uint8_t *sndcmsgbuf = NULL; frontend_conf = config_new_empty(); @@ -229,20 +235,6 @@ frontend(int debug, int verbose) iev_main->handler, iev_main); event_add(&iev_main->ev, NULL); - rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + - CMSG_SPACE(sizeof(int)); - if((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) - fatal("malloc"); - - icmp6ev.rcviov[0].iov_base = (caddr_t)icmp6ev.answer; - icmp6ev.rcviov[0].iov_len = sizeof(icmp6ev.answer); - icmp6ev.rcvmhdr.msg_name = (caddr_t)&icmp6ev.from; - icmp6ev.rcvmhdr.msg_namelen = sizeof(icmp6ev.from); - icmp6ev.rcvmhdr.msg_iov = icmp6ev.rcviov; - icmp6ev.rcvmhdr.msg_iovlen = 1; - icmp6ev.rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; - icmp6ev.rcvmhdr.msg_controllen = rcvcmsglen; - if (inet_pton(AF_INET6, "ff02::2", &all_routers.ipv6mr_multiaddr.s6_addr) == -1) fatal("inet_pton"); @@ -316,7 +308,7 @@ frontend_dispatch_main(int fd, short event, void *bula) struct ra_prefix_conf *ra_prefix_conf; struct ra_rdnss_conf *ra_rdnss_conf; struct ra_dnssl_conf *ra_dnssl_conf; - int n, shut = 0; + int n, shut = 0, icmp6sock, rdomain; if (event & EV_READ) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) @@ -414,7 +406,7 @@ frontend_dispatch_main(int fd, short event, void *bula) ra_prefix_conf)) fatalx("%s: IMSG_RECONF_RA_PREFIX wrong " "length: %lu", __func__, - IMSG_DATA_SIZE(imsg)); + IMSG_DATA_SIZE(imsg)); if ((ra_prefix_conf = malloc(sizeof(struct ra_prefix_conf))) == NULL) fatal(NULL); @@ -458,15 +450,15 @@ frontend_dispatch_main(int fd, short event, void *bula) nconf = NULL; break; case IMSG_ICMP6SOCK: - if (icmp6sock != -1) - fatalx("%s: received unexpected icmp6 fd", - __func__); if ((icmp6sock = imsg.fd) == -1) fatalx("%s: expected to receive imsg " "ICMPv6 fd but didn't receive any", __func__); - event_set(&icmp6ev.ev, icmp6sock, EV_READ | EV_PERSIST, - icmp6_receive, NULL); + if (IMSG_DATA_SIZE(imsg) != sizeof(rdomain)) + fatalx("%s: IMSG_ICMP6SOCK wrong length: " + "%lu", __func__, IMSG_DATA_SIZE(imsg)); + memcpy(&rdomain, imsg.data, sizeof(rdomain)); + set_icmp6sock(icmp6sock, rdomain); break; case IMSG_ROUTESOCK: if (routesock != -1) @@ -480,8 +472,6 @@ frontend_dispatch_main(int fd, short event, void *bula) route_receive, NULL); break; case IMSG_STARTUP: - if (pledge("stdio inet unix route mcast", NULL) == -1) - fatal("pledge"); frontend_startup(); break; case IMSG_CONTROLFD: @@ -588,20 +578,14 @@ frontend_startup(void) "process", __func__); event_add(&ev_route, NULL); - - if (!event_initialized(&icmp6ev.ev)) - fatalx("%s: did not receive a icmp6 socket fd from the main " - "process", __func__); - - event_add(&icmp6ev.ev, NULL); - - frontend_imsg_compose_main(IMSG_STARTUP_DONE, 0, NULL, 0); } void icmp6_receive(int fd, short events, void *arg) { + struct icmp6_ev *icmp6ev; + struct icmp6_hdr *icmp6_hdr; struct imsg_ra_rs ra_rs; struct in6_pktinfo *pi = NULL; struct cmsghdr *cm; @@ -609,14 +593,23 @@ icmp6_receive(int fd, short events, void *arg) int if_index = 0, *hlimp = NULL; char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; - if ((len = recvmsg(fd, &icmp6ev.rcvmhdr, 0)) == -1) { + icmp6ev = arg; + if ((len = recvmsg(fd, &icmp6ev->rcvmhdr, 0)) == -1) { log_warn("recvmsg"); return; } + if ((size_t)len < sizeof(struct icmp6_hdr)) + return; + + icmp6_hdr = (struct icmp6_hdr *)icmp6ev->answer; + if (icmp6_hdr->icmp6_type != ND_ROUTER_ADVERT && + icmp6_hdr->icmp6_type != ND_ROUTER_SOLICIT) + return; + /* extract optional information via Advanced API */ - for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev.rcvmhdr); cm; - cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev.rcvmhdr, cm)) { + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev->rcvmhdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev->rcvmhdr, cm)) { if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO && cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { @@ -641,29 +634,29 @@ icmp6_receive(int fd, short events, void *arg) if (*hlimp != 255) { log_warnx("invalid RA or RS with hop limit of %d from %s on %s", - *hlimp, inet_ntop(AF_INET6, &icmp6ev.from.sin6_addr, + *hlimp, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index, ifnamebuf)); return; } log_debug("RA or RS with hop limit of %d from %s on %s", - *hlimp, inet_ntop(AF_INET6, &icmp6ev.from.sin6_addr, + *hlimp, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index, ifnamebuf)); if ((size_t)len > sizeof(ra_rs.packet)) { log_warnx("invalid RA or RS with size %ld from %s on %s", - len, inet_ntop(AF_INET6, &icmp6ev.from.sin6_addr, + len, inet_ntop(AF_INET6, &icmp6ev->from.sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index, ifnamebuf)); return; } ra_rs.if_index = if_index; - memcpy(&ra_rs.from, &icmp6ev.from, sizeof(ra_rs.from)); + memcpy(&ra_rs.from, &icmp6ev->from, sizeof(ra_rs.from)); ra_rs.len = len; - memcpy(ra_rs.packet, icmp6ev.answer, len); + memcpy(ra_rs.packet, icmp6ev->answer, len); frontend_imsg_compose_engine(IMSG_RA_RS, 0, &ra_rs, sizeof(ra_rs)); } @@ -671,20 +664,24 @@ icmp6_receive(int fd, short events, void *arg) void join_all_routers_mcast_group(struct ra_iface *ra_iface) { + if (!event_initialized(&ra_iface->icmp6ev->ev)) + return; log_debug("joining multicast group on %s", ra_iface->name); all_routers.ipv6mr_interface = ra_iface->if_index; - if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, - &all_routers, sizeof(all_routers)) == -1) + if (setsockopt(EVENT_FD(&ra_iface->icmp6ev->ev), IPPROTO_IPV6, + IPV6_JOIN_GROUP, &all_routers, sizeof(all_routers)) == -1) fatal("IPV6_JOIN_GROUP(%s)", ra_iface->name); } void leave_all_routers_mcast_group(struct ra_iface *ra_iface) { + if (!event_initialized(&ra_iface->icmp6ev->ev)) + return; log_debug("leaving multicast group on %s", ra_iface->name); all_routers.ipv6mr_interface = ra_iface->if_index; - setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, - &all_routers, sizeof(all_routers)); + setsockopt(EVENT_FD(&ra_iface->icmp6ev->ev), IPPROTO_IPV6, + IPV6_LEAVE_GROUP, &all_routers, sizeof(all_routers)); } struct ra_iface* @@ -746,15 +743,29 @@ get_link_state(char *if_name) return ls; } +int +get_ifrdomain(char *if_name) +{ + struct ifreq ifr; + + (void) strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); + if (ioctl(ioctlsock, SIOCGIFRDOMAIN, (caddr_t)&ifr) == -1) { + log_warn("SIOCGIFRDOMAIN"); + return -1; + } + return ifr.ifr_rdomainid; +} + void merge_ra_interface(char *name, char *conf_name) { struct ra_iface *ra_iface; uint32_t if_index; - int link_state, has_linklocal; + int link_state, has_linklocal, ifrdomain; link_state = get_link_state(name); has_linklocal = interface_has_linklocal_address(name); + ifrdomain = get_ifrdomain(name); if ((ra_iface = find_ra_iface_by_name(name)) != NULL) { ra_iface->link_state = link_state; @@ -765,6 +776,16 @@ merge_ra_interface(char *name, char *conf_name) log_debug("%s has no IPv6 link-local address, " "removing", name); ra_iface->removed = 1; + } else if (ifrdomain == -1) { + log_debug("can't get rdomain for %s, removing", name); + ra_iface->removed = 1; + } else if (ra_iface->rdomain != ifrdomain) { + leave_all_routers_mcast_group(ra_iface); + unref_icmp6ev(ra_iface); + ra_iface->rdomain = ifrdomain; + ra_iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain); + join_all_routers_mcast_group(ra_iface); + ra_iface->removed = 0; } else { log_debug("keeping interface %s", name); ra_iface->removed = 0; @@ -795,9 +816,13 @@ merge_ra_interface(char *name, char *conf_name) sizeof(ra_iface->conf_name)); ra_iface->if_index = if_index; + ra_iface->rdomain = ifrdomain; + SIMPLEQ_INIT(&ra_iface->prefixes); - TAILQ_INSERT_TAIL(&ra_interfaces, ra_iface, entry); + + ra_iface->icmp6ev = get_icmp6ev_by_rdomain(ifrdomain); join_all_routers_mcast_group(ra_iface); + TAILQ_INSERT_TAIL(&ra_interfaces, ra_iface, entry); } void @@ -901,6 +926,7 @@ free_ra_iface(struct ra_iface *ra_iface) free(prefix); } + unref_icmp6ev(ra_iface); free(ra_iface); } @@ -934,6 +960,7 @@ interface_has_linklocal_address(char *name) { struct ifaddrs *ifap, *ifa; struct sockaddr_in6 *sin6; + struct in6_ifreq ifr6; int ret = 0; if (getifaddrs(&ifap) != 0) @@ -947,14 +974,28 @@ interface_has_linklocal_address(char *name) sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - ret = 1; - break; + if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + continue; + + memset(&ifr6, 0, sizeof(ifr6)); + strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); + memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr)); + if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) == -1) { + log_warn("SIOCGIFAFLAG_IN6"); + continue; } + + if (ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_TENTATIVE | + IN6_IFF_DUPLICATED)) + continue; + + ret = 1; + break; } freeifaddrs(ifap); return (ret); } + void get_interface_prefixes(struct ra_iface *ra_iface, struct ra_prefix_conf *autoprefix) @@ -1182,8 +1223,9 @@ build_packet(struct ra_iface *ra_iface) memcpy(ra_iface->data, buf, len); ra_iface->datalen = len; /* packet changed; tell engine to send new advertisments */ - frontend_imsg_compose_engine(IMSG_UPDATE_IF, 0, - &ra_iface->if_index, sizeof(ra_iface->if_index)); + if (event_initialized(&ra_iface->icmp6ev->ev)) + frontend_imsg_compose_engine(IMSG_UPDATE_IF, 0, + &ra_iface->if_index, sizeof(ra_iface->if_index)); } } @@ -1237,7 +1279,7 @@ ra_output(struct ra_iface *ra_iface, struct sockaddr_in6 *to) log_debug("send RA on %s", ra_iface->name); - len = sendmsg(icmp6sock, &sndmhdr, 0); + len = sendmsg(EVENT_FD(&ra_iface->icmp6ev->ev), &sndmhdr, 0); if (len == -1) log_warn("sendmsg on %s", ra_iface->name); @@ -1307,6 +1349,7 @@ handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) case RTM_IFINFO: case RTM_NEWADDR: case RTM_DELADDR: + case RTM_CHGADDRATTR: /* * do the same thing as after a config reload when interfaces * change or IPv6 addresses show up / disappear @@ -1318,3 +1361,91 @@ handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) break; } } + +struct icmp6_ev* +get_icmp6ev_by_rdomain(int rdomain) +{ + struct ra_iface *ra_iface; + struct icmp6_ev *icmp6ev = NULL; + + TAILQ_FOREACH (ra_iface, &ra_interfaces, entry) { + if (ra_iface->rdomain == rdomain) { + icmp6ev = ra_iface->icmp6ev; + break; + } + } + + if (icmp6ev == NULL) { + if ((icmp6ev = calloc(1, sizeof(*icmp6ev))) == NULL) + fatal("calloc"); + + icmp6ev->rcviov[0].iov_base = (caddr_t)icmp6ev->answer; + icmp6ev->rcviov[0].iov_len = sizeof(icmp6ev->answer); + icmp6ev->rcvmhdr.msg_name = (caddr_t)&icmp6ev->from; + icmp6ev->rcvmhdr.msg_namelen = sizeof(icmp6ev->from); + icmp6ev->rcvmhdr.msg_iov = icmp6ev->rcviov; + icmp6ev->rcvmhdr.msg_iovlen = 1; + icmp6ev->rcvmhdr.msg_controllen = + CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); + if ((icmp6ev->rcvmhdr.msg_control = malloc(icmp6ev-> + rcvmhdr.msg_controllen)) == NULL) + fatal("malloc"); + frontend_imsg_compose_main(IMSG_OPEN_ICMP6SOCK, 0, + &rdomain, sizeof(rdomain)); + } + + icmp6ev->refcnt++; + return (icmp6ev); +} + +void +unref_icmp6ev(struct ra_iface *ra_iface) +{ + struct icmp6_ev *icmp6ev = ra_iface->icmp6ev; + + ra_iface->icmp6ev = NULL; + + if (icmp6ev != NULL) { + icmp6ev->refcnt--; + if (icmp6ev->refcnt == 0) { + event_del(&icmp6ev->ev); + close(EVENT_FD(&icmp6ev->ev)); + free(icmp6ev); + } + } +} + +void +set_icmp6sock(int icmp6sock, int rdomain) +{ + struct ra_iface *ra_iface; + + TAILQ_FOREACH (ra_iface, &ra_interfaces, entry) { + if (!event_initialized(&ra_iface->icmp6ev->ev) && + ra_iface->rdomain == rdomain) { + event_set(&ra_iface->icmp6ev->ev, icmp6sock, EV_READ | + EV_PERSIST, icmp6_receive, ra_iface->icmp6ev); + event_add(&ra_iface->icmp6ev->ev, NULL); + icmp6sock = -1; + break; + } + } + + if (icmp6sock != -1) { + /* + * The interface disappeared or changed rdomain while we were + * waiting for the parent process to open the raw socket. + */ + close(icmp6sock); + return; + } + + TAILQ_FOREACH (ra_iface, &ra_interfaces, entry) { + if (ra_iface->rdomain == rdomain) { + join_all_routers_mcast_group(ra_iface); + frontend_imsg_compose_engine(IMSG_UPDATE_IF, 0, + &ra_iface->if_index, sizeof(ra_iface->if_index)); + } + } +} diff --git rad.c rad.c index 6d4e18c1215..e79999f00bb 100644 --- rad.c +++ rad.c @@ -61,6 +61,7 @@ static pid_t start_child(int, char *, int, int, int); void main_dispatch_frontend(int, short, void *); void main_dispatch_engine(int, short, void *); +void open_icmp6sock(int); static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); static int main_imsg_send_config(struct rad_conf *); @@ -118,14 +119,13 @@ int main(int argc, char *argv[]) { struct event ev_sigint, ev_sigterm, ev_sighup; - struct icmp6_filter filt; int ch; int debug = 0, engine_flag = 0, frontend_flag = 0; char *saved_argv0; int pipe_main2frontend[2]; int pipe_main2engine[2]; - int icmp6sock, on = 1, off = 0; int frontend_routesock, rtfilter; + int rtable_any = RTABLE_ANY; int control_fd; char *csock; @@ -259,52 +259,31 @@ main(int argc, char *argv[]) if (main_imsg_send_ipc_sockets(&iev_frontend->ibuf, &iev_engine->ibuf)) fatal("could not establish imsg links"); - if ((icmp6sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, - IPPROTO_ICMPV6)) == -1) - fatal("ICMPv6 socket"); - - if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, - sizeof(on)) == -1) - fatal("IPV6_RECVPKTINFO"); - - if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, - sizeof(on)) == -1) - fatal("IPV6_RECVHOPLIMIT"); - - if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, - sizeof(off)) == -1) - fatal("IPV6_RECVHOPLIMIT"); - - /* only router advertisements and solicitations */ - ICMP6_FILTER_SETBLOCKALL(&filt); - ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); - ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); - if (setsockopt(icmp6sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, - sizeof(filt)) == -1) - fatal("ICMP6_FILTER"); - if ((frontend_routesock = socket(AF_ROUTE, SOCK_RAW | SOCK_CLOEXEC, AF_INET6)) == -1) fatal("route socket"); rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_NEWADDR) | - ROUTE_FILTER(RTM_DELADDR); + ROUTE_FILTER(RTM_DELADDR) | ROUTE_FILTER(RTM_CHGADDRATTR); if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_MSGFILTER, &rtfilter, sizeof(rtfilter)) == -1) fatal("setsockopt(ROUTE_MSGFILTER)"); + if (setsockopt(frontend_routesock, AF_ROUTE, ROUTE_TABLEFILTER, + &rtable_any, sizeof(rtable_any)) == -1) + fatal("setsockopt(ROUTE_TABLEFILTER)"); if ((control_fd = control_init(csock)) == -1) fatalx("control socket setup failed"); - main_imsg_compose_frontend_fd(IMSG_ICMP6SOCK, 0, icmp6sock); - main_imsg_compose_frontend_fd(IMSG_ROUTESOCK, 0, frontend_routesock); - main_imsg_compose_frontend_fd(IMSG_CONTROLFD, 0, control_fd); + main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, + NULL, 0); + main_imsg_compose_frontend(IMSG_CONTROLFD, control_fd, NULL, 0); main_imsg_send_config(main_conf); - if (pledge("stdio rpath sendfd", NULL) == -1) + if (pledge("stdio inet rpath sendfd mcast wroute", NULL) == -1) fatal("pledge"); - main_imsg_compose_frontend(IMSG_STARTUP, 0, NULL, 0); + main_imsg_compose_frontend(IMSG_STARTUP, -1, NULL, 0); event_dispatch(); @@ -397,6 +376,7 @@ main_dispatch_frontend(int fd, short event, void *bula) struct imsg imsg; ssize_t n; int shut = 0, verbose; + int rdomain; ibuf = &iev->ibuf; @@ -420,9 +400,13 @@ main_dispatch_frontend(int fd, short event, void *bula) break; switch (imsg.hdr.type) { - case IMSG_STARTUP_DONE: - if (pledge("stdio rpath", NULL) == -1) - fatal("pledge"); + case IMSG_OPEN_ICMP6SOCK: + log_debug("IMSG_OPEN_ICMP6SOCK"); + if (IMSG_DATA_SIZE(imsg) != sizeof(rdomain)) + fatalx("%s: IMSG_OPEN_ICMP6SOCK wrong length: " + "%lu", __func__, IMSG_DATA_SIZE(imsg)); + memcpy(&rdomain, imsg.data, sizeof(rdomain)); + open_icmp6sock(rdomain); break; case IMSG_CTL_RELOAD: if (main_reload() == -1) @@ -500,22 +484,16 @@ main_dispatch_engine(int fd, short event, void *bula) } } -void -main_imsg_compose_frontend(int type, pid_t pid, void *data, uint16_t datalen) +int +main_imsg_compose_frontend(int type, int fd, void *data, uint16_t datalen) { if (iev_frontend) - imsg_compose_event(iev_frontend, type, 0, pid, -1, data, - datalen); + return (imsg_compose_event(iev_frontend, type, 0, 0, fd, data, + datalen)); + else + return (-1); } -void -main_imsg_compose_frontend_fd(int type, pid_t pid, int fd) -{ - if (iev_frontend) - imsg_compose_event(iev_frontend, type, 0, pid, fd, NULL, 0); -} - - void main_imsg_compose_engine(int type, pid_t pid, void *data, uint16_t datalen) { @@ -810,3 +788,38 @@ in6_to_str(struct in6_addr *in6) return (sin6_to_str(&sin6)); } + +void +open_icmp6sock(int rdomain) +{ + int icmp6sock, on = 1, off = 0; + + log_debug("%s: %d", __func__, rdomain); + + if ((icmp6sock = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC, + IPPROTO_ICMPV6)) == -1) + fatal("ICMPv6 socket"); + + if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, + sizeof(on)) == -1) + fatal("IPV6_RECVPKTINFO"); + + if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, + sizeof(on)) == -1) + fatal("IPV6_RECVHOPLIMIT"); + + if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, + sizeof(off)) == -1) + fatal("IPV6_RECVHOPLIMIT"); + + if (setsockopt(icmp6sock, SOL_SOCKET, SO_RTABLE, &rdomain, + sizeof(rdomain)) == -1) { + /* we might race against removal of the rdomain */ + log_warn("setsockopt SO_RTABLE"); + close(icmp6sock); + return; + } + + main_imsg_compose_frontend(IMSG_ICMP6SOCK, icmp6sock, &rdomain, + sizeof(rdomain)); +} diff --git rad.h rad.h index 823a2a9d633..c65f4554388 100644 --- rad.h +++ rad.h @@ -67,10 +67,10 @@ enum imsg_type { IMSG_RECONF_RA_DNSSL, IMSG_RECONF_END, IMSG_ICMP6SOCK, + IMSG_OPEN_ICMP6SOCK, IMSG_ROUTESOCK, IMSG_CONTROLFD, IMSG_STARTUP, - IMSG_STARTUP_DONE, IMSG_RA_RS, IMSG_SEND_RA, IMSG_UPDATE_IF, @@ -145,9 +145,7 @@ struct imsg_send_ra { extern uint32_t cmd_opts; /* rad.c */ -void main_imsg_compose_frontend(int, pid_t, void *, uint16_t); -void main_imsg_compose_frontend_fd(int, pid_t, int); - +int main_imsg_compose_frontend(int, int, void *, uint16_t); void main_imsg_compose_engine(int, pid_t, void *, uint16_t); void merge_config(struct rad_conf *, struct rad_conf *); void imsg_event_add(struct imsgev *); -- I'm not entirely sure you are real.