ra: fix routing loop on point to point links openwrt-19.07
authorHans Dedecker <dedeckeh@gmail.com>
Sat, 9 Jan 2021 20:17:48 +0000 (21:17 +0100)
committerHans Dedecker <dedeckeh@gmail.com>
Wed, 20 Jan 2021 20:03:10 +0000 (21:03 +0100)
For point-to-point links (e.g. PPP) don't create a link prefix route
when receiving a prefix information option with the on-link flag set.
Point-to-point links are non shared media and as such a destination
IPv6 address cannot be on-link.
If a link prefix route points to a point-to-point link it can trigger
a routing loop if the destination IPv6 address belongs to the prefix.
If such a packet is received and not directed to a local IPv6 address
it will be routed to the point-to-point link due to the link prefix route;
the upstream ISP router will route the IPv6 packet back due to the assigned
prefix route creating a "ping pong" effect

Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
(cherry picked from commit 53f07e90b7f1da6977143a488dd5cb73a33b233b)

src/ra.c

index 9fcdb31329f788a328993be9f68c15514bc56cc3..6b76a774181417b39835d89cac05599897f8daba 100644 (file)
--- a/src/ra.c
+++ b/src/ra.c
@@ -51,6 +51,7 @@
 #include "ra.h"
 
 static bool nocarrier = false;
+static bool ptp_link = false;
 
 static int sock = -1, rtnl = -1;
 static int if_index = 0;
@@ -87,6 +88,13 @@ int ra_init(const char *ifname, const struct in6_addr *ifid,
        if (sock < 0)
                goto failure;
 
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
+       if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0)
+               goto failure;
+
+       ptp_link = !!(ifr.ifr_flags & IFF_POINTOPOINT);
+
        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
        if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
@@ -480,7 +488,8 @@ bool ra_process(void)
                                                || entry->valid < entry->preferred)
                                        continue;
 
-                               if (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
+                               if ((pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) &&
+                                   !ptp_link)
                                        changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry,
                                                                        7200, ra_holdoff_interval);