⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nfnetlink_log.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * This is a module which is used for logging packets to userspace via * nfetlink. * * (C) 2005 by Harald Welte <laforge@netfilter.org> * * Based on the old ipv4-only ipt_ULOG.c: * (C) 2000-2004 by Harald Welte <laforge@netfilter.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/module.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/ip.h>#include <linux/ipv6.h>#include <linux/netdevice.h>#include <linux/netfilter.h>#include <linux/netlink.h>#include <linux/netfilter/nfnetlink.h>#include <linux/netfilter/nfnetlink_log.h>#include <linux/spinlock.h>#include <linux/sysctl.h>#include <linux/proc_fs.h>#include <linux/security.h>#include <linux/list.h>#include <linux/jhash.h>#include <linux/random.h>#include <net/sock.h>#include <asm/atomic.h>#ifdef CONFIG_BRIDGE_NETFILTER#include "../bridge/br_private.h"#endif#define NFULNL_NLBUFSIZ_DEFAULT	NLMSG_GOODSIZE#define NFULNL_TIMEOUT_DEFAULT 	HZ	/* every second */#define NFULNL_QTHRESH_DEFAULT 	100	/* 100 packets */#define NFULNL_COPY_RANGE_MAX	0xFFFF	/* max packet size is limited by 16-bit struct nfattr nfa_len field */#define PRINTR(x, args...)	do { if (net_ratelimit()) \				     printk(x, ## args); } while (0);#if 0#define UDEBUG(x, args ...)	printk(KERN_DEBUG "%s(%d):%s():	" x, 	   \					__FILE__, __LINE__, __FUNCTION__,  \					## args)#else#define UDEBUG(x, ...)#endifstruct nfulnl_instance {	struct hlist_node hlist;	/* global list of instances */	spinlock_t lock;	atomic_t use;			/* use count */	unsigned int qlen;		/* number of nlmsgs in skb */	struct sk_buff *skb;		/* pre-allocatd skb */	struct timer_list timer;	int peer_pid;			/* PID of the peer process */	/* configurable parameters */	unsigned int flushtimeout;	/* timeout until queue flush */	unsigned int nlbufsiz;		/* netlink buffer allocation size */	unsigned int qthreshold;	/* threshold of the queue */	u_int32_t copy_range;	u_int32_t seq;			/* instance-local sequential counter */	u_int16_t group_num;		/* number of this queue */	u_int16_t flags;	u_int8_t copy_mode;};static DEFINE_RWLOCK(instances_lock);static atomic_t global_seq;#define INSTANCE_BUCKETS	16static struct hlist_head instance_table[INSTANCE_BUCKETS];static unsigned int hash_init;static inline u_int8_t instance_hashfn(u_int16_t group_num){	return ((group_num & 0xff) % INSTANCE_BUCKETS);}static struct nfulnl_instance *__instance_lookup(u_int16_t group_num){	struct hlist_head *head;	struct hlist_node *pos;	struct nfulnl_instance *inst;	UDEBUG("entering (group_num=%u)\n", group_num);	head = &instance_table[instance_hashfn(group_num)];	hlist_for_each_entry(inst, pos, head, hlist) {		if (inst->group_num == group_num)			return inst;	}	return NULL;}static inline voidinstance_get(struct nfulnl_instance *inst){	atomic_inc(&inst->use);}static struct nfulnl_instance *instance_lookup_get(u_int16_t group_num){	struct nfulnl_instance *inst;	read_lock_bh(&instances_lock);	inst = __instance_lookup(group_num);	if (inst)		instance_get(inst);	read_unlock_bh(&instances_lock);	return inst;}static voidinstance_put(struct nfulnl_instance *inst){	if (inst && atomic_dec_and_test(&inst->use)) {		UDEBUG("kfree(inst=%p)\n", inst);		kfree(inst);		module_put(THIS_MODULE);	}}static void nfulnl_timer(unsigned long data);static struct nfulnl_instance *instance_create(u_int16_t group_num, int pid){	struct nfulnl_instance *inst;	UDEBUG("entering (group_num=%u, pid=%d)\n", group_num,		pid);	write_lock_bh(&instances_lock);	if (__instance_lookup(group_num)) {		inst = NULL;		UDEBUG("aborting, instance already exists\n");		goto out_unlock;	}	inst = kzalloc(sizeof(*inst), GFP_ATOMIC);	if (!inst)		goto out_unlock;	if (!try_module_get(THIS_MODULE)) {		kfree(inst);		goto out_unlock;	}	INIT_HLIST_NODE(&inst->hlist);	spin_lock_init(&inst->lock);	/* needs to be two, since we _put() after creation */	atomic_set(&inst->use, 2);	setup_timer(&inst->timer, nfulnl_timer, (unsigned long)inst);	inst->peer_pid = pid;	inst->group_num = group_num;	inst->qthreshold 	= NFULNL_QTHRESH_DEFAULT;	inst->flushtimeout 	= NFULNL_TIMEOUT_DEFAULT;	inst->nlbufsiz 		= NFULNL_NLBUFSIZ_DEFAULT;	inst->copy_mode 	= NFULNL_COPY_PACKET;	inst->copy_range 	= NFULNL_COPY_RANGE_MAX;	hlist_add_head(&inst->hlist,		       &instance_table[instance_hashfn(group_num)]);	UDEBUG("newly added node: %p, next=%p\n", &inst->hlist,		inst->hlist.next);	write_unlock_bh(&instances_lock);	return inst;out_unlock:	write_unlock_bh(&instances_lock);	return NULL;}static void __nfulnl_flush(struct nfulnl_instance *inst);static void__instance_destroy(struct nfulnl_instance *inst){	/* first pull it out of the global list */	UDEBUG("removing instance %p (queuenum=%u) from hash\n",		inst, inst->group_num);	hlist_del(&inst->hlist);	/* then flush all pending packets from skb */	spin_lock_bh(&inst->lock);	if (inst->skb)		__nfulnl_flush(inst);	spin_unlock_bh(&inst->lock);	/* and finally put the refcount */	instance_put(inst);}static inline voidinstance_destroy(struct nfulnl_instance *inst){	write_lock_bh(&instances_lock);	__instance_destroy(inst);	write_unlock_bh(&instances_lock);}static intnfulnl_set_mode(struct nfulnl_instance *inst, u_int8_t mode,		  unsigned int range){	int status = 0;	spin_lock_bh(&inst->lock);	switch (mode) {	case NFULNL_COPY_NONE:	case NFULNL_COPY_META:		inst->copy_mode = mode;		inst->copy_range = 0;		break;	case NFULNL_COPY_PACKET:		inst->copy_mode = mode;		inst->copy_range = min_t(unsigned int,					 range, NFULNL_COPY_RANGE_MAX);		break;	default:		status = -EINVAL;		break;	}	spin_unlock_bh(&inst->lock);	return status;}static intnfulnl_set_nlbufsiz(struct nfulnl_instance *inst, u_int32_t nlbufsiz){	int status;	spin_lock_bh(&inst->lock);	if (nlbufsiz < NFULNL_NLBUFSIZ_DEFAULT)		status = -ERANGE;	else if (nlbufsiz > 131072)		status = -ERANGE;	else {		inst->nlbufsiz = nlbufsiz;		status = 0;	}	spin_unlock_bh(&inst->lock);	return status;}static intnfulnl_set_timeout(struct nfulnl_instance *inst, u_int32_t timeout){	spin_lock_bh(&inst->lock);	inst->flushtimeout = timeout;	spin_unlock_bh(&inst->lock);	return 0;}static intnfulnl_set_qthresh(struct nfulnl_instance *inst, u_int32_t qthresh){	spin_lock_bh(&inst->lock);	inst->qthreshold = qthresh;	spin_unlock_bh(&inst->lock);	return 0;}static intnfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags){	spin_lock_bh(&inst->lock);	inst->flags = flags;	spin_unlock_bh(&inst->lock);	return 0;}static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size){	struct sk_buff *skb;	unsigned int n;	UDEBUG("entered (%u, %u)\n", inst_size, pkt_size);	/* alloc skb which should be big enough for a whole multipart	 * message.  WARNING: has to be <= 128k due to slab restrictions */	n = max(inst_size, pkt_size);	skb = alloc_skb(n, GFP_ATOMIC);	if (!skb) {		PRINTR("nfnetlink_log: can't alloc whole buffer (%u bytes)\n",			inst_size);		if (n > pkt_size) {			/* try to allocate only as much as we need for current			 * packet */			skb = alloc_skb(pkt_size, GFP_ATOMIC);			if (!skb)				PRINTR("nfnetlink_log: can't even alloc %u "				       "bytes\n", pkt_size);		}	}	return skb;}static int__nfulnl_send(struct nfulnl_instance *inst){	int status = -1;	if (inst->qlen > 1)		NLMSG_PUT(inst->skb, 0, 0,			  NLMSG_DONE,			  sizeof(struct nfgenmsg));	status = nfnetlink_unicast(inst->skb, inst->peer_pid, MSG_DONTWAIT);	if (status < 0) {		UDEBUG("netlink_unicast() failed\n");		/* FIXME: statistics */	}	inst->qlen = 0;	inst->skb = NULL;nlmsg_failure:	return status;}static void__nfulnl_flush(struct nfulnl_instance *inst){	/* timer holds a reference */	if (del_timer(&inst->timer))		instance_put(inst);	if (inst->skb)		__nfulnl_send(inst);}static voidnfulnl_timer(unsigned long data){	struct nfulnl_instance *inst = (struct nfulnl_instance *)data;	UDEBUG("timer function called, flushing buffer\n");	spin_lock_bh(&inst->lock);	if (inst->skb)		__nfulnl_send(inst);	spin_unlock_bh(&inst->lock);	instance_put(inst);}/* This is an inline function, we don't really care about a long * list of arguments */static inline int__build_packet_message(struct nfulnl_instance *inst,			const struct sk_buff *skb,			unsigned int data_len,			unsigned int pf,			unsigned int hooknum,			const struct net_device *indev,			const struct net_device *outdev,			const struct nf_loginfo *li,			const char *prefix, unsigned int plen){	struct nfulnl_msg_packet_hdr pmsg;	struct nlmsghdr *nlh;	struct nfgenmsg *nfmsg;	__be32 tmp_uint;	sk_buff_data_t old_tail = inst->skb->tail;	UDEBUG("entered\n");	nlh = NLMSG_PUT(inst->skb, 0, 0,			NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET,			sizeof(struct nfgenmsg));	nfmsg = NLMSG_DATA(nlh);	nfmsg->nfgen_family = pf;	nfmsg->version = NFNETLINK_V0;	nfmsg->res_id = htons(inst->group_num);	pmsg.hw_protocol	= skb->protocol;	pmsg.hook		= hooknum;	NLA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg);	if (prefix)		NLA_PUT(inst->skb, NFULA_PREFIX, plen, prefix);	if (indev) {		tmp_uint = htonl(indev->ifindex);#ifndef CONFIG_BRIDGE_NETFILTER		NLA_PUT(inst->skb, NFULA_IFINDEX_INDEV, sizeof(tmp_uint),			&tmp_uint);#else		if (pf == PF_BRIDGE) {			/* Case 1: outdev is physical input device, we need to			 * look for bridge group (when called from			 * netfilter_bridge) */			NLA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,				sizeof(tmp_uint), &tmp_uint);			/* this is the bridge group "brX" */			tmp_uint = htonl(indev->br_port->br->dev->ifindex);			NLA_PUT(inst->skb, NFULA_IFINDEX_INDEV,				sizeof(tmp_uint), &tmp_uint);		} else {			/* Case 2: indev is bridge group, we need to look for			 * physical device (when called from ipv4) */			NLA_PUT(inst->skb, NFULA_IFINDEX_INDEV,				sizeof(tmp_uint), &tmp_uint);			if (skb->nf_bridge && skb->nf_bridge->physindev) {				tmp_uint =				    htonl(skb->nf_bridge->physindev->ifindex);				NLA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,					sizeof(tmp_uint), &tmp_uint);			}		}#endif	}	if (outdev) {		tmp_uint = htonl(outdev->ifindex);#ifndef CONFIG_BRIDGE_NETFILTER		NLA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, sizeof(tmp_uint),			&tmp_uint);#else		if (pf == PF_BRIDGE) {			/* Case 1: outdev is physical output device, we need to			 * look for bridge group (when called from			 * netfilter_bridge) */			NLA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,				sizeof(tmp_uint), &tmp_uint);			/* this is the bridge group "brX" */			tmp_uint = htonl(outdev->br_port->br->dev->ifindex);			NLA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV,				sizeof(tmp_uint), &tmp_uint);		} else {			/* Case 2: indev is a bridge group, we need to look			 * for physical device (when called from ipv4) */			NLA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV,				sizeof(tmp_uint), &tmp_uint);			if (skb->nf_bridge && skb->nf_bridge->physoutdev) {				tmp_uint =				    htonl(skb->nf_bridge->physoutdev->ifindex);				NLA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,					sizeof(tmp_uint), &tmp_uint);			}		}#endif	}	if (skb->mark) {		tmp_uint = htonl(skb->mark);		NLA_PUT(inst->skb, NFULA_MARK, sizeof(tmp_uint), &tmp_uint);	}	if (indev && skb->dev) {		struct nfulnl_msg_packet_hw phw;		int len = dev_parse_header(skb, phw.hw_addr);		if (len > 0) {			phw.hw_addrlen = htons(len);			NLA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw);		}	}	if (skb->tstamp.tv64) {		struct nfulnl_msg_packet_timestamp ts;		struct timeval tv = ktime_to_timeval(skb->tstamp);		ts.sec = cpu_to_be64(tv.tv_sec);		ts.usec = cpu_to_be64(tv.tv_usec);		NLA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts);	}	/* UID */	if (skb->sk) {		read_lock_bh(&skb->sk->sk_callback_lock);		if (skb->sk->sk_socket && skb->sk->sk_socket->file) {			__be32 uid = htonl(skb->sk->sk_socket->file->f_uid);			/* need to unlock here since NLA_PUT may goto */			read_unlock_bh(&skb->sk->sk_callback_lock);			NLA_PUT(inst->skb, NFULA_UID, sizeof(uid), &uid);		} else			read_unlock_bh(&skb->sk->sk_callback_lock);	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -