Skip to content
Permalink
Browse files Browse the repository at this point in the history
Fix IPv6 routing loops
  • Loading branch information
lantis1008 committed Jan 20, 2021
1 parent 4ee0c93 commit 24afe94
Show file tree
Hide file tree
Showing 2 changed files with 249 additions and 0 deletions.
118 changes: 118 additions & 0 deletions patches-generic/601-odhcp6c-CNVD-C-2021-04732.patch
@@ -0,0 +1,118 @@
--- /dev/null
+++ b/package/network/ipv6/odhcp6c/patches/001-ra-align-ifindex-resolving.patch
@@ -0,0 +1,52 @@
+From 2b6959dfe2095402e004b63d9aca9900c074abb6 Mon Sep 17 00:00:00 2001
+From: Hans Dedecker <dedeckeh@gmail.com>
+Date: Wed, 6 Jan 2021 21:15:49 +0100
+Subject: [PATCH] ra: align ifindex resolving
+
+Use ioctl SIOCGIFINDEX to resolve ifindex similar as in init_dhcpv6
+
+Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
+---
+ src/ra.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/src/ra.c b/src/ra.c
+index 337c0bd..32a3097 100644
+--- a/src/ra.c
++++ b/src/ra.c
+@@ -27,6 +27,7 @@
+
+ #include <net/if.h>
+ #include <arpa/inet.h>
++#include <sys/ioctl.h>
+ #include <sys/socket.h>
+ #include <sys/types.h>
+ #include <netinet/in.h>
+@@ -76,6 +77,8 @@ static void ra_send_rs(int signal __attribute__((unused)));
+ int ra_init(const char *ifname, const struct in6_addr *ifid,
+ unsigned int options, unsigned int holdoff_interval)
+ {
++ struct ifreq ifr;
++
+ ra_options = options;
+ ra_holdoff_interval = holdoff_interval;
+
+@@ -84,11 +87,12 @@ int ra_init(const char *ifname, const struct in6_addr *ifid,
+ if (sock < 0)
+ goto failure;
+
+- if_index = if_nametoindex(ifname);
+- if (!if_index)
++ memset(&ifr, 0, sizeof(ifr));
++ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
++ if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
+ goto failure;
+
+- strncpy(if_name, ifname, sizeof(if_name) - 1);
++ if_index = ifr.ifr_ifindex;
+ lladdr = *ifid;
+
+ rtnl = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
+--
+2.20.1
+
--- /dev/null
+++ b/package/network/ipv6/odhcp6c/patches/002-ra-fix-routing-loop-ppp-links.patch
@@ -0,0 +1,60 @@
+From 53f07e90b7f1da6977143a488dd5cb73a33b233b Mon Sep 17 00:00:00 2001
+From: Hans Dedecker <dedeckeh@gmail.com>
+Date: Sat, 9 Jan 2021 21:17:48 +0100
+Subject: [PATCH] ra: fix routing loop on point to point links
+
+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>
+---
+ src/ra.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/src/ra.c b/src/ra.c
+index 32a3097..4e6dd64 100644
+--- 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)
+@@ -488,7 +496,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);
+
+--
+2.20.1
+
131 changes: 131 additions & 0 deletions patches-generic/602-netifd-CNVD-C-2021-04732.patch
@@ -0,0 +1,131 @@
--- /dev/null
+++ b/package/network/config/netifd/patches/001-interface_ip-add-unreachable-route-offlink-address.patch
@@ -0,0 +1,128 @@
+From c00c8335d6188daa326ecfe5a62da15a9b9987e1 Mon Sep 17 00:00:00 2001
+From: Hans Dedecker <dedeckeh@gmail.com>
+Date: Sat, 9 Jan 2021 21:18:45 +0100
+Subject: [PATCH] interface-ip: add unreachable route if address is offlink
+
+In order to avoid a routing loop add an unreachable route for the
+address prefix is the offlink flag is set for an address.
+This fixes a routing loop which is currently present on point-to-point
+links (e.g PPP) when the wan interface is assigned a globally unique
+prefix (e.g. 2001:db8:1:0::/64) from which an IPv6 address is picked
+and installed on the wan interface
+(e.g. 2001:db8:1:0:5054:ff:feab:d87c/64)
+
+The prefix route 2001:db8:1::/64 would be present in the routing table
+which will route any packet with as destination 2001:db8:1::/64 to the wan
+interface and would be routed back by the upstream router due to the
+wan interface due to the assigned global unique prefix.
+Besides not installing the prefix route 2001:db8:1::/64 on point-to-point links
+adding an unreachable route is required to avoid the routing loop.
+
+Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
+---
+ interface-ip.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 69 insertions(+)
+
+diff --git a/interface-ip.c b/interface-ip.c
+index 3768000..1444fbf 100644
+--- a/interface-ip.c
++++ b/interface-ip.c
+@@ -684,6 +684,22 @@ interface_update_proto_addr(struct vlist_tree *tree,
+ if (!(a_old->flags & DEVADDR_EXTERNAL)) {
+ interface_handle_subnet_route(iface, a_old, false);
+ system_del_address(dev, a_old);
++
++ if ((a_old->flags & DEVADDR_OFFLINK) && (a_old->mask < (v6 ? 128 : 32))) {
++ struct device_route route;
++
++ memset(&route, 0, sizeof(route));
++ route.flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
++ route.metric = INT32_MAX;
++ route.mask = a_old->mask;
++ route.addr = a_old->addr;
++
++ clear_if_addr(&route.addr, route.mask);
++
++ /* Delete null-route */
++ system_del_route(NULL, &route);
++ }
++
+ }
+ }
+ free(a_old->pclass);
+@@ -708,6 +724,26 @@ interface_update_proto_addr(struct vlist_tree *tree,
+ }
+
+ if (!keep) {
++ if (!(a_new->flags & DEVADDR_EXTERNAL) &&
++ (a_new->flags & DEVADDR_OFFLINK) &&
++ (a_new->mask < (v6 ? 128 : 32))) {
++ struct device_route route;
++
++ memset(&route, 0, sizeof(route));
++ route.flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
++ route.metric = INT32_MAX;
++ route.mask = a_new->mask;
++ route.addr = a_new->addr;
++
++ clear_if_addr(&route.addr, route.mask);
++
++ /*
++ * In case off link is specifed as address property
++ * add null-route to avoid routing loops
++ */
++ system_add_route(NULL, &route);
++ }
++
+ if (a_new->policy_table)
+ interface_add_addr_rules(a_new, true);
+ }
+@@ -1578,12 +1614,45 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled)
+ if (iface->metric || addr->policy_table)
+ interface_handle_subnet_route(iface, addr, true);
+
++ if ((addr->flags & DEVADDR_OFFLINK) && (addr->mask < (v6 ? 128 : 32))) {
++ struct device_route route;
++
++ memset(&route, 0, sizeof(route));
++ route.flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
++ route.metric = INT32_MAX;
++ route.mask = addr->mask;
++ route.addr = addr->addr;
++
++ clear_if_addr(&route.addr, route.mask);
++
++ /*
++ * In case off link is specifed as address property
++ * add null-route to avoid routing loops
++ */
++ system_add_route(NULL, &route);
++ }
++
+ if (addr->policy_table)
+ interface_add_addr_rules(addr, true);
+ } else {
+ interface_handle_subnet_route(iface, addr, false);
+ system_del_address(dev, addr);
+
++ if ((addr->flags & DEVADDR_OFFLINK) && (addr->mask < (v6 ? 128 : 32))) {
++ struct device_route route;
++
++ memset(&route, 0, sizeof(route));
++ route.flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
++ route.metric = INT32_MAX;
++ route.mask = addr->mask;
++ route.addr = addr->addr;
++
++ clear_if_addr(&route.addr, route.mask);
++
++ /* Delete null-route */
++ system_del_route(NULL, &route);
++ }
++
+ if (addr->policy_table)
+ interface_add_addr_rules(addr, false);
+ }
+--
+2.20.1
+

4 comments on commit 24afe94

@obsy
Copy link
Contributor

@obsy obsy commented on 24afe94 Jan 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lantis1008
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I will wait a bit longer to see if I can get the dnsmasq fixes (and the fixes to the fixes) in one go :)

@obsy
Copy link
Contributor

@obsy obsy commented on 24afe94 Jan 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm waiting too :)

@lantis1008
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've picked up the latest fixes for both issues now in Master. I note that you may have already done this in your fork from a forum post?
Anyway, available if you need it.

Please sign in to comment.