]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
inet6: Stop reacting to kernel neighbour messages about a router
authorRoy Marples <roy@marples.name>
Fri, 30 Aug 2019 10:06:20 +0000 (11:06 +0100)
committerRoy Marples <roy@marples.name>
Fri, 30 Aug 2019 10:06:20 +0000 (11:06 +0100)
It's unreliable and very corner case.
See the comment for the ipv6nd_neighbour() function.

src/if-bsd.c
src/if-linux.c
src/if-sun.c
src/ipv6nd.c
src/ipv6nd.h

index ed5041d5b75fb68e01f57260093ee5d491048599..47219e1a8a683c6d8e92caf5eade8b3f26ed502e 100644 (file)
@@ -1083,20 +1083,17 @@ if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
         * BSD announces host routes.
         * As such, we should be notified of reachability by its
         * existance with a hardware address.
-        * Ensure we don't call this for an incomplete state.
+        * Ensure we don't call this for a newly incomplete state.
         */
        if (rt.rt_dest.sa_family == AF_INET6 &&
            rt.rt_flags & RTF_HOST &&
            !(rtm->rtm_type == RTM_ADD && !(rt.rt_dflags & RTDF_GATELINK)))
        {
-               int flags = 0;
+               bool reachable;
 
-               if (rt.rt_dflags & RTDF_GATELINK)
-                       flags |= IPV6ND_ROUTER;
-               if (rtm->rtm_type != RTM_DELETE)
-                       flags |= IPV6ND_REACHABLE;
-
-               ipv6nd_neighbour(ctx, &rt.rt_ss_dest.sin6.sin6_addr, flags);
+               reachable = rtm->rtm_type != RTM_DELETE &&
+                   rt.rt_dflags & RTDF_GATELINK;
+               ipv6nd_neighbour(ctx, &rt.rt_ss_dest.sin6.sin6_addr, reachable);
        }
 #endif
 
index 1b7e6164a7e5de0c76492741acb6c791aa71c3be..287b7f1bb9124adf9863d9a220712b8eef6a004d 100644 (file)
@@ -680,8 +680,6 @@ link_neigh(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
        struct ndmsg *r;
        struct rtattr *rta;
        size_t len;
-       struct in6_addr addr6;
-       int flags;
 
        if (nlm->nlmsg_type != RTM_NEWNEIGH && nlm->nlmsg_type != RTM_DELNEIGH)
                return 0;
@@ -692,14 +690,13 @@ link_neigh(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
        rta = (struct rtattr *)RTM_RTA(r);
        len = RTM_PAYLOAD(nlm);
         if (r->ndm_family == AF_INET6) {
-               flags = 0;
-               if (r->ndm_flags & NTF_ROUTER)
-                       flags |= IPV6ND_ROUTER;
-               if (nlm->nlmsg_type == RTM_NEWNEIGH &&
+               bool reachable;
+               struct in6_addr addr6;
+
+               reachable = (nlm->nlmsg_type == RTM_NEWNEIGH &&
                    r->ndm_state &
                    (NUD_REACHABLE | NUD_STALE | NUD_DELAY | NUD_PROBE |
                     NUD_PERMANENT))
-                       flags |= IPV6ND_REACHABLE;
                memset(&addr6, 0, sizeof(addr6));
                while (RTA_OK(rta, len)) {
                        switch (rta->rta_type) {
@@ -710,7 +707,7 @@ link_neigh(struct dhcpcd_ctx *ctx, __unused struct interface *ifp,
                        }
                        rta = RTA_NEXT(rta, len);
                }
-               ipv6nd_neighbour(ctx, &addr6, flags);
+               ipv6nd_neighbour(ctx, &addr6, reachable);
        }
 
        return 0;
index 0db7371c0716305b97d4dedd4174515ebe0af607..2e776cc51c247adac77baa2ddb9ca61213744b8b 100644 (file)
@@ -812,8 +812,7 @@ if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm)
                        else
                                sdl.sdl_alen = 0;
                        ipv6nd_neighbour(ctx, &dst6,
-                           rtm->rtm_type != RTM_DELETE && sdl.sdl_alen ?
-                           IPV6ND_REACHABLE : 0);
+                           rtm->rtm_type != RTM_DELETE && sdl.sdl_alen);
                }
                break;
        }
index cb9e1086227d0152ce5a725885b48f6bb3c3fa50..35401b75c4dba552b15bbd640f863dd0127803a8 100644 (file)
@@ -554,8 +554,21 @@ ipv6nd_startexpire(struct interface *ifp)
            ipv6nd_expire, ifp);
 }
 
+/*
+ * Neighbour reachability.
+ *
+ * RFC 4681 6.2.5 says when a node is no longer a router it MUST
+ * send a RA with a zero lifetime.
+ * All OS's I know of set the NA router flag if they are a router
+ * or not and disregard that they are actively advertising or
+ * shutting down. If the interface is disabled, it cant't send a NA at all.
+ *
+ * As such we CANNOT rely on the NA Router flag and MUST use
+ * unreachability or receive a RA with a lifetime of zero to remove
+ * the node as a default router.
+ */
 void
-ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, int flags)
+ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, bool reachable)
 {
        struct ra *rap, *rapr;
 
@@ -570,11 +583,7 @@ ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, int flags)
        if (rap == NULL || rap->expired)
                return;
 
-       if (!(flags & IPV6ND_ROUTER) && rap->lifetime != 0) {
-               loginfox("%s: %s is no longer a router",
-                   rap->iface->name, rap->sfrom);
-               rap->lifetime = 0;
-       } else if (flags & IPV6ND_REACHABLE) {
+       if (reachable) {
                if (rap->isreachable)
                        return;
                loginfox("%s: %s is reachable again",
index b169b8bea4322501a99f8200478457c1e8263340..16c4dc79504183fa899c9721d993d670e82e559d 100644 (file)
@@ -91,9 +91,6 @@ struct rs_state {
 #define        RETRANS_TIMER                   1000    /* milliseconds */
 #define        DELAY_FIRST_PROBE_TIME          5       /* seconds */
 
-#define        IPV6ND_REACHABLE                (1 << 0)
-#define        IPV6ND_ROUTER                   (1 << 1)
-
 void ipv6nd_printoptions(const struct dhcpcd_ctx *,
     const struct dhcp_opt *, size_t);
 void ipv6nd_startrs(struct interface *);
@@ -112,7 +109,7 @@ int ipv6nd_dadcompleted(const struct interface *);
 void ipv6nd_advertise(struct ipv6_addr *);
 void ipv6nd_startexpire(struct interface *);
 void ipv6nd_drop(struct interface *);
-void ipv6nd_neighbour(struct dhcpcd_ctx *, struct in6_addr *, int);
+void ipv6nd_neighbour(struct dhcpcd_ctx *, struct in6_addr *, bool);
 #endif /* INET6 */
 
 #endif /* IPV6ND_H */