netifd: Route traffic from LAN to WAN using rules
authorKristian Evensen <kristian.evensen@gmail.com>
Thu, 21 Jan 2016 16:37:40 +0000 (17:37 +0100)
committerFelix Fietkau <nbd@openwrt.org>
Thu, 28 Jan 2016 21:40:38 +0000 (22:40 +0100)
After commit ebd3d8417c7a ("interface: fix moving interface address routes to
the table specified by ip[46]table"), it is no longer possible for clients on
LAN to reach machines on the WAN.

This patch restores support for clients on LAN reaching clients on WAN by using
rules. The rules are placed after the address rules, in order to make sure that
traffic originating from the router is routed correctly.

Signed-off-by: Kristian Evensen <kristian.evensen@gmail.com>
interface-ip.c
iprule.h

index b96d98c75784a5b7a8bf3fd82dee5d7a9f8bc3bd..919c8cc83f9bf7a830e6540807ecbf1b8df93139 100644 (file)
@@ -99,7 +99,7 @@ match_if_addr(union if_addr *a1, union if_addr *a2, int mask)
 
 static int set_ip_source_policy(bool add, bool v6, unsigned int priority,
                const union if_addr *addr, uint8_t mask, unsigned int table,
-               struct interface *in_iface, const char *action)
+               struct interface *in_iface, const char *action, bool src)
 {
        struct iprule rule = {
                .flags = IPRULE_PRIORITY,
@@ -107,9 +107,15 @@ static int set_ip_source_policy(bool add, bool v6, unsigned int priority,
        };
 
        if (addr) {
-               rule.flags |= IPRULE_SRC;
-               rule.src_addr = *addr;
-               rule.src_mask = mask;
+               if (src) {
+                       rule.flags |= IPRULE_SRC;
+                       rule.src_addr = *addr;
+                       rule.src_mask = mask;
+               } else {
+                       rule.flags |= IPRULE_DEST;
+                       rule.dest_addr = *addr;
+                       rule.dest_mask = mask;
+               }
        }
 
        if (table) {
@@ -481,6 +487,19 @@ interface_handle_subnet_route(struct interface *iface, struct device_addr *addr,
        system_add_route(dev, r);
 }
 
+static void
+interface_add_addr_rules(struct device_addr *addr, bool enabled)
+{
+       bool v6 = (addr->flags & DEVADDR_FAMILY) == DEVADDR_INET6;
+
+       set_ip_source_policy(enabled, v6, IPRULE_PRIORITY_ADDR, &addr->addr,
+                            (v6) ? 128 : 32, addr->policy_table, NULL, NULL,
+                            true);
+       set_ip_source_policy(enabled, v6, IPRULE_PRIORITY_ADDR_MASK,
+                            &addr->addr, addr->mask, addr->policy_table, NULL,
+                            NULL, false);
+}
+
 static void
 interface_update_proto_addr(struct vlist_tree *tree,
                            struct vlist_node *node_new,
@@ -541,16 +560,12 @@ interface_update_proto_addr(struct vlist_tree *tree,
 
        if (node_old) {
                if (a_old->enabled && !keep) {
-                       if ((a_old->flags & DEVADDR_FAMILY) == DEVADDR_INET6)
-                               v6 = true;
-
                        //This is needed for source routing to work correctly. If a device
                        //has two connections to a network using the same subnet, adding
                        //only the network-rule will cause packets to be routed through the
                        //first matching network (source IP matches both masks).
                        if (a_old->policy_table)
-                               set_ip_source_policy(false, v6, IPRULE_PRIORITY_ADDR, &a_old->addr,
-                                               (v6) ? 128 : 32, a_old->policy_table, NULL, NULL);
+                               interface_add_addr_rules(a_old, false);
 
                        if (!(a_old->flags & DEVADDR_EXTERNAL)) {
                                interface_handle_subnet_route(iface, a_old, false);
@@ -580,8 +595,7 @@ interface_update_proto_addr(struct vlist_tree *tree,
 
                        if (!keep) {
                                if (a_new->policy_table)
-                                       set_ip_source_policy(true, v6, IPRULE_PRIORITY_ADDR, &a_new->addr,
-                                                       (v6) ? 128 : 32, a_new->policy_table, NULL, NULL);
+                                       interface_add_addr_rules(a_new, true);
                        }
                }
        }
@@ -762,10 +776,10 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
                if (prefix->iface) {
                        if (prefix->iface->ip6table)
                                set_ip_source_policy(false, true, IPRULE_PRIORITY_NW, &addr.addr,
-                                               addr.mask, prefix->iface->ip6table, iface, NULL);
+                                               addr.mask, prefix->iface->ip6table, iface, NULL, true);
 
                        set_ip_source_policy(false, true, IPRULE_PRIORITY_REJECT, &addr.addr,
-                                                       addr.mask, 0, iface, "unreachable");
+                                                       addr.mask, 0, iface, "unreachable", true);
                }
 
                system_del_route(l3_downlink, &route);
@@ -777,11 +791,11 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment,
 
                if (prefix->iface && !assignment->enabled) {
                        set_ip_source_policy(true, true, IPRULE_PRIORITY_REJECT, &addr.addr,
-                                       addr.mask, 0, iface, "unreachable");
+                                       addr.mask, 0, iface, "unreachable", true);
 
                        if (prefix->iface->ip6table)
                                set_ip_source_policy(true, true, IPRULE_PRIORITY_NW, &addr.addr,
-                                               addr.mask, prefix->iface->ip6table, iface, NULL);
+                                               addr.mask, prefix->iface->ip6table, iface, NULL, true);
                }
 
                route.metric = iface->metric;
@@ -1250,15 +1264,13 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled)
                                interface_handle_subnet_route(iface, addr, true);
 
                        if (addr->policy_table)
-                               set_ip_source_policy(true, v6, IPRULE_PRIORITY_ADDR, &addr->addr,
-                                               (v6) ? 128 : 32, addr->policy_table, NULL, NULL);
+                               interface_add_addr_rules(addr, true);
                } else {
                        interface_handle_subnet_route(iface, addr, false);
                        system_del_address(dev, addr);
 
                        if (addr->policy_table)
-                               set_ip_source_policy(false, v6, IPRULE_PRIORITY_ADDR, &addr->addr,
-                                               (v6) ? 128 : 32, addr->policy_table, NULL, NULL);
+                               interface_add_addr_rules(addr, false);
                }
                addr->enabled = enabled;
        }
@@ -1295,7 +1307,7 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled)
                set_ip_lo_policy(enabled, false, ip->iface);
 
                set_ip_source_policy(enabled, true, IPRULE_PRIORITY_REJECT + ip->iface->l3_dev.dev->ifindex,
-                       NULL, 0, 0, ip->iface, "failed_policy");
+                       NULL, 0, 0, ip->iface, "failed_policy", true);
                ip->iface->policy_rules_set = enabled;
        }
 }
index ea87193687b7cd0699af920a594fb643cc95bd50..e8a25558ef76fc79f5f0f569ca923c92e849bdbc 100644 (file)
--- a/iprule.h
+++ b/iprule.h
@@ -18,6 +18,7 @@
 #include "interface-ip.h"
 
 #define IPRULE_PRIORITY_ADDR 10000
+#define IPRULE_PRIORITY_ADDR_MASK 20000
 #define IPRULE_PRIORITY_NW 90000
 #define IPRULE_PRIORITY_REJECT 4200000000