netfilter: bridge: optionally set indev to vlan
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 8 May 2012 17:36:44 +0000 (19:36 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 8 May 2012 17:36:47 +0000 (19:36 +0200)
if net.bridge.bridge-nf-filter-vlan-tagged sysctl is enabled, bridge
netfilter removes the vlan header temporarily and then feeds the packet
to ip(6)tables.

When the new "bridge-nf-pass-vlan-input-device" sysctl is on
(default off), then bridge netfilter will also set the
in-interface to the vlan interface; if such an interface exists.

This is needed to make iptables REDIRECT target work with
"vlan-on-top-of-bridge" setups and to allow use of "iptables -i" to
match the vlan device name.

Also update Documentation with current brnf default settings.

Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: Bart De Schuymer <bdschuym@pandora.be>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Documentation/networking/ip-sysctl.txt
net/bridge/br_netfilter.c

index 90b0c4fd275b10ffe1c5b1ad05a0cdf78f367033..6f896b94abdc74369a28eb48f8af74bfe2c0c84a 100644 (file)
@@ -1301,13 +1301,22 @@ bridge-nf-call-ip6tables - BOOLEAN
 bridge-nf-filter-vlan-tagged - BOOLEAN
        1 : pass bridged vlan-tagged ARP/IP/IPv6 traffic to {arp,ip,ip6}tables.
        0 : disable this.
-       Default: 1
+       Default: 0
 
 bridge-nf-filter-pppoe-tagged - BOOLEAN
        1 : pass bridged pppoe-tagged IP/IPv6 traffic to {ip,ip6}tables.
        0 : disable this.
-       Default: 1
+       Default: 0
 
+bridge-nf-pass-vlan-input-dev - BOOLEAN
+       1: if bridge-nf-filter-vlan-tagged is enabled, try to find a vlan
+       interface on the bridge and set the netfilter input device to the vlan.
+       This allows use of e.g. "iptables -i br0.1" and makes the REDIRECT
+       target work with vlan-on-top-of-bridge interfaces.  When no matching
+       vlan interface is found, or this switch is off, the input device is
+       set to the bridge interface.
+       0: disable bridge netfilter vlan interface lookup.
+       Default: 0
 
 proc/sys/net/sctp/* Variables:
 
index 53f083686ae470a4f56b60f5fed0ba1a43f07123..dce55d4ee83b95b97dffd7ccab94a2ad8815a225 100644 (file)
@@ -54,12 +54,14 @@ static int brnf_call_ip6tables __read_mostly = 1;
 static int brnf_call_arptables __read_mostly = 1;
 static int brnf_filter_vlan_tagged __read_mostly = 0;
 static int brnf_filter_pppoe_tagged __read_mostly = 0;
+static int brnf_pass_vlan_indev __read_mostly = 0;
 #else
 #define brnf_call_iptables 1
 #define brnf_call_ip6tables 1
 #define brnf_call_arptables 1
 #define brnf_filter_vlan_tagged 0
 #define brnf_filter_pppoe_tagged 0
+#define brnf_pass_vlan_indev 0
 #endif
 
 #define IS_IP(skb) \
@@ -503,6 +505,19 @@ bridged_dnat:
        return 0;
 }
 
+static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct net_device *dev)
+{
+       struct net_device *vlan, *br;
+
+       br = bridge_parent(dev);
+       if (brnf_pass_vlan_indev == 0 || !vlan_tx_tag_present(skb))
+               return br;
+
+       vlan = __vlan_find_dev_deep(br, vlan_tx_tag_get(skb) & VLAN_VID_MASK);
+
+       return vlan ? vlan : br;
+}
+
 /* Some common code for IPv4/IPv6 */
 static struct net_device *setup_pre_routing(struct sk_buff *skb)
 {
@@ -515,7 +530,7 @@ static struct net_device *setup_pre_routing(struct sk_buff *skb)
 
        nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING;
        nf_bridge->physindev = skb->dev;
-       skb->dev = bridge_parent(skb->dev);
+       skb->dev = brnf_get_logical_dev(skb, skb->dev);
        if (skb->protocol == htons(ETH_P_8021Q))
                nf_bridge->mask |= BRNF_8021Q;
        else if (skb->protocol == htons(ETH_P_PPP_SES))
@@ -774,7 +789,7 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
        else
                skb->protocol = htons(ETH_P_IPV6);
 
-       NF_HOOK(pf, NF_INET_FORWARD, skb, bridge_parent(in), parent,
+       NF_HOOK(pf, NF_INET_FORWARD, skb, brnf_get_logical_dev(skb, in), parent,
                br_nf_forward_finish);
 
        return NF_STOLEN;
@@ -1002,6 +1017,13 @@ static ctl_table brnf_table[] = {
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
+       {
+               .procname       = "bridge-nf-pass-vlan-input-dev",
+               .data           = &brnf_pass_vlan_indev,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = brnf_sysctl_call_tables,
+       },
        { }
 };
 #endif