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.

Reply via email to