2210 lines · 53.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * This is a module which is used for queueing packets and communicating with * userspace via nfnetlink. * * (C) 2005 by Harald Welte <laforge@netfilter.org> * (C) 2007 by Patrick McHardy <kaber@trash.net> * * Based on the old ipv4-only ip_queue.c: * (C) 2000-2002 James Morris <jmorris@intercode.com.au> * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org> */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/notifier.h>#include <linux/netdevice.h>#include <linux/netfilter.h>#include <linux/proc_fs.h>#include <linux/netfilter_ipv4.h>#include <linux/netfilter_ipv6.h>#include <linux/netfilter_bridge.h>#include <linux/netfilter/nfnetlink.h>#include <linux/netfilter/nfnetlink_queue.h>#include <linux/netfilter/nf_conntrack_common.h>#include <linux/icmp.h>#include <linux/icmpv6.h>#include <linux/ip.h>#include <linux/list.h>#include <linux/sctp.h>#include <linux/cgroup-defs.h>#include <linux/rhashtable.h>#include <linux/jhash.h>#include <linux/tcp.h>#include <linux/udp.h>#include <net/gre.h>#include <net/gso.h>#include <net/sock.h>#include <net/tcp_states.h>#include <net/netfilter/nf_queue.h>#include <net/netns/generic.h> #include <linux/atomic.h> #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)#include "../bridge/br_private.h"#endif #if IS_ENABLED(CONFIG_NF_CONNTRACK)#include <net/netfilter/nf_conntrack.h>#endif #define NFQNL_QMAX_DEFAULT 1024#define NFQNL_HASH_MIN     8#define NFQNL_HASH_MAX     32768 /* We're using struct nlattr which has 16bit nla_len. Note that nla_len * includes the header length. Thus, the maximum packet length that we * support is 65531 bytes. We send truncated packets if the specified length * is larger than that.  Userspace can check for presence of NFQA_CAP_LEN * attribute to detect truncation. */#define NFQNL_MAX_COPY_RANGE (0xffff - NLA_HDRLEN) struct nfqnl_instance {	struct hlist_node hlist;		/* global list of queues */	struct rhashtable nfqnl_packet_map;	struct rcu_work	rwork; 	u32 peer_portid;	unsigned int queue_maxlen;	unsigned int copy_range;	unsigned int queue_dropped;	unsigned int queue_user_dropped;  	u_int16_t queue_num;			/* number of this queue */	u_int8_t copy_mode;	u_int32_t flags;			/* Set using NFQA_CFG_FLAGS *//* * Following fields are dirtied for each queued packet, * keep them in same cache line if possible. */	spinlock_t	lock	____cacheline_aligned_in_smp;	unsigned int	queue_total;	unsigned int	id_sequence;		/* 'sequence' of pkt ids */	struct list_head queue_list;		/* packets in queue */}; typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long); static struct workqueue_struct *nfq_cleanup_wq __read_mostly;static unsigned int nfnl_queue_net_id __read_mostly; #define INSTANCE_BUCKETS	16struct nfnl_queue_net {	spinlock_t instances_lock;	struct hlist_head instance_table[INSTANCE_BUCKETS];}; static struct nfnl_queue_net *nfnl_queue_pernet(struct net *net){	return net_generic(net, nfnl_queue_net_id);} static inline u_int8_t instance_hashfn(u_int16_t queue_num){	return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS;} static const struct rhashtable_params nfqnl_rhashtable_params = {	.head_offset = offsetof(struct nf_queue_entry, hash_node),	.key_offset = offsetof(struct nf_queue_entry, id),	.key_len = sizeof(u32),	.automatic_shrinking = true,	.min_size = NFQNL_HASH_MIN,	.max_size = NFQNL_HASH_MAX,}; static struct nfqnl_instance *instance_lookup(struct nfnl_queue_net *q, u_int16_t queue_num){	struct hlist_head *head;	struct nfqnl_instance *inst; 	head = &q->instance_table[instance_hashfn(queue_num)];	hlist_for_each_entry_rcu(inst, head, hlist) {		if (inst->queue_num == queue_num)			return inst;	}	return NULL;} static struct nfqnl_instance *instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid){	struct nfqnl_instance *inst;	unsigned int h;	int err; 	inst = kzalloc_obj(*inst, GFP_KERNEL_ACCOUNT);	if (!inst)		return ERR_PTR(-ENOMEM); 	inst->queue_num = queue_num;	inst->peer_portid = portid;	inst->queue_maxlen = NFQNL_QMAX_DEFAULT;	inst->copy_range = NFQNL_MAX_COPY_RANGE;	inst->copy_mode = NFQNL_COPY_NONE;	spin_lock_init(&inst->lock);	INIT_LIST_HEAD(&inst->queue_list); 	err = rhashtable_init(&inst->nfqnl_packet_map, &nfqnl_rhashtable_params);	if (err < 0)		goto out_free; 	spin_lock(&q->instances_lock);	if (instance_lookup(q, queue_num)) {		err = -EEXIST;		goto out_unlock;	} 	if (!try_module_get(THIS_MODULE)) {		err = -EAGAIN;		goto out_unlock;	} 	h = instance_hashfn(queue_num);	hlist_add_head_rcu(&inst->hlist, &q->instance_table[h]); 	spin_unlock(&q->instances_lock); 	return inst; out_unlock:	spin_unlock(&q->instances_lock);	rhashtable_destroy(&inst->nfqnl_packet_map);out_free:	kfree(inst);	return ERR_PTR(err);} static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn,			unsigned long data); static void instance_destroy_work(struct work_struct *work){	struct nfqnl_instance *inst; 	inst = container_of(to_rcu_work(work), struct nfqnl_instance,			    rwork);	rcu_read_lock();	nfqnl_flush(inst, NULL, 0);	rcu_read_unlock(); 	rhashtable_destroy(&inst->nfqnl_packet_map); 	kfree(inst);	module_put(THIS_MODULE);} static void__instance_destroy(struct nfqnl_instance *inst){	hlist_del_rcu(&inst->hlist); 	INIT_RCU_WORK(&inst->rwork, instance_destroy_work);	queue_rcu_work(nfq_cleanup_wq, &inst->rwork);} static voidinstance_destroy(struct nfnl_queue_net *q, struct nfqnl_instance *inst){	spin_lock(&q->instances_lock);	__instance_destroy(inst);	spin_unlock(&q->instances_lock);} static int__enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry){	int err; 	err = rhashtable_insert_fast(&queue->nfqnl_packet_map, &entry->hash_node,				     nfqnl_rhashtable_params);	if (unlikely(err))		return err; 	list_add_tail(&entry->list, &queue->queue_list);	queue->queue_total++; 	return 0;} static void__dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry){	rhashtable_remove_fast(&queue->nfqnl_packet_map, &entry->hash_node,			       nfqnl_rhashtable_params);	list_del(&entry->list);	queue->queue_total--;} static struct nf_queue_entry *find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id){	struct nf_queue_entry *entry; 	spin_lock_bh(&queue->lock);	entry = rhashtable_lookup_fast(&queue->nfqnl_packet_map, &id,				       nfqnl_rhashtable_params); 	if (entry)		__dequeue_entry(queue, entry); 	spin_unlock_bh(&queue->lock); 	return entry;} static unsigned int nf_iterate(struct sk_buff *skb,			       struct nf_hook_state *state,			       const struct nf_hook_entries *hooks,			       unsigned int *index){	const struct nf_hook_entry *hook;	unsigned int verdict, i = *index; 	while (i < hooks->num_hook_entries) {		hook = &hooks->hooks[i];repeat:		verdict = nf_hook_entry_hookfn(hook, skb, state);		if (verdict != NF_ACCEPT) {			*index = i;			if (verdict != NF_REPEAT)				return verdict;			goto repeat;		}		i++;	} 	*index = i;	return NF_ACCEPT;} static struct nf_hook_entries *nf_hook_entries_head(const struct net *net, u8 pf, u8 hooknum){	switch (pf) {#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE	case NFPROTO_BRIDGE:		return rcu_dereference(net->nf.hooks_bridge[hooknum]);#endif	case NFPROTO_IPV4:		return rcu_dereference(net->nf.hooks_ipv4[hooknum]);	case NFPROTO_IPV6:		return rcu_dereference(net->nf.hooks_ipv6[hooknum]);	default:		WARN_ON_ONCE(1);		return NULL;	} 	return NULL;} static int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry){#ifdef CONFIG_INET	const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry); 	if (entry->state.hook == NF_INET_LOCAL_OUT) {		const struct iphdr *iph = ip_hdr(skb); 		if (!(iph->tos == rt_info->tos &&		      skb->mark == rt_info->mark &&		      iph->daddr == rt_info->daddr &&		      iph->saddr == rt_info->saddr))			return ip_route_me_harder(entry->state.net, entry->state.sk,						  skb, RTN_UNSPEC);	}#endif	return 0;} static int nf_ip6_reroute(struct sk_buff *skb,			  const struct nf_queue_entry *entry){	struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry); 	if (entry->state.hook == NF_INET_LOCAL_OUT) {		const struct ipv6hdr *iph = ipv6_hdr(skb); 		if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||		    !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) ||		    skb->mark != rt_info->mark)			return nf_ip6_route_me_harder(entry->state.net,						      entry->state.sk, skb);	}	return 0;} static int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry){	int ret = 0; 	switch (entry->state.pf) {	case AF_INET:		ret = nf_ip_reroute(skb, entry);		break;	case AF_INET6:		ret = nf_ip6_reroute(skb, entry);		break;	}	return ret;} /* caller must hold rcu read-side lock */static void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict){	const struct nf_hook_entry *hook_entry;	const struct nf_hook_entries *hooks;	struct sk_buff *skb = entry->skb;	const struct net *net;	unsigned int i;	int err;	u8 pf; 	net = entry->state.net;	pf = entry->state.pf; 	hooks = nf_hook_entries_head(net, pf, entry->state.hook); 	i = entry->hook_index;	if (!hooks || i >= hooks->num_hook_entries) {		kfree_skb_reason(skb, SKB_DROP_REASON_NETFILTER_DROP);		nf_queue_entry_free(entry);		return;	} 	hook_entry = &hooks->hooks[i]; 	/* Continue traversal iff userspace said ok... */	if (verdict == NF_REPEAT)		verdict = nf_hook_entry_hookfn(hook_entry, skb, &entry->state); 	if (verdict == NF_ACCEPT) {		if (nf_reroute(skb, entry) < 0)			verdict = NF_DROP;	} 	if (verdict == NF_ACCEPT) {next_hook:		++i;		verdict = nf_iterate(skb, &entry->state, hooks, &i);	} 	switch (verdict & NF_VERDICT_MASK) {	case NF_ACCEPT:	case NF_STOP:		local_bh_disable();		entry->state.okfn(entry->state.net, entry->state.sk, skb);		local_bh_enable();		break;	case NF_QUEUE:		err = nf_queue(skb, &entry->state, i, verdict);		if (err == 1)			goto next_hook;		break;	case NF_STOLEN:		break;	default:		kfree_skb(skb);	} 	nf_queue_entry_free(entry);} /* return true if the entry has an unconfirmed conntrack attached that isn't owned by us * exclusively. */static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry, bool *is_unconfirmed){#if IS_ENABLED(CONFIG_NF_CONNTRACK)	struct nf_conn *ct = (void *)skb_nfct(entry->skb); 	if (!ct || nf_ct_is_confirmed(ct))		return false; 	if (is_unconfirmed)		*is_unconfirmed = true; 	/* in some cases skb_clone() can occur after initial conntrack	 * pickup, but conntrack assumes exclusive skb->_nfct ownership for	 * unconfirmed entries.	 *	 * This happens for br_netfilter and with ip multicast routing.	 * This can't be solved with serialization here because one clone	 * could have been queued for local delivery or could be transmitted	 * in parallel on another CPU.	 */	return refcount_read(&ct->ct_general.use) > 1;#endif	return false;} static bool nf_bridge_port_valid(const struct net_device *dev){	if (!dev)		return true; 	return netif_is_bridge_port(dev);} /* queued skbs leave rcu protection.  We bump device refcount so that * the device cannot go away.  However, while packet was out the port * could have been removed from the bridge. * * Ensure in+outdev are still part of a bridge at reinject time. * * The device rx_handler_data could even be pointing at data that is * not a net_bridge_port structure. */static bool nf_bridge_ports_valid(const struct nf_queue_entry *entry){#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)	if (!nf_bridge_port_valid(entry->physin) ||	    !nf_bridge_port_valid(entry->physout))		return false;#endif	if (entry->state.pf != PF_BRIDGE)		return true; 	if (!nf_bridge_port_valid(entry->state.in) ||	    !nf_bridge_port_valid(entry->state.out))		return false; 	return true;} static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict){	const struct nf_ct_hook *ct_hook; 	if (!nf_bridge_ports_valid(entry))		verdict = NF_DROP; 	if (verdict == NF_ACCEPT ||	    verdict == NF_REPEAT ||	    verdict == NF_STOP) {		unsigned int ct_verdict = verdict; 		rcu_read_lock();		ct_hook = rcu_dereference(nf_ct_hook);		if (ct_hook)			ct_verdict = ct_hook->update(entry->state.net, entry->skb);		rcu_read_unlock();

Lines 1–500 of 2210.