]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - net/bridge/br_netfilter_hooks.c
bridge/mdb: remove wrong use of NLM_F_MULTI
[mirror_ubuntu-bionic-kernel.git] / net / bridge / br_netfilter_hooks.c
index c2eea1b8737a154f561eba1c46999f351c28b112..980c0ca9022b8bbe04e7be42f3127664543e769d 100644 (file)
@@ -50,25 +50,22 @@ static unsigned int brnf_net_id __read_mostly;
 
 struct brnf_net {
        bool enabled;
-};
 
 #ifdef CONFIG_SYSCTL
-static struct ctl_table_header *brnf_sysctl_header;
-static int brnf_call_iptables __read_mostly = 1;
-static int brnf_call_ip6tables __read_mostly = 1;
-static int brnf_call_arptables __read_mostly = 1;
-static int brnf_filter_vlan_tagged __read_mostly;
-static int brnf_filter_pppoe_tagged __read_mostly;
-static int brnf_pass_vlan_indev __read_mostly;
-#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
+       struct ctl_table_header *ctl_hdr;
 #endif
 
+       /* default value is 1 */
+       int call_iptables;
+       int call_ip6tables;
+       int call_arptables;
+
+       /* default value is 0 */
+       int filter_vlan_tagged;
+       int filter_pppoe_tagged;
+       int pass_vlan_indev;
+};
+
 #define IS_IP(skb) \
        (!skb_vlan_tag_present(skb) && skb->protocol == htons(ETH_P_IP))
 
@@ -88,17 +85,28 @@ static inline __be16 vlan_proto(const struct sk_buff *skb)
                return 0;
 }
 
-#define IS_VLAN_IP(skb) \
-       (vlan_proto(skb) == htons(ETH_P_IP) && \
-        brnf_filter_vlan_tagged)
+static inline bool is_vlan_ip(const struct sk_buff *skb, const struct net *net)
+{
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
+
+       return vlan_proto(skb) == htons(ETH_P_IP) && brnet->filter_vlan_tagged;
+}
+
+static inline bool is_vlan_ipv6(const struct sk_buff *skb,
+                               const struct net *net)
+{
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
+
+       return vlan_proto(skb) == htons(ETH_P_IPV6) &&
+              brnet->filter_vlan_tagged;
+}
 
-#define IS_VLAN_IPV6(skb) \
-       (vlan_proto(skb) == htons(ETH_P_IPV6) && \
-        brnf_filter_vlan_tagged)
+static inline bool is_vlan_arp(const struct sk_buff *skb, const struct net *net)
+{
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
 
-#define IS_VLAN_ARP(skb) \
-       (vlan_proto(skb) == htons(ETH_P_ARP) && \
-        brnf_filter_vlan_tagged)
+       return vlan_proto(skb) == htons(ETH_P_ARP) && brnet->filter_vlan_tagged;
+}
 
 static inline __be16 pppoe_proto(const struct sk_buff *skb)
 {
@@ -106,15 +114,23 @@ static inline __be16 pppoe_proto(const struct sk_buff *skb)
                            sizeof(struct pppoe_hdr)));
 }
 
-#define IS_PPPOE_IP(skb) \
-       (skb->protocol == htons(ETH_P_PPP_SES) && \
-        pppoe_proto(skb) == htons(PPP_IP) && \
-        brnf_filter_pppoe_tagged)
+static inline bool is_pppoe_ip(const struct sk_buff *skb, const struct net *net)
+{
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
+
+       return skb->protocol == htons(ETH_P_PPP_SES) &&
+              pppoe_proto(skb) == htons(PPP_IP) && brnet->filter_pppoe_tagged;
+}
+
+static inline bool is_pppoe_ipv6(const struct sk_buff *skb,
+                                const struct net *net)
+{
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
 
-#define IS_PPPOE_IPV6(skb) \
-       (skb->protocol == htons(ETH_P_PPP_SES) && \
-        pppoe_proto(skb) == htons(PPP_IPV6) && \
-        brnf_filter_pppoe_tagged)
+       return skb->protocol == htons(ETH_P_PPP_SES) &&
+              pppoe_proto(skb) == htons(PPP_IPV6) &&
+              brnet->filter_pppoe_tagged;
+}
 
 /* largest possible L2 header, see br_nf_dev_queue_xmit() */
 #define NF_BRIDGE_MAX_MAC_HEADER_LENGTH (PPPOE_SES_HLEN + ETH_HLEN)
@@ -275,7 +291,7 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_
                struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
                int ret;
 
