linux/net/bridge/br_netfilter_hooks.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *	Handle firewalling
 *	Linux ethernet bridge
 *
 *	Authors:
 *	Lennert Buytenhek		<[email protected]>
 *	Bart De Schuymer		<[email protected]>
 *
 *	Lennert dedicates this file to Kerstin Wurdinger.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/ip.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/if_pppox.h>
#include <linux/ppp_defs.h>
#include <linux/netfilter_bridge.h>
#include <uapi/linux/netfilter_bridge.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/netfilter_arp.h>
#include <linux/in_route.h>
#include <linux/rculist.h>
#include <linux/inetdevice.h>

#include <net/ip.h>
#include <net/ipv6.h>
#include <net/addrconf.h>
#include <net/route.h>
#include <net/netfilter/br_netfilter.h>
#include <net/netns/generic.h>

#include <linux/uaccess.h>
#include "br_private.h"
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif

#if IS_ENABLED(CONFIG_NF_CONNTRACK)
#include <net/netfilter/nf_conntrack_core.h>
#endif

static unsigned int brnf_net_id __read_mostly;

struct brnf_net {};

#define IS_IP(skb)

#define IS_IPV6(skb)

#define IS_ARP(skb)

static inline __be16 vlan_proto(const struct sk_buff *skb)
{}

static inline bool is_vlan_ip(const struct sk_buff *skb, const struct net *net)
{}

static inline bool is_vlan_ipv6(const struct sk_buff *skb,
				const struct net *net)
{}

static inline bool is_vlan_arp(const struct sk_buff *skb, const struct net *net)
{}

static inline __be16 pppoe_proto(const struct sk_buff *skb)
{}

static inline bool is_pppoe_ip(const struct sk_buff *skb, const struct net *net)
{}

static inline bool is_pppoe_ipv6(const struct sk_buff *skb,
				 const struct net *net)
{}

/* largest possible L2 header, see br_nf_dev_queue_xmit() */
#define NF_BRIDGE_MAX_MAC_HEADER_LENGTH

struct brnf_frag_data {};

static DEFINE_PER_CPU(struct brnf_frag_data, brnf_frag_data_storage) =;

static void nf_bridge_info_free(struct sk_buff *skb)
{}

static inline struct net_device *bridge_parent(const struct net_device *dev)
{}

static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb)
{}

unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb)
{}

static inline void nf_bridge_pull_encap_header(struct sk_buff *skb)
{}

static inline void nf_bridge_pull_encap_header_rcsum(struct sk_buff *skb)
{}

/* When handing a packet over to the IP layer
 * check whether we have a skb that is in the
 * expected format
 */

static int br_validate_ipv4(struct net *net, struct sk_buff *skb)
{}

void nf_bridge_update_protocol(struct sk_buff *skb)
{}

/* Obtain the correct destination MAC address, while preserving the original
 * source MAC address. If we already know this address, we just copy it. If we
 * don't, we use the neighbour framework to find out. In both cases, we make
 * sure that br_handle_frame_finish() is called afterwards.
 */
int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_buff *skb)
{}

static inline bool
br_nf_ipv4_daddr_was_changed(const struct sk_buff *skb,
			     const struct nf_bridge_info *nf_bridge)
{}

/* This requires some explaining. If DNAT has taken place,
 * we will need to fix up the destination Ethernet address.
 * This is also true when SNAT takes place (for the reply direction).
 *
 * There are two cases to consider:
 * 1. The packet was DNAT'ed to a device in the same bridge
 *    port group as it was received on. We can still bridge
 *    the packet.
 * 2. The packet was DNAT'ed to a different device, either
 *    a non-bridged device or another bridge port group.
 *    The packet will need to be routed.
 *
 * The correct way of distinguishing between these two cases is to
 * call ip_route_input() and to look at skb->dst->dev, which is
 * changed to the destination device if ip_route_input() succeeds.
 *
 * Let's first consider the case that ip_route_input() succeeds:
 *
 * If the output device equals the logical bridge device the packet
 * came in on, we can consider this bridging. The corresponding MAC
 * address will be obtained in br_nf_pre_routing_finish_bridge.
 * Otherwise, the packet is considered to be routed and we just
 * change the destination MAC address so that the packet will
 * later be passed up to the IP stack to be routed. For a redirected
 * packet, ip_route_input() will give back the localhost as output device,
 * which differs from the bridge device.
 *
 * Let's now consider the case that ip_route_input() fails:
 *
 * This can be because the destination address is martian, in which case
 * the packet will be dropped.
 * If IP forwarding is disabled, ip_route_input() will fail, while
 * ip_route_output_key() can return success. The source
 * address for ip_route_output_key() is set to zero, so ip_route_output_key()
 * thinks we're handling a locally generated packet and won't care
 * if IP forwarding is enabled. If the output device equals the logical bridge
 * device, we proceed as if ip_route_input() succeeded. If it differs from the
 * logical bridge port or if ip_route_output_key() fails we drop the packet.
 */
static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{}

static struct net_device *brnf_get_logical_dev(struct sk_buff *skb,
					       const struct net_device *dev,
					       const struct net *net)
{}

/* Some common code for IPv4/IPv6 */
struct net_device *setup_pre_routing(struct sk_buff *skb, const struct net *net)
{}

/* Direct IPv6 traffic to br_nf_pre_routing_ipv6.
 * Replicate the checks that IPv4 does on packet reception.
 * Set skb->dev to the bridge device (i.e. parent of the
 * receiving device) to make netfilter happy, the REDIRECT
 * target in particular.  Save the original destination IP
 * address to be able to detect DNAT afterwards. */
