Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41384136 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'connection-tracking-support-for-bridge'



Pablo Neira Ayuso says:

====================
connection tracking support for bridge

This patchset adds native connection tracking support for the bridge.

Patch #1 and #2 extract code from IPv4/IPv6 fragmentation core and
introduce the fraglist splitter. That splits a skbuff fraglist into
independent fragments.

Patch #3 and #4 also extract code from IPv4/IPv6 fragmentation core
and introduce the skbuff into fragments transformer. This can be used
by linearized skbuffs (eg. coming from nfqueue and ct helpers) as well
as cloned skbuffs (that are either seen either with taps or with bridge
port flooding).

Patch #5 moves the specific IPCB() code from these new fragment
splitter/transformer APIs into the IPv4 stack. The bridge has a
different control buffer layout and it starts using this new APIs in
this patchset.

Patch #6 adds basic infrastructure that allows to register bridge
conntrack support.

Patch #7 adds bridge conntrack support (only for IPv4 in this patch).

Patch #8 adds IPv6 support for the bridge conntrack support.

Patch #9 registers the IPv4/IPv6 conntrack hooks in case the bridge
conntrack is used to deal with local traffic, ie. prerouting -> input
bridge hook path. This cover the bridge interface has a IP address
scenario.

Before this patchset, only chance for people to do stateful filtering is
to use the `br_netfilter` emulation layer, that turns bridge frame into
IPv4/IPv6 packets and inject them into the IPv4/IPv6 hooks. Apparently,
this module allows users to use iptables and all of its feature-set from
the bridge, including stateful filtering. However, this approach is
flawed in many aspects that have been discussed many times. This is a
step forward to deprecate `br_netfilter'.

v2: Fix English typo in commit message.
v3: Fix another English typo in commit message.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d48ecb40 af9573be
Loading
Loading
Loading
Loading
+50 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ struct ip6_rt_info {
};

struct nf_queue_entry;
struct nf_ct_bridge_frag_data;

/*
 * Hook functions for ipv6 to allow xt_* modules to be built-in even
@@ -39,6 +40,15 @@ struct nf_ipv6_ops {
	int (*fragment)(struct net *net, struct sock *sk, struct sk_buff *skb,
			int (*output)(struct net *, struct sock *, struct sk_buff *));
	int (*reroute)(struct sk_buff *skb, const struct nf_queue_entry *entry);
#if IS_MODULE(CONFIG_IPV6)
	int (*br_defrag)(struct net *net, struct sk_buff *skb, u32 user);
	int (*br_fragment)(struct net *net, struct sock *sk,
			   struct sk_buff *skb,
			   struct nf_ct_bridge_frag_data *data,
			   int (*output)(struct net *, struct sock *sk,
					 const struct nf_ct_bridge_frag_data *data,
					 struct sk_buff *));
#endif
};

#ifdef CONFIG_NETFILTER
@@ -86,6 +96,46 @@ static inline int nf_ip6_route(struct net *net, struct dst_entry **dst,
#endif
}

static inline int nf_ipv6_br_defrag(struct net *net, struct sk_buff *skb,
				    u32 user)
{
#if IS_MODULE(CONFIG_IPV6)
	const struct nf_ipv6_ops *v6_ops = nf_get_ipv6_ops();

	if (!v6_ops)
		return 1;

	return v6_ops->br_defrag(net, skb, user);
#else
	return nf_ct_frag6_gather(net, skb, user);
#endif
}

int br_ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
		    struct nf_ct_bridge_frag_data *data,
		    int (*output)(struct net *, struct sock *sk,
				  const struct nf_ct_bridge_frag_data *data,
				  struct sk_buff *));

static inline int nf_br_ip6_fragment(struct net *net, struct sock *sk,
				     struct sk_buff *skb,
				     struct nf_ct_bridge_frag_data *data,
				     int (*output)(struct net *, struct sock *sk,
						   const struct nf_ct_bridge_frag_data *data,
						   struct sk_buff *))
{
#if IS_MODULE(CONFIG_IPV6)
	const struct nf_ipv6_ops *v6_ops = nf_get_ipv6_ops();

	if (!v6_ops)
		return 1;

	return v6_ops->br_fragment(net, sk, skb, data, output);
#else
	return br_ip6_fragment(net, sk, skb, data, output);
#endif
}

int ip6_route_me_harder(struct net *net, struct sk_buff *skb);

static inline int nf_ip6_route_me_harder(struct net *net, struct sk_buff *skb)
+39 −0
Original line number Diff line number Diff line
@@ -165,6 +165,45 @@ int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb);
int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb);
int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
		   int (*output)(struct net *, struct sock *, struct sk_buff *));

struct ip_fraglist_iter {
	struct sk_buff	*frag_list;
	struct sk_buff	*frag;
	struct iphdr	*iph;
	int		offset;
	unsigned int	hlen;
};

void ip_fraglist_init(struct sk_buff *skb, struct iphdr *iph,
		      unsigned int hlen, struct ip_fraglist_iter *iter);
void ip_fraglist_prepare(struct sk_buff *skb, struct ip_fraglist_iter *iter);

static inline struct sk_buff *ip_fraglist_next(struct ip_fraglist_iter *iter)
{
	struct sk_buff *skb = iter->frag;

	iter->frag = skb->next;
	skb_mark_not_on_list(skb);

	return skb;
}

struct ip_frag_state {
	struct iphdr	*iph;
	unsigned int	hlen;
	unsigned int	ll_rs;
	unsigned int	mtu;
	unsigned int	left;
	int		offset;
	int		ptr;
	__be16		not_last_frag;
};

void ip_frag_init(struct sk_buff *skb, unsigned int hlen, unsigned int ll_rs,
		  unsigned int mtu, struct ip_frag_state *state);
struct sk_buff *ip_frag_next(struct sk_buff *skb,
			     struct ip_frag_state *state);

void ip_send_check(struct iphdr *ip);
int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
int ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb);
+44 −0
Original line number Diff line number Diff line
@@ -154,6 +154,50 @@ struct frag_hdr {
#define	IP6_MF		0x0001
#define	IP6_OFFSET	0xFFF8

struct ip6_fraglist_iter {
	struct ipv6hdr	*tmp_hdr;
	struct sk_buff	*frag_list;
	struct sk_buff	*frag;
	int		offset;
	unsigned int	hlen;
	__be32		frag_id;
	u8		nexthdr;
};

int ip6_fraglist_init(struct sk_buff *skb, unsigned int hlen, u8 *prevhdr,
		      u8 nexthdr, __be32 frag_id,
		      struct ip6_fraglist_iter *iter);
void ip6_fraglist_prepare(struct sk_buff *skb, struct ip6_fraglist_iter *iter);

static inline struct sk_buff *ip6_fraglist_next(struct ip6_fraglist_iter *iter)
{
	struct sk_buff *skb = iter->frag;

	iter->frag = skb->next;
	skb_mark_not_on_list(skb);

	return skb;
}

struct ip6_frag_state {
	u8		*prevhdr;
	unsigned int	hlen;
	unsigned int	mtu;
	unsigned int	left;
	int		offset;
	int		ptr;
	int		hroom;
	int		troom;
	__be32		frag_id;
	u8		nexthdr;
};

void ip6_frag_init(struct sk_buff *skb, unsigned int hlen, unsigned int mtu,
		   unsigned short needed_tailroom, int hdr_room, u8 *prevhdr,
		   u8 nexthdr, __be32 frag_id, struct ip6_frag_state *state);
struct sk_buff *ip6_frag_next(struct sk_buff *skb,
			      struct ip6_frag_state *state);

#define IP6_REPLY_MARK(net, mark) \
	((net)->ipv6.sysctl.fwmark_reflect ? (mark) : 0)

+1 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ union nf_conntrack_expect_proto {
struct nf_conntrack_net {
	unsigned int users4;
	unsigned int users6;
	unsigned int users_bridge;
};

#include <linux/types.h>
+20 −0
Original line number Diff line number Diff line
#ifndef NF_CONNTRACK_BRIDGE_
#define NF_CONNTRACK_BRIDGE_

struct nf_ct_bridge_info {
	struct nf_hook_ops	*ops;
	unsigned int		ops_size;
	struct module		*me;
};

void nf_ct_bridge_register(struct nf_ct_bridge_info *info);
void nf_ct_bridge_unregister(struct nf_ct_bridge_info *info);

struct nf_ct_bridge_frag_data {
	char	mac[ETH_HLEN];
	bool	vlan_present;
	u16	vlan_tci;
	__be16	vlan_proto;
};

#endif
Loading