Send a RA with router lifetime of 0 when an interface is removed from
authorflorian <florian@openbsd.org>
Wed, 11 Jul 2018 17:32:05 +0000 (17:32 +0000)
committerflorian <florian@openbsd.org>
Wed, 11 Jul 2018 17:32:05 +0000 (17:32 +0000)
the config.

RFC 4861, 6.2.5:
[...] the router SHOULD transmit one or more (but not more than
MAX_FINAL_RTR_ADVERTISEMENTS) final multicast Router Advertisements on
the interface with a Router Lifetime field of zero.

usr.sbin/rad/engine.c
usr.sbin/rad/frontend.c
usr.sbin/rad/rad.h

index 25df94b..4f568e3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: engine.c,v 1.4 2018/07/11 14:03:13 florian Exp $      */
+/*     $OpenBSD: engine.c,v 1.5 2018/07/11 17:32:05 florian Exp $      */
 
 /*
  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -43,8 +43,8 @@
 #include "rad.h"
 #include "engine.h"
 
-#define        MAX_RTR_ADV_INTERVAL    600
-#define        MIN_RTR_ADV_INTERVAL    200
+#define        MAX_RTR_ADV_INTERVAL            600
+#define        MIN_RTR_ADV_INTERVAL            200
 
 struct engine_iface {
        TAILQ_ENTRY(engine_iface)       entry;
@@ -63,6 +63,7 @@ void                   parse_ra_rs(struct imsg_ra_rs *);
 void                    parse_ra(struct imsg_ra_rs *);
 void                    parse_rs(struct imsg_ra_rs *);
 void                    update_iface(uint32_t);
+void                    remove_iface(uint32_t);
 struct engine_iface    *find_engine_iface_by_id(uint32_t);
 void                    iface_timeout(int, short, void *);
 
@@ -147,6 +148,8 @@ engine(int debug, int verbose)
        if (inet_pton(AF_INET6, "ff02::1", &all_nodes.sin6_addr) != 1)
                fatal("inet_pton");
 
+       TAILQ_INIT(&engine_interfaces);
+
        event_dispatch();
 
        engine_shutdown();
@@ -224,6 +227,13 @@ engine_dispatch_frontend(int fd, short event, void *bula)
                        memcpy(&if_index, imsg.data, sizeof(if_index));
                        update_iface(if_index);
                        break;
+               case IMSG_REMOVE_IF:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(if_index))
+                               fatal("%s: IMSG_REMOVE_IF wrong length: %d",
+                                   __func__, imsg.hdr.len);
+                       memcpy(&if_index, imsg.data, sizeof(if_index));
+                       remove_iface(if_index);
+                       break;
                case IMSG_CTL_LOG_VERBOSE:
                        /* Already checked by frontend. */
                        memcpy(&verbose, imsg.data, sizeof(verbose));
@@ -487,6 +497,7 @@ update_iface(uint32_t if_index)
                engine_iface = calloc(1, sizeof(*engine_iface));
                engine_iface->if_index = if_index;
                evtimer_set(&engine_iface->timer, iface_timeout, engine_iface);
+               TAILQ_INSERT_TAIL(&engine_interfaces, engine_iface, entry);
        }
 
        tv.tv_sec = 0;
@@ -494,6 +505,34 @@ update_iface(uint32_t if_index)
        evtimer_add(&engine_iface->timer, &tv);
 }
 
