netfilter: bridge: add helpers for fetching physin/outdev

right now we store this in the nf_bridge_info struct, accessible
via skb->nf_bridge.  This patch prepares removal of this pointer from skb:

Instead of using skb->nf_bridge->x, we use helpers to obtain the in/out
device (or ifindexes).

Followup patches to netfilter will then allow nf_bridge_info to be
obtained by a call into the br_netfilter core, rather than keeping a
pointer to it in sk_buff.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Florian Westphal 2015-04-02 14:31:41 +02:00 committed by Pablo Neira Ayuso
parent e70deecbf8
commit c737b7c451
8 changed files with 97 additions and 34 deletions

View File

@ -2,7 +2,7 @@
#define __LINUX_BRIDGE_NETFILTER_H #define __LINUX_BRIDGE_NETFILTER_H
#include <uapi/linux/netfilter_bridge.h> #include <uapi/linux/netfilter_bridge.h>
#include <linux/skbuff.h>
enum nf_br_hook_priorities { enum nf_br_hook_priorities {
NF_BR_PRI_FIRST = INT_MIN, NF_BR_PRI_FIRST = INT_MIN,
@ -40,6 +40,27 @@ static inline void br_drop_fake_rtable(struct sk_buff *skb)
skb_dst_drop(skb); skb_dst_drop(skb);
} }
static inline int nf_bridge_get_physinif(const struct sk_buff *skb)
{
return skb->nf_bridge ? skb->nf_bridge->physindev->ifindex : 0;
}
static inline int nf_bridge_get_physoutif(const struct sk_buff *skb)
{
return skb->nf_bridge ? skb->nf_bridge->physoutdev->ifindex : 0;
}
static inline struct net_device *
nf_bridge_get_physindev(const struct sk_buff *skb)
{
return skb->nf_bridge ? skb->nf_bridge->physindev : NULL;
}
static inline struct net_device *
nf_bridge_get_physoutdev(const struct sk_buff *skb)
{
return skb->nf_bridge ? skb->nf_bridge->physoutdev : NULL;
}
#else #else
#define br_drop_fake_rtable(skb) do { } while (0) #define br_drop_fake_rtable(skb) do { } while (0)
#endif /* CONFIG_BRIDGE_NETFILTER */ #endif /* CONFIG_BRIDGE_NETFILTER */

View File

