summaryrefslogtreecommitdiff
path: root/interface-ip.c
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2021-01-09 21:18:45 +0100
committerHans Dedecker <dedeckeh@gmail.com>2021-01-11 20:46:46 +0100
commitc00c8335d6188daa326ecfe5a62da15a9b9987e1 (patch)
tree670098a7beb1758561b9442a42b88f16afff3caa /interface-ip.c
parente71909c42875b59e651f46d157c202b212666713 (diff)
downloadnetifd-c00c8335d6188daa326ecfe5a62da15a9b9987e1.tar.gz
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>
Diffstat (limited to 'interface-ip.c')
-rw-r--r--interface-ip.c69
1 files changed, 69 insertions, 0 deletions
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);
}