netifd: Add rpfilter config support
[project/netifd.git] / system-linux.c
index 6a6028c..bb7ccf9 100644 (file)
@@ -265,6 +265,11 @@ static void system_set_disable_ipv6(struct device *dev, const char *val)
        system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/disable_ipv6", dev->ifname, val);
 }
 
+static void system_set_rpfilter(struct device *dev, const char *val)
+{
+       system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/rp_filter", dev->ifname, val);
+}
+
 static int system_get_sysctl(const char *path, char *buf, const size_t buf_sz)
 {
        int fd = -1, ret = -1;
@@ -299,6 +304,12 @@ static int system_get_disable_ipv6(struct device *dev, char *buf, const size_t b
                        dev->ifname, buf, buf_sz);
 }
 
+static int system_get_rpfilter(struct device *dev, char *buf, const size_t buf_sz)
+{
+       return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/rp_filter",
+                       dev->ifname, buf, buf_sz);
+}
+
 // Evaluate netlink messages
 static int cb_rtnl_event(struct nl_msg *msg, void *arg)
 {
@@ -760,7 +771,6 @@ int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvla
        struct nl_msg *msg;
        struct nlattr *linkinfo, *data;
        struct ifinfomsg iim = { .ifi_family = AF_UNSPEC, };
-       int ifindex = system_if_resolve(dev);
        int i, rv;
        static const struct {
                const char *name;
@@ -772,9 +782,6 @@ int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvla
                { "passthru", MACVLAN_MODE_PASSTHRU },
        };
 
-       if (ifindex == 0)
-               return -ENOENT;
-
        msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
 
        if (!msg)
@@ -785,7 +792,7 @@ int system_macvlan_add(struct device *macvlan, struct device *dev, struct macvla
        if (cfg->flags & MACVLAN_OPT_MACADDR)
                nla_put(msg, IFLA_ADDRESS, sizeof(cfg->macaddr), cfg->macaddr);
        nla_put_string(msg, IFLA_IFNAME, macvlan->ifname);
-       nla_put_u32(msg, IFLA_LINK, ifindex);
+       nla_put_u32(msg, IFLA_LINK, dev->ifindex);
 
        if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO)))
                goto nla_put_failure;
@@ -877,12 +884,8 @@ int system_vlandev_add(struct device *vlandev, struct device *dev, struct vlande
        struct nl_msg *msg;
        struct nlattr *linkinfo, *data;
        struct ifinfomsg iim = { .ifi_family = AF_UNSPEC };
-       int ifindex = system_if_resolve(dev);
        int rv;
 
-       if (ifindex == 0)
-               return -ENOENT;
-
        msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
 
        if (!msg)
@@ -890,7 +893,7 @@ int system_vlandev_add(struct device *vlandev, struct device *dev, struct vlande
 
        nlmsg_append(msg, &iim, sizeof(iim), 0);
        nla_put_string(msg, IFLA_IFNAME, vlandev->ifname);
-       nla_put_u32(msg, IFLA_LINK, ifindex);
+       nla_put_u32(msg, IFLA_LINK, dev->ifindex);
        
        if (!(linkinfo = nla_nest_start(msg, IFLA_LINKINFO)))
                goto nla_put_failure;
@@ -961,6 +964,11 @@ system_if_get_settings(struct device *dev, struct device_settings *s)
                s->promisc = ifr.ifr_flags & IFF_PROMISC;
                s->flags |= DEV_OPT_PROMISC;
        }
+
+       if (!system_get_rpfilter(dev, buf, sizeof(buf))) {
+               s->rpfilter = strtoul(buf, NULL, 0);
+               s->flags |= DEV_OPT_RPFILTER;
+       }
 }
 
 void
@@ -996,6 +1004,12 @@ system_if_apply_settings(struct device *dev, struct device_settings *s, unsigned
                                    !s->promisc ? IFF_PROMISC : 0) < 0)
                        s->flags &= ~DEV_OPT_PROMISC;
        }
+       if (s->flags & DEV_OPT_RPFILTER & apply_mask) {
+               char buf[2];
+
+               snprintf(buf, sizeof(buf), "%d", s->rpfilter);
+               system_set_rpfilter(dev, buf);
+       }
 }
 
 int system_if_up(struct device *dev)
@@ -1514,6 +1528,25 @@ bool system_is_default_rt_table(unsigned int id)
        return (id == RT_TABLE_MAIN);
 }
 
+bool system_resolve_rpfilter(const char *filter, unsigned int *id)
+{
+       char *e;
+       unsigned int n;
+
+       if (!strcmp(filter, "strict"))
+               n = 1;
+       else if (!strcmp(filter, "loose"))
+               n = 2;
+       else {
+               n = strtoul(filter, &e, 0);
+               if (*e || e == filter || n > 2)
+                       return false;
+       }
+
+       *id = n;
+       return true;
+}
+
 static int system_iprule(struct iprule *rule, int cmd)
 {
        int alen = ((rule->flags & IPRULE_FAMILY) == IPRULE_INET4) ? 4 : 16;