@ -13,6 +13,7 @@
#include <net/dst.h> #include <net/dst.h>
#include <net/netfilter/ipv4/nf_reject.h> #include <net/netfilter/ipv4/nf_reject.h>
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
#include <linux/netfilter_bridge.h>
#include <net/netfilter/ipv4/nf_reject.h> #include <net/netfilter/ipv4/nf_reject.h>
const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb, const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb,
@ -146,7 +147,8 @@ void nf_send_reset(struct sk_buff *oldskb, int hook)
*/ */
if (oldskb->nf_bridge) { if (oldskb->nf_bridge) {
struct ethhdr *oeth = eth_hdr(oldskb); struct ethhdr *oeth = eth_hdr(oldskb);
nskb->dev = oldskb->nf_bridge->physindev;
nskb->dev = nf_bridge_get_physindev(oldskb);
niph->tot_len = htons(nskb->len); niph->tot_len = htons(nskb->len);
ip_send_check(niph); ip_send_check(niph);
if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),

View File

@ -13,6 +13,7 @@
#include <net/ip6_checksum.h> #include <net/ip6_checksum.h>
#include <net/netfilter/ipv6/nf_reject.h> #include <net/netfilter/ipv6/nf_reject.h>
#include <linux/netfilter_ipv6.h> #include <linux/netfilter_ipv6.h>
#include <linux/netfilter_bridge.h>
#include <net/netfilter/ipv6/nf_reject.h> #include <net/netfilter/ipv6/nf_reject.h>
const struct tcphdr *nf_reject_ip6_tcphdr_get(struct sk_buff *oldskb, const struct tcphdr *nf_reject_ip6_tcphdr_get(struct sk_buff *oldskb,
@ -195,7 +196,8 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
*/ */
if (oldskb->nf_bridge) { if (oldskb->nf_bridge) {
struct ethhdr *oeth = eth_hdr(oldskb); struct ethhdr *oeth = eth_hdr(oldskb);
nskb->dev = oldskb->nf_bridge->physindev;
nskb->dev = nf_bridge_get_physindev(oldskb);
nskb->protocol = htons(ETH_P_IPV6); nskb->protocol = htons(ETH_P_IPV6);
ip6h->payload_len = htons(sizeof(struct tcphdr)); ip6h->payload_len = htons(sizeof(struct tcphdr));
if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),

View File

@ -19,6 +19,7 @@
#include <net/netlink.h> #include <net/netlink.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter_bridge.h>
#include <linux/netfilter/ipset/pfxlen.h> #include <linux/netfilter/ipset/pfxlen.h>
#include <linux/netfilter/ipset/ip_set.h> #include <linux/netfilter/ipset/ip_set.h>
#include <linux/netfilter/ipset/ip_set_hash.h> #include <linux/netfilter/ipset/ip_set_hash.h>
@ -211,6 +212,22 @@ hash_netiface4_data_next(struct hash_netiface4_elem *next,
#define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed) #define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed)
#include "ip_set_hash_gen.h" #include "ip_set_hash_gen.h"
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
static const char *get_physindev_name(const struct sk_buff *skb)
{
struct net_device *dev = nf_bridge_get_physindev(skb);
return dev ? dev->name : NULL;
}
static const char *get_phyoutdev_name(const struct sk_buff *skb)
{
struct net_device *dev = nf_bridge_get_physoutdev(skb);
return dev ? dev->name : NULL;
}
#endif
static int static int
hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb, hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par,
@ -234,16 +251,15 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
e.ip &= ip_set_netmask(e.cidr); e.ip &= ip_set_netmask(e.cidr);
#define IFACE(dir) (par->dir ? par->dir->name : NULL) #define IFACE(dir) (par->dir ? par->dir->name : NULL)
#define PHYSDEV(dir) (nf_bridge->dir ? nf_bridge->dir->name : NULL)
#define SRCDIR (opt->flags & IPSET_DIM_TWO_SRC) #define SRCDIR (opt->flags & IPSET_DIM_TWO_SRC)
if (opt->cmdflags & IPSET_FLAG_PHYSDEV) { if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
const struct nf_bridge_info *nf_bridge = skb->nf_bridge; e.iface = SRCDIR ? get_physindev_name(skb) :
get_phyoutdev_name(skb);
if (!nf_bridge) if (!e.iface)
return -EINVAL; return -EINVAL;
e.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
e.physdev = 1; e.physdev = 1;
#else #else
e.iface = NULL; e.iface = NULL;
@ -476,11 +492,11 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
if (opt->cmdflags & IPSET_FLAG_PHYSDEV) { if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
const struct nf_bridge_info *nf_bridge = skb->nf_bridge; e.iface = SRCDIR ? get_physindev_name(skb) :
get_phyoutdev_name(skb);
if (!nf_bridge) if (!e.iface)
return -EINVAL; return -EINVAL;
e.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
e.physdev = 1; e.physdev = 1;
#else #else
e.iface = NULL; e.iface = NULL;

View File

@ -17,6 +17,7 @@
#include <net/route.h> #include <net/route.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter_bridge.h>
#include <linux/netfilter/xt_LOG.h> #include <linux/netfilter/xt_LOG.h>
#include <net/netfilter/nf_log.h> #include <net/netfilter/nf_log.h>
@ -163,10 +164,10 @@ nf_log_dump_packet_common(struct nf_log_buf *m, u_int8_t pf,
const struct net_device *physindev; const struct net_device *physindev;
const struct net_device *physoutdev; const struct net_device *physoutdev;
physindev = skb->nf_bridge->physindev; physindev = nf_bridge_get_physindev(skb);
if (physindev && in != physindev) if (physindev && in != physindev)
nf_log_buf_add(m, "PHYSIN=%s ", physindev->name); nf_log_buf_add(m, "PHYSIN=%s ", physindev->name);
physoutdev = skb->nf_bridge->physoutdev; physoutdev = nf_bridge_get_physoutdev(skb);
if (physoutdev && out != physoutdev) if (physoutdev && out != physoutdev)
nf_log_buf_add(m, "PHYSOUT=%s ", physoutdev->name); nf_log_buf_add(m, "PHYSOUT=%s ", physoutdev->name);
} }

View File

@ -10,6 +10,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter_bridge.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <net/protocol.h> #include <net/protocol.h>
@ -54,12 +55,14 @@ void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
dev_put(entry->outdev); dev_put(entry->outdev);
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
if (entry->skb->nf_bridge) { if (entry->skb->nf_bridge) {
struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge; struct net_device *physdev;
if (nf_bridge->physindev) physdev = nf_bridge_get_physindev(entry->skb);
dev_put(nf_bridge->physindev); if (physdev)
if (nf_bridge->physoutdev) dev_put(physdev);
dev_put(nf_bridge->physoutdev); physdev = nf_bridge_get_physoutdev(entry->skb);
if (physdev)
dev_put(physdev);
} }
#endif #endif
/* Drop reference to owner of hook which queued us. */ /* Drop reference to owner of hook which queued us. */
@ -79,13 +82,12 @@ bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)
dev_hold(entry->outdev); dev_hold(entry->outdev);
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
if (entry->skb->nf_bridge) { if (entry->skb->nf_bridge) {
struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge;
struct net_device *physdev; struct net_device *physdev;
physdev = nf_bridge->physindev; physdev = nf_bridge_get_physindev(entry->skb);
if (physdev) if (physdev)
dev_hold(physdev); dev_hold(physdev);
physdev = nf_bridge->physoutdev; physdev = nf_bridge_get_physoutdev(entry->skb);
if (physdev) if (physdev)
dev_hold(physdev); dev_hold(physdev);
} }

View File

@ -23,6 +23,7 @@
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter_bridge.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_log.h> #include <linux/netfilter/nfnetlink_log.h>
@ -448,14 +449,18 @@ __build_packet_message(struct nfnl_log_net *log,
htonl(br_port_get_rcu(indev)->br->dev->ifindex))) htonl(br_port_get_rcu(indev)->br->dev->ifindex)))
goto nla_put_failure; goto nla_put_failure;
} else { } else {
struct net_device *physindev;
/* Case 2: indev is bridge group, we need to look for /* Case 2: indev is bridge group, we need to look for
* physical device (when called from ipv4) */ * physical device (when called from ipv4) */
if (nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV, if (nla_put_be32(inst->skb, NFULA_IFINDEX_INDEV,
htonl(indev->ifindex))) htonl(indev->ifindex)))
goto nla_put_failure; goto nla_put_failure;
if (skb->nf_bridge && skb->nf_bridge->physindev &&
physindev = nf_bridge_get_physindev(skb);
if (physindev &&
nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSINDEV, nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSINDEV,
htonl(skb->nf_bridge->physindev->ifindex))) htonl(physindev->ifindex)))
goto nla_put_failure; goto nla_put_failure;
} }
#endif #endif
@ -479,14 +484,18 @@ __build_packet_message(struct nfnl_log_net *log,
htonl(br_port_get_rcu(outdev)->br->dev->ifindex))) htonl(br_port_get_rcu(outdev)->br->dev->ifindex)))
goto nla_put_failure; goto nla_put_failure;
} else { } else {
struct net_device *physoutdev;
/* Case 2: indev is a bridge group, we need to look /* Case 2: indev is a bridge group, we need to look
* for physical device (when called from ipv4) */ * for physical device (when called from ipv4) */
if (nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV, if (nla_put_be32(inst->skb, NFULA_IFINDEX_OUTDEV,
htonl(outdev->ifindex))) htonl(outdev->ifindex)))
goto nla_put_failure; goto nla_put_failure;
if (skb->nf_bridge && skb->nf_bridge->physoutdev &&
physoutdev = nf_bridge_get_physoutdev(skb);
if (physoutdev &&
nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV, nla_put_be32(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
htonl(skb->nf_bridge->physoutdev->ifindex))) htonl(physoutdev->ifindex)))
goto nla_put_failure; goto nla_put_failure;
} }
#endif #endif

