]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
route: add support for directed broadcast forwarding
authorXin Long <lucien.xin@gmail.com>
Fri, 27 Jul 2018 08:37:28 +0000 (16:37 +0800)
committerDavid S. Miller <davem@davemloft.net>
Sun, 29 Jul 2018 19:37:06 +0000 (12:37 -0700)
This patch implements the feature described in rfc1812#section-5.3.5.2
and rfc2644. It allows the router to forward directed broadcast when
sysctl bc_forwarding is enabled.

Note that this feature could be done by iptables -j TEE, but it would
cause some problems:
  - target TEE's gateway param has to be set with a specific address,
    and it's not flexible especially when the route wants forward all
    directed broadcasts.
  - this duplicates the directed broadcasts so this may cause side
    effects to applications.

Besides, to keep consistent with other os router like BSD, it's also
necessary to implement it in the route rx path.

Note that route cache needs to be flushed when bc_forwarding is
changed.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/inetdevice.h
include/uapi/linux/ip.h
include/uapi/linux/netconf.h
net/ipv4/devinet.c
net/ipv4/route.c

index 27650f1bff3d7ad8595935de659d658f35de6dd8..c759d1cbcedd8d7f19f835457641dee9761a0fa0 100644 (file)
@@ -93,6 +93,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
 
 #define IN_DEV_FORWARD(in_dev)         IN_DEV_CONF_GET((in_dev), FORWARDING)
 #define IN_DEV_MFORWARD(in_dev)                IN_DEV_ANDCONF((in_dev), MC_FORWARDING)
+#define IN_DEV_BFORWARD(in_dev)                IN_DEV_ANDCONF((in_dev), BC_FORWARDING)
 #define IN_DEV_RPFILTER(in_dev)                IN_DEV_MAXCONF((in_dev), RP_FILTER)
 #define IN_DEV_SRC_VMARK(in_dev)       IN_DEV_ORCONF((in_dev), SRC_VMARK)
 #define IN_DEV_SOURCE_ROUTE(in_dev)    IN_DEV_ANDCONF((in_dev), \
index b24a742beae58974722348255ebe239584661905..e42d13b55cf3acafd90f0ec6d13ebd685ad3f684 100644 (file)
@@ -168,6 +168,7 @@ enum
        IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
        IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
        IPV4_DEVCONF_DROP_GRATUITOUS_ARP,
+       IPV4_DEVCONF_BC_FORWARDING,
        __IPV4_DEVCONF_MAX
 };
 
index c84fcdfca862e67887bfe89dc8bea523c9a1d4d2..fac4edd553798cd87a24278bd4683632cd562f7f 100644 (file)
@@ -18,6 +18,7 @@ enum {
        NETCONFA_PROXY_NEIGH,
        NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
        NETCONFA_INPUT,
+       NETCONFA_BC_FORWARDING,
        __NETCONFA_MAX
 };
 #define NETCONFA_MAX   (__NETCONFA_MAX - 1)
index d7585ab1a77a0e9d0f942960811a7c61c70ae129..ea4bd8a52422e75c98e30cb3ab537e97b2170520 100644 (file)
@@ -1827,6 +1827,8 @@ static int inet_netconf_msgsize_devconf(int type)
                size += nla_total_size(4);
        if (all || type == NETCONFA_MC_FORWARDING)
                size += nla_total_size(4);
+       if (all || type == NETCONFA_BC_FORWARDING)
+               size += nla_total_size(4);
        if (all || type == NETCONFA_PROXY_NEIGH)
                size += nla_total_size(4);
        if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
@@ -1873,6 +1875,10 @@ static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex,
            nla_put_s32(skb, NETCONFA_MC_FORWARDING,
                        IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0)
                goto nla_put_failure;
+       if ((all || type == NETCONFA_BC_FORWARDING) &&
+           nla_put_s32(skb, NETCONFA_BC_FORWARDING,
+                       IPV4_DEVCONF(*devconf, BC_FORWARDING)) < 0)
+               goto nla_put_failure;
        if ((all || type == NETCONFA_PROXY_NEIGH) &&
            nla_put_s32(skb, NETCONFA_PROXY_NEIGH,
                        IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0)
@@ -2143,6 +2149,10 @@ static int devinet_conf_proc(struct ctl_table *ctl, int write,
                        if ((new_value == 0) && (old_value != 0))
                                rt_cache_flush(net);
 
+               if (i == IPV4_DEVCONF_BC_FORWARDING - 1 &&
+                   new_value != old_value)
+                       rt_cache_flush(net);
+
                if (i == IPV4_DEVCONF_RP_FILTER - 1 &&
                    new_value != old_value) {
                        ifindex = devinet_conf_ifindex(net, cnf);
@@ -2259,6 +2269,7 @@ static struct devinet_sysctl_table {
                DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding",
                                             devinet_sysctl_forward),
                DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"),
+               DEVINET_SYSCTL_RW_ENTRY(BC_FORWARDING, "bc_forwarding"),
 
                DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"),
                DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"),
index 1df6e97106d79eef9dfde27472c5f9c20cae3943..b678466da451c994b7baec77f96c482afe62da4b 100644 (file)
@@ -1996,8 +1996,11 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
                goto no_route;
        }
 
-       if (res->type == RTN_BROADCAST)
+       if (res->type == RTN_BROADCAST) {
+               if (IN_DEV_BFORWARD(in_dev))
+                       goto make_route;
                goto brd_input;
+       }
 
        if (res->type == RTN_LOCAL) {
                err = fib_validate_source(skb, saddr, daddr, tos,
@@ -2014,6 +2017,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        if (res->type != RTN_UNICAST)
                goto martian_destination;
 
+make_route:
        err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos, flkeys);
 out:   return err;