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

📄 ip_conntrack_netlink.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Connection tracking via netlink socket. Allows for user space * protocol helpers and general trouble making from userspace. * * (C) 2001 by Jay Schulist <jschlst@samba.org> * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org> * (C) 2003 by Patrick Mchardy <kaber@trash.net> * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net> * * I've reworked this stuff to use attributes instead of conntrack  * structures. 5.44 am. I need more tea. --pablo 05/07/11. * * Initial connection tracking via netlink development funded and  * generally made possible by Network Robots, Inc. (www.networkrobots.com) * * Further development of this code funded by Astaro AG (http://www.astaro.com) * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. */#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/timer.h>#include <linux/skbuff.h>#include <linux/errno.h>#include <linux/netlink.h>#include <linux/spinlock.h>#include <linux/interrupt.h>#include <linux/notifier.h>#include <linux/netfilter.h>#include <linux/netfilter_ipv4/ip_conntrack.h>#include <linux/netfilter_ipv4/ip_conntrack_core.h>#include <linux/netfilter_ipv4/ip_conntrack_helper.h>#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>#include <linux/netfilter_ipv4/ip_nat_protocol.h>#include <linux/netfilter/nfnetlink.h>#include <linux/netfilter/nfnetlink_conntrack.h>MODULE_LICENSE("GPL");static char __initdata version[] = "0.90";#if 0#define DEBUGP printk#else#define DEBUGP(format, args...)#endifstatic inline intctnetlink_dump_tuples_proto(struct sk_buff *skb, 			    const struct ip_conntrack_tuple *tuple){	struct ip_conntrack_protocol *proto;	int ret = 0;	NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);	/* If no protocol helper is found, this function will return the	 * generic protocol helper, so proto won't *ever* be NULL */	proto = ip_conntrack_proto_find_get(tuple->dst.protonum);	if (likely(proto->tuple_to_nfattr))		ret = proto->tuple_to_nfattr(skb, tuple);		ip_conntrack_proto_put(proto);	return ret;nfattr_failure:	return -1;}static inline intctnetlink_dump_tuples(struct sk_buff *skb, 		      const struct ip_conntrack_tuple *tuple){	struct nfattr *nest_parms;		nest_parms = NFA_NEST(skb, CTA_TUPLE_IP);	NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip);	NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.ip);	NFA_NEST_END(skb, nest_parms);	nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO);	ctnetlink_dump_tuples_proto(skb, tuple);	NFA_NEST_END(skb, nest_parms);	return 0;nfattr_failure:	return -1;}static inline intctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct){	u_int32_t status = htonl((u_int32_t) ct->status);	NFA_PUT(skb, CTA_STATUS, sizeof(status), &status);	return 0;nfattr_failure:	return -1;}static inline intctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct){	long timeout_l = ct->timeout.expires - jiffies;	u_int32_t timeout;	if (timeout_l < 0)		timeout = 0;	else		timeout = htonl(timeout_l / HZ);		NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout);	return 0;nfattr_failure:	return -1;}static inline intctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct){	struct ip_conntrack_protocol *proto = ip_conntrack_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);	struct nfattr *nest_proto;	int ret;	if (!proto->to_nfattr) {		ip_conntrack_proto_put(proto);		return 0;	}		nest_proto = NFA_NEST(skb, CTA_PROTOINFO);	ret = proto->to_nfattr(skb, nest_proto, ct);	ip_conntrack_proto_put(proto);	NFA_NEST_END(skb, nest_proto);	return ret;nfattr_failure:	return -1;}static inline intctnetlink_dump_helpinfo(struct sk_buff *skb, const struct ip_conntrack *ct){	struct nfattr *nest_helper;	if (!ct->helper)		return 0;			nest_helper = NFA_NEST(skb, CTA_HELP);	NFA_PUT(skb, CTA_HELP_NAME, CTA_HELP_MAXNAMESIZE, &ct->helper->name);	if (ct->helper->to_nfattr)		ct->helper->to_nfattr(skb, ct);	NFA_NEST_END(skb, nest_helper);	return 0;nfattr_failure:	return -1;}#ifdef CONFIG_IP_NF_CT_ACCTstatic inline intctnetlink_dump_counters(struct sk_buff *skb, const struct ip_conntrack *ct,			enum ip_conntrack_dir dir){	enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;	struct nfattr *nest_count = NFA_NEST(skb, type);	u_int32_t tmp;	tmp = htonl(ct->counters[dir].packets);	NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp);	tmp = htonl(ct->counters[dir].bytes);	NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp);	NFA_NEST_END(skb, nest_count);	return 0;nfattr_failure:	return -1;}#else#define ctnetlink_dump_counters(a, b, c) (0)#endif#ifdef CONFIG_IP_NF_CONNTRACK_MARKstatic inline intctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct){	u_int32_t mark = htonl(ct->mark);	NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark);	return 0;nfattr_failure:	return -1;}#else#define ctnetlink_dump_mark(a, b) (0)#endifstatic inline intctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct){	u_int32_t id = htonl(ct->id);	NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id);	return 0;nfattr_failure:	return -1;}static inline intctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct){	unsigned int use = htonl(atomic_read(&ct->ct_general.use));		NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use);	return 0;nfattr_failure:	return -1;}#define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple)static intctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,		    int event, int nowait, 		    const struct ip_conntrack *ct){	struct nlmsghdr *nlh;	struct nfgenmsg *nfmsg;	struct nfattr *nest_parms;	unsigned char *b;	b = skb->tail;	event |= NFNL_SUBSYS_CTNETLINK << 8;	nlh    = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg));	nfmsg  = NLMSG_DATA(nlh);	nlh->nlmsg_flags    = (nowait && pid) ? NLM_F_MULTI : 0;	nfmsg->nfgen_family = AF_INET;	nfmsg->version      = NFNETLINK_V0;	nfmsg->res_id	    = 0;	nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG);	if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)		goto nfattr_failure;	NFA_NEST_END(skb, nest_parms);		nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY);	if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)		goto nfattr_failure;	NFA_NEST_END(skb, nest_parms);	if (ctnetlink_dump_status(skb, ct) < 0 ||	    ctnetlink_dump_timeout(skb, ct) < 0 ||	    ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||	    ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 ||	    ctnetlink_dump_protoinfo(skb, ct) < 0 ||	    ctnetlink_dump_helpinfo(skb, ct) < 0 ||	    ctnetlink_dump_mark(skb, ct) < 0 ||	    ctnetlink_dump_id(skb, ct) < 0 ||	    ctnetlink_dump_use(skb, ct) < 0)		goto nfattr_failure;	nlh->nlmsg_len = skb->tail - b;	return skb->len;nlmsg_failure:nfattr_failure:	skb_trim(skb, b - skb->data);	return -1;}#ifdef CONFIG_IP_NF_CONNTRACK_EVENTSstatic int ctnetlink_conntrack_event(struct notifier_block *this,                                     unsigned long events, void *ptr){	struct nlmsghdr *nlh;	struct nfgenmsg *nfmsg;	struct nfattr *nest_parms;	struct ip_conntrack *ct = (struct ip_conntrack *)ptr;	struct sk_buff *skb;	unsigned int type;	unsigned char *b;	unsigned int flags = 0, group;	/* ignore our fake conntrack entry */	if (ct == &ip_conntrack_untracked)		return NOTIFY_DONE;	if (events & IPCT_DESTROY) {		type = IPCTNL_MSG_CT_DELETE;		group = NFNLGRP_CONNTRACK_DESTROY;		goto alloc_skb;	}	if (events & (IPCT_NEW | IPCT_RELATED)) {		type = IPCTNL_MSG_CT_NEW;		flags = NLM_F_CREATE|NLM_F_EXCL;		/* dump everything */		events = ~0UL;		group = NFNLGRP_CONNTRACK_NEW;		goto alloc_skb;	}	if (events & (IPCT_STATUS |		      IPCT_PROTOINFO |		      IPCT_HELPER |		      IPCT_HELPINFO |		      IPCT_NATINFO)) {		type = IPCTNL_MSG_CT_NEW;		group = NFNLGRP_CONNTRACK_UPDATE;		goto alloc_skb;	} 		return NOTIFY_DONE;alloc_skb:  /* FIXME: Check if there are any listeners before, don't hurt performance */		skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);	if (!skb)		return NOTIFY_DONE;	b = skb->tail;	type |= NFNL_SUBSYS_CTNETLINK << 8;	nlh   = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));	nfmsg = NLMSG_DATA(nlh);	nlh->nlmsg_flags    = flags;	nfmsg->nfgen_family = AF_INET;	nfmsg->version	= NFNETLINK_V0;	nfmsg->res_id	= 0;	nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG);	if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)		goto nfattr_failure;	NFA_NEST_END(skb, nest_parms);		nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY);	if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)		goto nfattr_failure;	NFA_NEST_END(skb, nest_parms);		/* NAT stuff is now a status flag */	if ((events & IPCT_STATUS || events & IPCT_NATINFO)	    && ctnetlink_dump_status(skb, ct) < 0)		goto nfattr_failure;	if (events & IPCT_REFRESH	    && ctnetlink_dump_timeout(skb, ct) < 0)		goto nfattr_failure;	if (events & IPCT_PROTOINFO	    && ctnetlink_dump_protoinfo(skb, ct) < 0)		goto nfattr_failure;	if (events & IPCT_HELPINFO	    && ctnetlink_dump_helpinfo(skb, ct) < 0)		goto nfattr_failure;	if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||	    ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)		goto nfattr_failure;	nlh->nlmsg_len = skb->tail - b;	nfnetlink_send(skb, 0, group, 0);	return NOTIFY_DONE;nlmsg_failure:nfattr_failure:	kfree_skb(skb);	return NOTIFY_DONE;}#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */static int ctnetlink_done(struct netlink_callback *cb){	DEBUGP("entered %s\n", __FUNCTION__);	return 0;}static intctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb){	struct ip_conntrack *ct = NULL;	struct ip_conntrack_tuple_hash *h;	struct list_head *i;	u_int32_t *id = (u_int32_t *) &cb->args[1];	DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__, 			cb->args[0], *id);	read_lock_bh(&ip_conntrack_lock);	for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) {		list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {			h = (struct ip_conntrack_tuple_hash *) i;			if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)				continue;			ct = tuplehash_to_ctrack(h);			if (ct->id <= *id)				continue;			if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,		                        	cb->nlh->nlmsg_seq,						IPCTNL_MSG_CT_NEW,						1, ct) < 0)				goto out;			*id = ct->id;		}	}out:		read_unlock_bh(&ip_conntrack_lock);	DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);	return skb->len;}#ifdef CONFIG_IP_NF_CT_ACCTstatic intctnetlink_dump_table_w(struct sk_buff *skb, struct netlink_callback *cb){	struct ip_conntrack *ct = NULL;	struct ip_conntrack_tuple_hash *h;	struct list_head *i;	u_int32_t *id = (u_int32_t *) &cb->args[1];	DEBUGP("entered %s, last bucket=%u id=%u\n", __FUNCTION__, 			cb->args[0], *id);	write_lock_bh(&ip_conntrack_lock);	for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) {		list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) {			h = (struct ip_conntrack_tuple_hash *) i;			if (DIRECTION(h) != IP_CT_DIR_ORIGINAL)				continue;			ct = tuplehash_to_ctrack(h);			if (ct->id <= *id)				continue;			if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,		                        	cb->nlh->nlmsg_seq,						IPCTNL_MSG_CT_NEW,						1, ct) < 0)				goto out;			*id = ct->id;			memset(&ct->counters, 0, sizeof(ct->counters));		}	}out:		write_unlock_bh(&ip_conntrack_lock);	DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);	return skb->len;}#endifstatic const size_t cta_min_ip[CTA_IP_MAX] = {	[CTA_IP_V4_SRC-1]	= sizeof(u_int32_t),	[CTA_IP_V4_DST-1]	= sizeof(u_int32_t),};static inline intctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple){	struct nfattr *tb[CTA_IP_MAX];	DEBUGP("entered %s\n", __FUNCTION__);	nfattr_parse_nested(tb, CTA_IP_MAX, attr);	if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))		return -EINVAL;	if (!tb[CTA_IP_V4_SRC-1])		return -EINVAL;	tuple->src.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);	if (!tb[CTA_IP_V4_DST-1])		return -EINVAL;	tuple->dst.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);	DEBUGP("leaving\n");	return 0;}static const size_t cta_min_proto[CTA_PROTO_MAX] = {	[CTA_PROTO_NUM-1]	= sizeof(u_int8_t),	[CTA_PROTO_SRC_PORT-1]	= sizeof(u_int16_t),	[CTA_PROTO_DST_PORT-1]	= sizeof(u_int16_t),	[CTA_PROTO_ICMP_TYPE-1]	= sizeof(u_int8_t),	[CTA_PROTO_ICMP_CODE-1]	= sizeof(u_int8_t),	[CTA_PROTO_ICMP_ID-1]	= sizeof(u_int16_t),};static inline intctnetlink_parse_tuple_proto(struct nfattr *attr, 			    struct ip_conntrack_tuple *tuple){	struct nfattr *tb[CTA_PROTO_MAX];	struct ip_conntrack_protocol *proto;	int ret = 0;	DEBUGP("entered %s\n", __FUNCTION__);	nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);	if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))		return -EINVAL;	if (!tb[CTA_PROTO_NUM-1])		return -EINVAL;	tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]);	proto = ip_conntrack_proto_find_get(tuple->dst.protonum);	if (likely(proto->nfattr_to_tuple))		ret = proto->nfattr_to_tuple(tb, tuple);		ip_conntrack_proto_put(proto);		return ret;}static inline intctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple,		      enum ctattr_tuple type){	struct nfattr *tb[CTA_TUPLE_MAX];

⌨️ 快捷键说明

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