interface-ip: add support for excluding interfaces in host route lookup
authorFelix Fietkau <nbd@nbd.name>
Thu, 19 May 2022 15:21:23 +0000 (17:21 +0200)
committerFelix Fietkau <nbd@nbd.name>
Thu, 19 May 2022 15:21:24 +0000 (17:21 +0200)
When adding host routes needed for an interface to communicate, it may be
necessary to skip the interface itself, in case it provides a default route.
This helps with avoiding accidental loops

Signed-off-by: Felix Fietkau <nbd@nbd.name>
interface-ip.c
interface-ip.h
proto-shell.c
ubus.c

index 54d5fe029d2babecfe8719eaf3d3c0d54734d5d4..585cb6f1d6736b4c4df8b84f344e15e000e6120d 100644 (file)
@@ -257,12 +257,19 @@ interface_ip_find_route_target(struct interface *iface, union if_addr *a,
 }
 
 struct interface *
-interface_ip_add_target_route(union if_addr *addr, bool v6, struct interface *iface)
+interface_ip_add_target_route(union if_addr *addr, bool v6, struct interface *iface,
+                             bool exclude)
 {
        struct device_route *route, *r_next = NULL;
        bool defaultroute_target = false;
        union if_addr addr_zero;
        int addrsize = v6 ? sizeof(addr->in6) : sizeof(addr->in);
+       struct interface *exclude_iface = NULL;
+
+       if (exclude) {
+               exclude_iface = iface;
+               iface = NULL;
+       }
 
        memset(&addr_zero, 0, sizeof(addr_zero));
        if (memcmp(&addr_zero, addr, addrsize) == 0)
@@ -278,6 +285,9 @@ interface_ip_add_target_route(union if_addr *addr, bool v6, struct interface *if
                interface_ip_find_route_target(iface, addr, v6, &r_next);
        } else {
                vlist_for_each_element(&interfaces, iface, node) {
+                       if (iface == exclude_iface)
+                               continue;
+
                        /* look for locally addressable target first */
                        if (interface_ip_find_addr_target(iface, addr, v6))
                                return iface;
index b17ad94c5159a8720fe2044573aac7dedf0fcf65..8843349b2de8227df6d2eabcfc99aa27b47fc04b 100644 (file)
@@ -184,7 +184,8 @@ void interface_ip_flush(struct interface_ip_settings *ip);
 void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled);
 void interface_ip_update_metric(struct interface_ip_settings *ip, int metric);
 
-struct interface *interface_ip_add_target_route(union if_addr *addr, bool v6, struct interface *iface);
+struct interface *interface_ip_add_target_route(union if_addr *addr, bool v6, struct interface *iface,
+                                               bool exclude);
 
 struct device_prefix* interface_ip_add_device_prefix(struct interface *iface,
                struct in6_addr *addr, uint8_t length, time_t valid_until, time_t preferred_until,
index e20d53961592d614123c03fa7057d3d31f061fb2..9cdbc7fde362ac4ea112743bfcd8831bc38d6eca 100644 (file)
@@ -129,7 +129,7 @@ proto_shell_update_host_dep(struct proto_shell_dependency *dep)
        }
 
        if (!dep->any)
-               iface = interface_ip_add_target_route(&dep->host, dep->v6, iface);
+               iface = interface_ip_add_target_route(&dep->host, dep->v6, iface, false);
 
        if (!iface)
                goto out;
diff --git a/ubus.c b/ubus.c
index a38617928b415c7540338684a1402785d83dd416..2876e7d173fb5fef23732171f3aa431df4ce9f29 100644 (file)
--- a/ubus.c
+++ b/ubus.c
@@ -54,6 +54,7 @@ enum {
        HR_TARGET,
        HR_V6,
        HR_INTERFACE,
+       HR_EXCLUDE,
        __HR_MAX
 };
 
@@ -61,6 +62,7 @@ static const struct blobmsg_policy route_policy[__HR_MAX] = {
        [HR_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING },
        [HR_V6] = { .name = "v6", .type = BLOBMSG_TYPE_BOOL },
        [HR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING },
+       [HR_EXCLUDE] = { .name = "exclude", .type = BLOBMSG_TYPE_BOOL },
 };
 
 static int
@@ -72,6 +74,7 @@ netifd_add_host_route(struct ubus_context *ctx, struct ubus_object *obj,
        struct interface *iface = NULL;
        union if_addr a;
        bool v6 = false;
+       bool exclude = false;
 
        blobmsg_parse(route_policy, __HR_MAX, tb, blob_data(msg), blob_len(msg));
        if (!tb[HR_TARGET])
@@ -80,6 +83,9 @@ netifd_add_host_route(struct ubus_context *ctx, struct ubus_object *obj,
        if (tb[HR_V6])
                v6 = blobmsg_get_bool(tb[HR_V6]);
 
+       if (tb[HR_EXCLUDE])
+               exclude = blobmsg_get_bool(tb[HR_EXCLUDE]);
+
        if (tb[HR_INTERFACE])
                iface = vlist_find(&interfaces, blobmsg_data(tb[HR_INTERFACE]), iface, node);
 
@@ -87,8 +93,7 @@ netifd_add_host_route(struct ubus_context *ctx, struct ubus_object *obj,
        if (!inet_pton(v6 ? AF_INET6 : AF_INET, blobmsg_data(tb[HR_TARGET]), &a))
                return UBUS_STATUS_INVALID_ARGUMENT;
 
-
-       iface = interface_ip_add_target_route(&a, v6, iface);
+       iface = interface_ip_add_target_route(&a, v6, iface, exclude);
        if (!iface)
                return UBUS_STATUS_NOT_FOUND;