1831 lines · 43.8 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/list.h>#include <linux/cgroup-defs.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 /* 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 rcu_head rcu; 	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 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 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; 	spin_lock(&q->instances_lock);	if (instance_lookup(q, queue_num)) {		err = -EEXIST;		goto out_unlock;	} 	inst = kzalloc(sizeof(*inst), GFP_ATOMIC);	if (!inst) {		err = -ENOMEM;		goto out_unlock;	} 	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); 	if (!try_module_get(THIS_MODULE)) {		err = -EAGAIN;		goto out_free;	} 	h = instance_hashfn(queue_num);	hlist_add_head_rcu(&inst->hlist, &q->instance_table[h]); 	spin_unlock(&q->instances_lock); 	return inst; out_free:	kfree(inst);out_unlock:	spin_unlock(&q->instances_lock);	return ERR_PTR(err);} static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn,			unsigned long data); static voidinstance_destroy_rcu(struct rcu_head *head){	struct nfqnl_instance *inst = container_of(head, struct nfqnl_instance,						   rcu); 	rcu_read_lock();	nfqnl_flush(inst, NULL, 0);	rcu_read_unlock();	kfree(inst);	module_put(THIS_MODULE);} static void__instance_destroy(struct nfqnl_instance *inst){	hlist_del_rcu(&inst->hlist);	call_rcu(&inst->rcu, instance_destroy_rcu);} 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 inline void__enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry){       list_add_tail(&entry->list, &queue->queue_list);       queue->queue_total++;} static void__dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry){	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 = NULL, *i; 	spin_lock_bh(&queue->lock); 	list_for_each_entry(i, &queue->queue_list, list) {		if (i->id == id) {			entry = i;			break;		}	} 	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_reroute(struct sk_buff *skb, struct nf_queue_entry *entry){	const struct nf_ipv6_ops *v6ops;	int ret = 0; 	switch (entry->state.pf) {	case AF_INET:		ret = nf_ip_reroute(skb, entry);		break;	case AF_INET6:		v6ops = rcu_dereference(nf_ipv6_ops);		if (v6ops)			ret = v6ops->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);} static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict){	const struct nf_ct_hook *ct_hook; 	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(); 		switch (ct_verdict & NF_VERDICT_MASK) {		case NF_ACCEPT:			/* follow userspace verdict, could be REPEAT */			break;		case NF_STOLEN:			nf_queue_entry_free(entry);			return;		default:			verdict = ct_verdict & NF_VERDICT_MASK;			break;		}	}	nf_reinject(entry, verdict);} static voidnfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data){	struct nf_queue_entry *entry, *next; 	spin_lock_bh(&queue->lock);	list_for_each_entry_safe(entry, next, &queue->queue_list, list) {		if (!cmpfn || cmpfn(entry, data)) {			list_del(&entry->list);			queue->queue_total--;			nfqnl_reinject(entry, NF_DROP);		}	}	spin_unlock_bh(&queue->lock);} static intnfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet,		      bool csum_verify){	__u32 flags = 0; 	if (packet->ip_summed == CHECKSUM_PARTIAL)		flags = NFQA_SKB_CSUMNOTREADY;	else if (csum_verify)		flags = NFQA_SKB_CSUM_NOTVERIFIED; 	if (skb_is_gso(packet))		flags |= NFQA_SKB_GSO; 	return flags ? nla_put_be32(nlskb, NFQA_SKB_INFO, htonl(flags)) : 0;} static int nfqnl_put_sk_uidgid(struct sk_buff *skb, struct sock *sk){	const struct cred *cred; 	if (!sk_fullsock(sk))		return 0; 	read_lock_bh(&sk->sk_callback_lock);	if (sk->sk_socket && sk->sk_socket->file) {		cred = sk->sk_socket->file->f_cred;		if (nla_put_be32(skb, NFQA_UID,		    htonl(from_kuid_munged(&init_user_ns, cred->fsuid))))			goto nla_put_failure;		if (nla_put_be32(skb, NFQA_GID,		    htonl(from_kgid_munged(&init_user_ns, cred->fsgid))))			goto nla_put_failure;	}	read_unlock_bh(&sk->sk_callback_lock);	return 0; nla_put_failure:	read_unlock_bh(&sk->sk_callback_lock);	return -1;} static int nfqnl_put_sk_classid(struct sk_buff *skb, struct sock *sk){#if IS_ENABLED(CONFIG_CGROUP_NET_CLASSID)	if (sk && sk_fullsock(sk)) {		u32 classid = sock_cgroup_classid(&sk->sk_cgrp_data); 		if (classid && nla_put_be32(skb, NFQA_CGROUP_CLASSID, htonl(classid)))			return -1;	}#endif	return 0;} static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, char **secdata){	u32 seclen = 0;#if IS_ENABLED(CONFIG_NETWORK_SECMARK)	if (!skb || !sk_fullsock(skb->sk))		return 0; 	read_lock_bh(&skb->sk->sk_callback_lock); 	if (skb->secmark)		security_secid_to_secctx(skb->secmark, secdata, &seclen); 	read_unlock_bh(&skb->sk->sk_callback_lock);#endif	return seclen;} static u32 nfqnl_get_bridge_size(struct nf_queue_entry *entry){	struct sk_buff *entskb = entry->skb;	u32 nlalen = 0; 	if (entry->state.pf != PF_BRIDGE || !skb_mac_header_was_set(entskb))		return 0; 	if (skb_vlan_tag_present(entskb))		nlalen += nla_total_size(nla_total_size(sizeof(__be16)) +					 nla_total_size(sizeof(__be16)));

Lines 1–500 of 1831.