View File

@ -25,6 +25,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h> #include <linux/netfilter_ipv6.h>
#include <linux/netfilter_bridge.h>
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_queue.h> #include <linux/netfilter/nfnetlink_queue.h>
#include <linux/list.h> #include <linux/list.h>
@ -396,14 +397,18 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
htonl(br_port_get_rcu(indev)->br->dev->ifindex))) htonl(br_port_get_rcu(indev)->br->dev->ifindex)))
goto nla_put_failure; goto nla_put_failure;
} else { } else {
int physinif;
/* Case 2: indev is bridge group, we need to look for /* Case 2: indev is bridge group, we need to look for
* physical device (when called from ipv4) */ * physical device (when called from ipv4) */
if (nla_put_be32(skb, NFQA_IFINDEX_INDEV, if (nla_put_be32(skb, NFQA_IFINDEX_INDEV,
htonl(indev->ifindex))) htonl(indev->ifindex)))
goto nla_put_failure; goto nla_put_failure;
if (entskb->nf_bridge && entskb->nf_bridge->physindev &&
physinif = nf_bridge_get_physinif(entskb);
if (physinif &&
nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV, nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV,
htonl(entskb->nf_bridge->physindev->ifindex))) htonl(physinif)))
goto nla_put_failure; goto nla_put_failure;
} }
#endif #endif
@ -426,14 +431,18 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
htonl(br_port_get_rcu(outdev)->br->dev->ifindex))) htonl(br_port_get_rcu(outdev)->br->dev->ifindex)))
goto nla_put_failure; goto nla_put_failure;
} else { } else {
int physoutif;
/* Case 2: outdev is bridge group, we need to look for /* Case 2: outdev is bridge group, we need to look for
* physical output device (when called from ipv4) */ * physical output device (when called from ipv4) */
if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV,
htonl(outdev->ifindex))) htonl(outdev->ifindex)))
goto nla_put_failure; goto nla_put_failure;
if (entskb->nf_bridge && entskb->nf_bridge->physoutdev &&
physoutif = nf_bridge_get_physoutif(entskb);
if (physoutif &&
nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV, nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV,
htonl(entskb->nf_bridge->physoutdev->ifindex))) htonl(physoutif)))
goto nla_put_failure; goto nla_put_failure;
} }
#endif #endif
@ -765,11 +774,12 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
return 1; return 1;
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
if (entry->skb->nf_bridge) { if (entry->skb->nf_bridge) {
if (entry->skb->nf_bridge->physindev && int physinif, physoutif;
entry->skb->nf_bridge->physindev->ifindex == ifindex)
return 1; physinif = nf_bridge_get_physinif(entry->skb);
if (entry->skb->nf_bridge->physoutdev && physoutif = nf_bridge_get_physoutif(entry->skb);
entry->skb->nf_bridge->physoutdev->ifindex == ifindex)
if (physinif == ifindex || physoutif == ifindex)
return 1; return 1;
} }
#endif #endif