+void
+remove_iface(uint32_t if_index)
+{
+       struct engine_iface     *engine_iface;
+       struct imsg_send_ra      send_ra;
+       char                     if_name[IF_NAMESIZE];
+
+       if ((engine_iface = find_engine_iface_by_id(if_index)) == NULL) {
+               /* we don't know this interface, frontend can delete it */
+               engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0,
+                   &if_index, sizeof(if_index));
+               return;
+       }
+
+       send_ra.if_index = engine_iface->if_index;
+       memcpy(&send_ra.to, &all_nodes, sizeof(send_ra.to));
+
+       TAILQ_REMOVE(&engine_interfaces, engine_iface, entry);
+       evtimer_del(&engine_iface->timer);
+
+       if (if_indextoname(if_index, if_name) != NULL)
+               engine_imsg_compose_frontend(IMSG_SEND_RA, 0, &send_ra,
+                   sizeof(send_ra));
+       engine_imsg_compose_frontend(IMSG_REMOVE_IF, 0,
+           &engine_iface->if_index, sizeof(engine_iface->if_index));
+       free(engine_iface);
+}
+
 void
 iface_timeout(int fd, short events, void *arg)
 {
@@ -501,7 +540,6 @@ iface_timeout(int fd, short events, void *arg)
        struct imsg_send_ra      send_ra;
        struct timeval           tv;
 
-
        tv.tv_sec = MIN_RTR_ADV_INTERVAL +
            arc4random_uniform(MAX_RTR_ADV_INTERVAL - MIN_RTR_ADV_INTERVAL);
        tv.tv_usec = arc4random_uniform(1000000);
index f6a7e7b..e3bc537 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: frontend.c,v 1.3 2018/07/11 14:03:13 florian Exp $    */
+/*     $OpenBSD: frontend.c,v 1.4 2018/07/11 17:32:05 florian Exp $    */
 
 /*
  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -129,6 +129,7 @@ int                  in6_mask2prefixlen(struct in6_addr *);
 void                    get_interface_prefixes(struct ra_iface *,
                             struct ra_prefix_conf *);
 void                    build_package(struct ra_iface *);
+void                    build_leaving_package(struct ra_iface *);
 void                    ra_output(struct ra_iface *, struct sockaddr_in6 *);
 
 struct rad_conf        *frontend_conf;
@@ -434,6 +435,7 @@ frontend_dispatch_engine(int fd, short event, void *bula)
        struct imsg              imsg;
        struct imsg_send_ra      send_ra;
        struct ra_iface         *ra_iface;
+       uint32_t                 if_index;
        int                      n, shut = 0;
 
        if (event & EV_READ) {
@@ -465,6 +467,17 @@ frontend_dispatch_engine(int fd, short event, void *bula)
                        if (ra_iface)
                                ra_output(ra_iface, &send_ra.to);
                        break;
+               case IMSG_REMOVE_IF:
+                       if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(if_index))
+                               fatal("%s: IMSG_REMOVE_IF wrong length: %d",
+                                   __func__, imsg.hdr.len);
+                       memcpy(&if_index, imsg.data, sizeof(if_index));
+                       ra_iface = find_ra_iface_by_id(if_index);
+                       if (ra_iface) {
+                               TAILQ_REMOVE(&ra_interfaces, ra_iface, entry);
+                               free_ra_iface(ra_iface);
+                       }
+                       break;
                default:
                        log_debug("%s: error handling imsg %d", __func__,
                            imsg.hdr.type);
@@ -631,7 +644,7 @@ merge_ra_interfaces(void)
 {
        struct ra_iface_conf    *ra_iface_conf;
        struct ra_prefix_conf   *ra_prefix_conf;
-       struct ra_iface         *ra_iface, *tmp;
+       struct ra_iface         *ra_iface;
        uint32_t                 if_index;
 
        TAILQ_FOREACH(ra_iface, &ra_interfaces, entry)
@@ -660,13 +673,6 @@ merge_ra_interfaces(void)
                }
        }
 
-       TAILQ_FOREACH_SAFE(ra_iface, &ra_interfaces, entry, tmp) {
-               if (ra_iface->removed) {
-                       TAILQ_REMOVE(&ra_interfaces, ra_iface, entry);
-                       free_ra_iface(ra_iface);
-               }
-       }
-
        TAILQ_FOREACH(ra_iface, &ra_interfaces, entry) {
                while ((ra_prefix_conf = SIMPLEQ_FIRST(&ra_iface->prefixes))
                    != NULL) {
@@ -676,6 +682,14 @@ merge_ra_interfaces(void)
                }
                ra_iface->prefix_count = 0;
 
+               if (ra_iface->removed) {
+                       log_debug("iface removed: %s", ra_iface->name);
+                       build_leaving_package(ra_iface);
+                       frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0,
+                           &ra_iface->if_index, sizeof(ra_iface->if_index));
+                       continue;
+               }
+
                ra_iface_conf = find_ra_iface_conf(
                    &frontend_conf->ra_iface_list, ra_iface->name);
 
@@ -897,6 +911,22 @@ build_package(struct ra_iface *ra_iface)
        }
 }
 
+void
+build_leaving_package(struct ra_iface *ra_iface)
+{
+       struct nd_router_advert          ra;
+       size_t                           len;
+
+       len = sizeof(ra);
+
+       memset(&ra, 0, sizeof(ra));
+
+       ra.nd_ra_type = ND_ROUTER_ADVERT;
+
+       memcpy(ra_iface->data, &ra, sizeof(ra));
+       ra_iface->datalen = sizeof(ra);
+}
+
 void
 ra_output(struct ra_iface *ra_iface, struct sockaddr_in6 *to)
 {
index 445bf9c..ee9b32d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rad.h,v 1.4 2018/07/11 14:03:13 florian Exp $ */
+/*     $OpenBSD: rad.h,v 1.5 2018/07/11 17:32:05 florian Exp $ */
 
 /*
  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
@@ -62,6 +62,7 @@ enum imsg_type {
        IMSG_RA_RS,
        IMSG_SEND_RA,
        IMSG_UPDATE_IF,
+       IMSG_REMOVE_IF,
        IMSG_SOCKET_IPC
 };