static unsigned int br_nf_pre_routing(void *priv,
				      struct sk_buff *skb,
				      const struct nf_hook_state *state)
{}

#if IS_ENABLED(CONFIG_NF_CONNTRACK)
/* conntracks' nf_confirm logic cannot handle cloned skbs referencing
 * the same nf_conn entry, which will happen for multicast (broadcast)
 * Frames on bridges.
 *
 * Example:
 *      macvlan0
 *      br0
 *  ethX  ethY
 *
 * ethX (or Y) receives multicast or broadcast packet containing
 * an IP packet, not yet in conntrack table.
 *
 * 1. skb passes through bridge and fake-ip (br_netfilter)Prerouting.
 *    -> skb->_nfct now references a unconfirmed entry
 * 2. skb is broad/mcast packet. bridge now passes clones out on each bridge
 *    interface.
 * 3. skb gets passed up the stack.
 * 4. In macvlan case, macvlan driver retains clone(s) of the mcast skb
 *    and schedules a work queue to send them out on the lower devices.
 *
 *    The clone skb->_nfct is not a copy, it is the same entry as the
 *    original skb.  The macvlan rx handler then returns RX_HANDLER_PASS.
 * 5. Normal conntrack hooks (in NF_INET_LOCAL_IN) confirm the orig skb.
 *
 * The Macvlan broadcast worker and normal confirm path will race.
 *
 * This race will not happen if step 2 already confirmed a clone. In that
 * case later steps perform skb_clone() with skb->_nfct already confirmed (in
 * hash table).  This works fine.
 *
 * But such confirmation won't happen when eb/ip/nftables rules dropped the
 * packets before they reached the nf_confirm step in postrouting.
 *
 * Work around this problem by explicit confirmation of the entry at
 * LOCAL_IN time, before upper layer has a chance to clone the unconfirmed
 * entry.
 *
 */
static unsigned int br_nf_local_in(void *priv,
				   struct sk_buff *skb,
				   const struct nf_hook_state *state)
{}
#endif

/* PF_BRIDGE/FORWARD *************************************************/
static int br_nf_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{}


static unsigned int br_nf_forward_ip(struct sk_buff *skb,
				     const struct nf_hook_state *state,
				     u8 pf)
{}

static unsigned int br_nf_forward_arp(struct sk_buff *skb,
				      const struct nf_hook_state *state)
{}

/* This is the 'purely bridged' case.  For IP, we pass the packet to
 * netfilter with indev and outdev set to the bridge device,
 * but we are still able to filter on the 'real' indev/outdev
 * because of the physdev module. For ARP, indev and outdev are the
 * bridge ports.
 */
static unsigned int br_nf_forward(void *priv,
				  struct sk_buff *skb,
				  const struct nf_hook_state *state)
{}

static int br_nf_push_frag_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
{}

static int
br_nf_ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
		  int (*output)(struct net *, struct sock *, struct sk_buff *))
{}

static unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb)
{}

static int br_nf_dev_queue_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
{}

/* PF_BRIDGE/POST_ROUTING ********************************************/
static unsigned int br_nf_post_routing(void *priv,
				       struct sk_buff *skb,
				       const struct nf_hook_state *state)
{}

/* IP/SABOTAGE *****************************************************/
/* Don't hand locally destined packets to PF_INET(6)/PRE_ROUTING
 * for the second time. */
static unsigned int ip_sabotage_in(void *priv,
				   struct sk_buff *skb,
				   const struct nf_hook_state *state)
{}

/* This is called when br_netfilter has called into iptables/netfilter,
 * and DNAT has taken place on a bridge-forwarded packet.
 *
 * neigh->output has created a new MAC header, with local br0 MAC
 * as saddr.
 *
 * This restores the original MAC saddr of the bridged packet
 * before invoking bridge forward logic to transmit the packet.
 */
static void br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb)
{}

static int br_nf_dev_xmit(struct sk_buff *skb)
{}

static const struct nf_br_ops br_ops =;

/* 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[] =;

static int brnf_device_event(struct notifier_block *unused, unsigned long event,
			     void *ptr)
{}

static struct notifier_block brnf_notifier __read_mostly =;

/* recursively invokes nf_hook_slow (again), skipping already-called
 * hooks (< NF_BR_PRI_BRNF).
 *
 * Called with rcu read lock held.
 */
int br_nf_hook_thresh(unsigned int hook, struct net *net,
		      struct sock *sk, struct sk_buff *skb,
		      struct net_device *indev,
		      struct net_device *outdev,
		      int (*okfn)(struct net *, struct sock *,
				  struct sk_buff *))
{}

#ifdef CONFIG_SYSCTL
static
int brnf_sysctl_call_tables(const struct ctl_table *ctl, int write,
			    void *buffer, size_t *lenp, loff_t *ppos)
{}

static struct ctl_table brnf_table[] =;

static inline void br_netfilter_sysctl_default(struct brnf_net *brnf)
{}

static int br_netfilter_sysctl_init_net(struct net *net)
{}

static void br_netfilter_sysctl_exit_net(struct net *net,
					 struct brnf_net *brnet)
{}

static int __net_init brnf_init_net(struct net *net)
{}
#endif

static void __net_exit brnf_exit_net(struct net *net)
{}

static struct pernet_operations brnf_net_ops __read_mostly =;

static int __init br_netfilter_init(void)
{}

static void __exit br_netfilter_fini(void)
{}

module_init();
module_exit(br_netfilter_fini);

MODULE_LICENSE();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_DESCRIPTION();