-               if (neigh->hh.hh_len) {
+               if ((neigh->nud_state & NUD_CONNECTED) && neigh->hh.hh_len) {
                        neigh_hh_bridge(&neigh->hh, skb);
                        skb->dev = nf_bridge->physindev;
                        ret = br_handle_frame_finish(net, sk, skb);
@@ -422,12 +438,16 @@ bridged_dnat:
        return 0;
 }
 
-static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct net_device *dev)
+static struct net_device *brnf_get_logical_dev(struct sk_buff *skb,
+                                              const struct net_device *dev,
+                                              const struct net *net)
 {
        struct net_device *vlan, *br;
+       struct brnf_net *brnet = net_generic(net, brnf_net_id);
 
        br = bridge_parent(dev);
-       if (brnf_pass_vlan_indev == 0 || !skb_vlan_tag_present(skb))
+
+       if (brnet->pass_vlan_indev == 0 || !skb_vlan_tag_present(skb))
                return br;
 
        vlan = __vlan_find_dev_deep_rcu(br, skb->vlan_proto,
@@ -437,7 +457,7 @@ static struct net_device *brnf_get_logical_dev(struct sk_buff *skb, const struct
 }
 
 /* Some common code for IPv4/IPv6 */
-struct net_device *setup_pre_routing(struct sk_buff *skb)
+struct net_device *setup_pre_routing(struct sk_buff *skb, const struct net *net)
 {
        struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
 
@@ -448,7 +468,7 @@ struct net_device *setup_pre_routing(struct sk_buff *skb)
 
        nf_bridge->in_prerouting = 1;
        nf_bridge->physindev = skb->dev;
-       skb->dev = brnf_get_logical_dev(skb, skb->dev);
+       skb->dev = brnf_get_logical_dev(skb, skb->dev, net);
 
        if (skb->protocol == htons(ETH_P_8021Q))
                nf_bridge->orig_proto = BRNF_PROTO_8021Q;
@@ -474,6 +494,7 @@ static unsigned int br_nf_pre_routing(void *priv,
        struct net_bridge_port *p;
        struct net_bridge *br;
        __u32 len = nf_bridge_encap_header_len(skb);
+       struct brnf_net *brnet;
 
        if (unlikely(!pskb_may_pull(skb, len)))
                return NF_DROP;
@@ -483,18 +504,22 @@ static unsigned int br_nf_pre_routing(void *priv,
                return NF_DROP;
        br = p->br;
 
-       if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb)) {
-               if (!brnf_call_ip6tables && !br->nf_call_ip6tables)
+       brnet = net_generic(state->net, brnf_net_id);
+       if (IS_IPV6(skb) || is_vlan_ipv6(skb, state->net) ||
+           is_pppoe_ipv6(skb, state->net)) {
+               if (!brnet->call_ip6tables &&
+                   !br_opt_get(br, BROPT_NF_CALL_IP6TABLES))
                        return NF_ACCEPT;
 
                nf_bridge_pull_encap_header_rcsum(skb);
                return br_nf_pre_routing_ipv6(priv, skb, state);
        }
 
-       if (!brnf_call_iptables && !br->nf_call_iptables)
+       if (!brnet->call_iptables && !br_opt_get(br, BROPT_NF_CALL_IPTABLES))
                return NF_ACCEPT;
 
-       if (!IS_IP(skb) && !IS_VLAN_IP(skb) && !IS_PPPOE_IP(skb))
+       if (!IS_IP(skb) && !is_vlan_ip(skb, state->net) &&
+           !is_pppoe_ip(skb, state->net))
                return NF_ACCEPT;
 
        nf_bridge_pull_encap_header_rcsum(skb);
@@ -505,13 +530,14 @@ static unsigned int br_nf_pre_routing(void *priv,
        nf_bridge_put(skb->nf_bridge);
        if (!nf_bridge_alloc(skb))
                return NF_DROP;
-       if (!setup_pre_routing(skb))
+       if (!setup_pre_routing(skb, state->net))
                return NF_DROP;
 
        nf_bridge = nf_bridge_info_get(skb);
        nf_bridge->ipv4_daddr = ip_hdr(skb)->daddr;
 
        skb->protocol = htons(ETH_P_IP);
+       skb->transport_header = skb->network_header + ip_hdr(skb)->ihl * 4;
 
        NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, state->net, state->sk, skb,
                skb->dev, NULL,
@@ -527,7 +553,7 @@ static int br_nf_forward_finish(struct net *net, struct sock *sk, struct sk_buff
        struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
        struct net_device *in;
 
-       if (!IS_ARP(skb) && !IS_VLAN_ARP(skb)) {
+       if (!IS_ARP(skb) && !is_vlan_arp(skb, net)) {
 
                if (skb->protocol == htons(ETH_P_IP))
                        nf_bridge->frag_max_size = IPCB(skb)->frag_max_size;
@@ -581,9 +607,11 @@ static unsigned int br_nf_forward_ip(void *priv,
        if (!parent)
                return NF_DROP;
 
-       if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
+       if (IS_IP(skb) || is_vlan_ip(skb, state->net) ||
+           is_pppoe_ip(skb, state->net))
                pf = NFPROTO_IPV4;
-       else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
+       else if (IS_IPV6(skb) || is_vlan_ipv6(skb, state->net) ||
+                is_pppoe_ipv6(skb, state->net))
                pf = NFPROTO_IPV6;
        else
                return NF_ACCEPT;
@@ -614,7 +642,7 @@ static unsigned int br_nf_forward_ip(void *priv,
                skb->protocol = htons(ETH_P_IPV6);
 
        NF_HOOK(pf, NF_INET_FORWARD, state->net, NULL, skb,
-               brnf_get_logical_dev(skb, state->in),
+               brnf_get_logical_dev(skb, state->in, state->net),
                parent, br_nf_forward_finish);
 
        return NF_STOLEN;
@@ -627,23 +655,25 @@ static unsigned int br_nf_forward_arp(void *priv,
        struct net_bridge_port *p;
        struct net_bridge *br;
        struct net_device **d = (struct net_device **)(skb->cb);
+       struct brnf_net *brnet;
 
        p = br_port_get_rcu(state->out);
        if (p == NULL)
                return NF_ACCEPT;
        br = p->br;
 
-       if (!brnf_call_arptables && !br->nf_call_arptables)
+       brnet = net_generic(state->net, brnf_net_id);
+       if (!brnet->call_arptables && !br_opt_get(br, BROPT_NF_CALL_ARPTABLES))
                return NF_ACCEPT;
 
        if (!IS_ARP(skb)) {
-               if (!IS_VLAN_ARP(skb))
+               if (!is_vlan_arp(skb, state->net))
                        return NF_ACCEPT;
                nf_bridge_pull_encap_header(skb);
        }
 
        if (arp_hdr(skb)->ar_pln != 4) {
-               if (IS_VLAN_ARP(skb))
+               if (is_vlan_arp(skb, state->net))
                        nf_bridge_push_encap_header(skb);
                return NF_ACCEPT;
        }
@@ -798,9 +828,11 @@ static unsigned int br_nf_post_routing(void *priv,
        if (!realoutdev)
                return NF_DROP;
 
-       if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
+       if (IS_IP(skb) || is_vlan_ip(skb, state->net) ||
+           is_pppoe_ip(skb, state->net))
                pf = NFPROTO_IPV4;
-       else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
+       else if (IS_IPV6(skb) || is_vlan_ipv6(skb, state->net) ||
+                is_pppoe_ipv6(skb, state->net))
                pf = NFPROTO_IPV6;
        else
                return NF_ACCEPT;
@@ -832,7 +864,8 @@ static unsigned int ip_sabotage_in(void *priv,
                                   struct sk_buff *skb,
                                   const struct nf_hook_state *state)
 {
-       if (skb->nf_bridge && !skb->nf_bridge->in_prerouting) {
+       if (skb->nf_bridge && !skb->nf_bridge->in_prerouting &&
+           !netif_is_l3_master(skb->dev)) {
                state->okfn(state->net, state->sk, skb);
                return NF_STOLEN;
        }
@@ -880,11 +913,6 @@ static const struct nf_br_ops br_ops = {
        .br_dev_xmit_hook =     br_nf_dev_xmit,
 };
 
-void br_netfilter_enable(void)
-{
-}
-EXPORT_SYMBOL_GPL(br_netfilter_enable);
-
 /* For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
  * br_dev_queue_push_xmit is called afterwards */
 static const struct nf_hook_ops br_nf_ops[] = {
@@ -952,23 +980,6 @@ static int brnf_device_event(struct notifier_block *unused, unsigned long event,
        return NOTIFY_OK;
 }
 
-static void __net_exit brnf_exit_net(struct net *net)
-{
-       struct brnf_net *brnet = net_generic(net, brnf_net_id);
-
-       if (!brnet->enabled)
-               return;
-
-       nf_unregister_net_hooks(net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
-       brnet->enabled = false;
-}
-
-static struct pernet_operations brnf_net_ops __read_mostly = {
-       .exit = brnf_exit_net,
-       .id   = &brnf_net_id,
-       .size = sizeof(struct brnf_net),
-};
-
 static struct notifier_block brnf_notifier __read_mostly = {
        .notifier_call = brnf_device_event,
 };
@@ -1027,50 +1038,125 @@ int brnf_sysctl_call_tables(struct ctl_table *ctl, int write,
 static struct ctl_table brnf_table[] = {
        {
                .procname       = "bridge-nf-call-arptables",
-               .data           = &brnf_call_arptables,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
        {
                .procname       = "bridge-nf-call-iptables",
-               .data           = &brnf_call_iptables,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
        {
                .procname       = "bridge-nf-call-ip6tables",
-               .data           = &brnf_call_ip6tables,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
        {
                .procname       = "bridge-nf-filter-vlan-tagged",
-               .data           = &brnf_filter_vlan_tagged,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = brnf_sysctl_call_tables,
        },
        {
                .procname       = "bridge-nf-filter-pppoe-tagged",
-               .data           = &brnf_filter_pppoe_tagged,
                .maxlen         = sizeof(int),
                .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,
        },
        { }
 };
+
+static inline void br_netfilter_sysctl_default(struct brnf_net *brnf)
+{
+       brnf->call_iptables = 1;
+       brnf->call_ip6tables = 1;
+       brnf->call_arptables = 1;
+       brnf->filter_vlan_tagged = 0;
+       brnf->filter_pppoe_tagged = 0;
+       brnf->pass_vlan_indev = 0;
+}
+
+static int br_netfilter_sysctl_init_net(struct net *net)
+{
+       struct ctl_table *table = brnf_table;
+       struct brnf_net *brnet;
+
+       if (!net_eq(net, &init_net)) {
+               table = kmemdup(table, sizeof(brnf_table), GFP_KERNEL);
+               if (!table)
+                       return -ENOMEM;
+       }
+
+       brnet = net_generic(net, brnf_net_id);
+       table[0].data = &brnet->call_arptables;
+       table[1].data = &brnet->call_iptables;
+       table[2].data = &brnet->call_ip6tables;
+       table[3].data = &brnet->filter_vlan_tagged;
+       table[4].data = &brnet->filter_pppoe_tagged;
+       table[5].data = &brnet->pass_vlan_indev;
+
+       br_netfilter_sysctl_default(brnet);
+
+       brnet->ctl_hdr = register_net_sysctl(net, "net/bridge", table);
+       if (!brnet->ctl_hdr) {
+               if (!net_eq(net, &init_net))
+                       kfree(table);
+
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void br_netfilter_sysctl_exit_net(struct net *net,
+                                        struct brnf_net *brnet)
+{
+       struct ctl_table *table = brnet->ctl_hdr->ctl_table_arg;
+
+       unregister_net_sysctl_table(brnet->ctl_hdr);
+       if (!net_eq(net, &init_net))
+               kfree(table);
+}
+
+static int __net_init brnf_init_net(struct net *net)
+{
+       return br_netfilter_sysctl_init_net(net);
+}
 #endif
 
+static void __net_exit brnf_exit_net(struct net *net)
+{
+       struct brnf_net *brnet;
+
+       brnet = net_generic(net, brnf_net_id);
+       if (brnet->enabled) {
+               nf_unregister_net_hooks(net, br_nf_ops, ARRAY_SIZE(br_nf_ops));
+               brnet->enabled = false;
+       }
+
+#ifdef CONFIG_SYSCTL
+       br_netfilter_sysctl_exit_net(net, brnet);
+#endif
+}
+
+static struct pernet_operations brnf_net_ops __read_mostly = {
+#ifdef CONFIG_SYSCTL
+       .init = brnf_init_net,
+#endif
+       .exit = brnf_exit_net,
+       .id   = &brnf_net_id,
+       .size = sizeof(struct brnf_net),
+};
+
 static int __init br_netfilter_init(void)
 {
        int ret;
@@ -1085,16 +1171,6 @@ static int __init br_netfilter_init(void)
                return ret;
        }
 
-#ifdef CONFIG_SYSCTL
-       brnf_sysctl_header = register_net_sysctl(&init_net, "net/bridge", brnf_table);
-       if (brnf_sysctl_header == NULL) {
-               printk(KERN_WARNING
-                      "br_netfilter: can't register to sysctl.\n");
-               unregister_netdevice_notifier(&brnf_notifier);
-               unregister_pernet_subsys(&brnf_net_ops);
-               return -ENOMEM;
-       }
-#endif
        RCU_INIT_POINTER(nf_br_ops, &br_ops);
        printk(KERN_NOTICE "Bridge firewalling registered\n");
        return 0;
@@ -1105,9 +1181,6 @@ static void __exit br_netfilter_fini(void)
        RCU_INIT_POINTER(nf_br_ops, NULL);
        unregister_netdevice_notifier(&brnf_notifier);
        unregister_pernet_subsys(&brnf_net_ops);
-#ifdef CONFIG_SYSCTL
-       unregister_net_sysctl_table(brnf_sysctl_header);
-#endif
 }
 
 module_init(br_netfilter_init);