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

📄 nf_conntrack_netlink.c

📁 linux 内核源代码
💻 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-2006 by Harald Welte <laforge@gnumonks.org> * (C) 2003 by Patrick Mchardy <kaber@trash.net> * (C) 2005-2007 by Pablo Neira Ayuso <pablo@netfilter.org> * * 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 <net/netlink.h>#include <net/netfilter/nf_conntrack.h>#include <net/netfilter/nf_conntrack_core.h>#include <net/netfilter/nf_conntrack_expect.h>#include <net/netfilter/nf_conntrack_helper.h>#include <net/netfilter/nf_conntrack_l3proto.h>#include <net/netfilter/nf_conntrack_l4proto.h>#include <net/netfilter/nf_conntrack_tuple.h>#ifdef CONFIG_NF_NAT_NEEDED#include <net/netfilter/nf_nat_core.h>#include <net/netfilter/nf_nat_protocol.h>#endif#include <linux/netfilter/nfnetlink.h>#include <linux/netfilter/nfnetlink_conntrack.h>MODULE_LICENSE("GPL");static char __initdata version[] = "0.93";static inline intctnetlink_dump_tuples_proto(struct sk_buff *skb,			    const struct nf_conntrack_tuple *tuple,			    struct nf_conntrack_l4proto *l4proto){	int ret = 0;	struct nlattr *nest_parms;	nest_parms = nla_nest_start(skb, CTA_TUPLE_PROTO | NLA_F_NESTED);	if (!nest_parms)		goto nla_put_failure;	NLA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);	if (likely(l4proto->tuple_to_nlattr))		ret = l4proto->tuple_to_nlattr(skb, tuple);	nla_nest_end(skb, nest_parms);	return ret;nla_put_failure:	return -1;}static inline intctnetlink_dump_tuples_ip(struct sk_buff *skb,			 const struct nf_conntrack_tuple *tuple,			 struct nf_conntrack_l3proto *l3proto){	int ret = 0;	struct nlattr *nest_parms;	nest_parms = nla_nest_start(skb, CTA_TUPLE_IP | NLA_F_NESTED);	if (!nest_parms)		goto nla_put_failure;	if (likely(l3proto->tuple_to_nlattr))		ret = l3proto->tuple_to_nlattr(skb, tuple);	nla_nest_end(skb, nest_parms);	return ret;nla_put_failure:	return -1;}static inline intctnetlink_dump_tuples(struct sk_buff *skb,		      const struct nf_conntrack_tuple *tuple){	int ret;	struct nf_conntrack_l3proto *l3proto;	struct nf_conntrack_l4proto *l4proto;	l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);	ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto);	nf_ct_l3proto_put(l3proto);	if (unlikely(ret < 0))		return ret;	l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum);	ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto);	nf_ct_l4proto_put(l4proto);	return ret;}static inline intctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct){	__be32 status = htonl((u_int32_t) ct->status);	NLA_PUT(skb, CTA_STATUS, sizeof(status), &status);	return 0;nla_put_failure:	return -1;}static inline intctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct){	long timeout_l = ct->timeout.expires - jiffies;	__be32 timeout;	if (timeout_l < 0)		timeout = 0;	else		timeout = htonl(timeout_l / HZ);	NLA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout);	return 0;nla_put_failure:	return -1;}static inline intctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct){	struct nf_conntrack_l4proto *l4proto = nf_ct_l4proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);	struct nlattr *nest_proto;	int ret;	if (!l4proto->to_nlattr) {		nf_ct_l4proto_put(l4proto);		return 0;	}	nest_proto = nla_nest_start(skb, CTA_PROTOINFO | NLA_F_NESTED);	if (!nest_proto)		goto nla_put_failure;	ret = l4proto->to_nlattr(skb, nest_proto, ct);	nf_ct_l4proto_put(l4proto);	nla_nest_end(skb, nest_proto);	return ret;nla_put_failure:	nf_ct_l4proto_put(l4proto);	return -1;}static inline intctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct){	struct nlattr *nest_helper;	const struct nf_conn_help *help = nfct_help(ct);	struct nf_conntrack_helper *helper;	if (!help)		return 0;	rcu_read_lock();	helper = rcu_dereference(help->helper);	if (!helper)		goto out;	nest_helper = nla_nest_start(skb, CTA_HELP | NLA_F_NESTED);	if (!nest_helper)		goto nla_put_failure;	NLA_PUT(skb, CTA_HELP_NAME, strlen(helper->name), helper->name);	if (helper->to_nlattr)		helper->to_nlattr(skb, ct);	nla_nest_end(skb, nest_helper);out:	rcu_read_unlock();	return 0;nla_put_failure:	rcu_read_unlock();	return -1;}#ifdef CONFIG_NF_CT_ACCTstatic inline intctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct,			enum ip_conntrack_dir dir){	enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;	struct nlattr *nest_count;	__be32 tmp;	nest_count = nla_nest_start(skb, type | NLA_F_NESTED);	if (!nest_count)		goto nla_put_failure;	tmp = htonl(ct->counters[dir].packets);	NLA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp);	tmp = htonl(ct->counters[dir].bytes);	NLA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp);	nla_nest_end(skb, nest_count);	return 0;nla_put_failure:	return -1;}#else#define ctnetlink_dump_counters(a, b, c) (0)#endif#ifdef CONFIG_NF_CONNTRACK_MARKstatic inline intctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct){	__be32 mark = htonl(ct->mark);	NLA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark);	return 0;nla_put_failure:	return -1;}#else#define ctnetlink_dump_mark(a, b) (0)#endifstatic inline intctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct){	__be32 id = htonl((unsigned long)ct);	NLA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id);	return 0;nla_put_failure:	return -1;}static inline intctnetlink_dump_use(struct sk_buff *skb, const struct nf_conn *ct){	__be32 use = htonl(atomic_read(&ct->ct_general.use));	NLA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use);	return 0;nla_put_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 nf_conn *ct){	struct nlmsghdr *nlh;	struct nfgenmsg *nfmsg;	struct nlattr *nest_parms;	unsigned char *b = skb_tail_pointer(skb);	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 =		ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;	nfmsg->version      = NFNETLINK_V0;	nfmsg->res_id	    = 0;	nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);	if (!nest_parms)		goto nla_put_failure;	if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)		goto nla_put_failure;	nla_nest_end(skb, nest_parms);	nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED);	if (!nest_parms)		goto nla_put_failure;	if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)		goto nla_put_failure;	nla_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 nla_put_failure;	nlh->nlmsg_len = skb_tail_pointer(skb) - b;	return skb->len;nlmsg_failure:nla_put_failure:	nlmsg_trim(skb, b);	return -1;}#ifdef CONFIG_NF_CONNTRACK_EVENTSstatic int ctnetlink_conntrack_event(struct notifier_block *this,				     unsigned long events, void *ptr){	struct nlmsghdr *nlh;	struct nfgenmsg *nfmsg;	struct nlattr *nest_parms;	struct nf_conn *ct = (struct nf_conn *)ptr;	struct sk_buff *skb;	unsigned int type;	sk_buff_data_t b;	unsigned int flags = 0, group;	/* ignore our fake conntrack entry */	if (ct == &nf_conntrack_untracked)		return NOTIFY_DONE;	if (events & IPCT_DESTROY) {		type = IPCTNL_MSG_CT_DELETE;		group = NFNLGRP_CONNTRACK_DESTROY;	} else  if (events & (IPCT_NEW | IPCT_RELATED)) {		type = IPCTNL_MSG_CT_NEW;		flags = NLM_F_CREATE|NLM_F_EXCL;		group = NFNLGRP_CONNTRACK_NEW;	} else  if (events & (IPCT_STATUS | IPCT_PROTOINFO)) {		type = IPCTNL_MSG_CT_NEW;		group = NFNLGRP_CONNTRACK_UPDATE;	} else		return NOTIFY_DONE;	if (!nfnetlink_has_listeners(group))		return NOTIFY_DONE;	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 = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;	nfmsg->version	= NFNETLINK_V0;	nfmsg->res_id	= 0;	nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);	if (!nest_parms)		goto nla_put_failure;	if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0)		goto nla_put_failure;	nla_nest_end(skb, nest_parms);	nest_parms = nla_nest_start(skb, CTA_TUPLE_REPLY | NLA_F_NESTED);	if (!nest_parms)		goto nla_put_failure;	if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)		goto nla_put_failure;	nla_nest_end(skb, nest_parms);	if (events & IPCT_DESTROY) {		if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||		    ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)			goto nla_put_failure;	} else {		if (ctnetlink_dump_status(skb, ct) < 0)			goto nla_put_failure;		if (ctnetlink_dump_timeout(skb, ct) < 0)			goto nla_put_failure;		if (events & IPCT_PROTOINFO		    && ctnetlink_dump_protoinfo(skb, ct) < 0)			goto nla_put_failure;		if ((events & IPCT_HELPER || nfct_help(ct))		    && ctnetlink_dump_helpinfo(skb, ct) < 0)			goto nla_put_failure;#ifdef CONFIG_NF_CONNTRACK_MARK		if ((events & IPCT_MARK || ct->mark)		    && ctnetlink_dump_mark(skb, ct) < 0)			goto nla_put_failure;#endif		if (events & IPCT_COUNTER_FILLING &&		    (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||		     ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0))			goto nla_put_failure;	}	nlh->nlmsg_len = skb->tail - b;	nfnetlink_send(skb, 0, group, 0);	return NOTIFY_DONE;nlmsg_failure:nla_put_failure:	kfree_skb(skb);	return NOTIFY_DONE;}#endif /* CONFIG_NF_CONNTRACK_EVENTS */static int ctnetlink_done(struct netlink_callback *cb){	if (cb->args[1])		nf_ct_put((struct nf_conn *)cb->args[1]);	return 0;}#define L3PROTO(ct) ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3numstatic intctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb){	struct nf_conn *ct, *last;	struct nf_conntrack_tuple_hash *h;	struct hlist_node *n;	struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);	u_int8_t l3proto = nfmsg->nfgen_family;	read_lock_bh(&nf_conntrack_lock);	last = (struct nf_conn *)cb->args[1];	for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) {restart:		hlist_for_each_entry(h, n, &nf_conntrack_hash[cb->args[0]],				     hnode) {			if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)				continue;			ct = nf_ct_tuplehash_to_ctrack(h);			/* Dump entries of a given L3 protocol number.			 * If it is not specified, ie. l3proto == 0,			 * then dump everything. */			if (l3proto && L3PROTO(ct) != l3proto)				continue;			if (cb->args[1]) {				if (ct != last)					continue;				cb->args[1] = 0;			}			if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,						cb->nlh->nlmsg_seq,						IPCTNL_MSG_CT_NEW,						1, ct) < 0) {				nf_conntrack_get(&ct->ct_general);				cb->args[1] = (unsigned long)ct;				goto out;			}#ifdef CONFIG_NF_CT_ACCT			if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) ==						IPCTNL_MSG_CT_GET_CTRZERO)				memset(&ct->counters, 0, sizeof(ct->counters));#endif		}		if (cb->args[1]) {			cb->args[1] = 0;			goto restart;		}	}out:	read_unlock_bh(&nf_conntrack_lock);	if (last)		nf_ct_put(last);	return skb->len;}static inline intctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple){	struct nlattr *tb[CTA_IP_MAX+1];	struct nf_conntrack_l3proto *l3proto;	int ret = 0;	nla_parse_nested(tb, CTA_IP_MAX, attr, NULL);	l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);	if (likely(l3proto->nlattr_to_tuple)) {		ret = nla_validate_nested(attr, CTA_IP_MAX,					  l3proto->nla_policy);		if (ret == 0)			ret = l3proto->nlattr_to_tuple(tb, tuple);	}	nf_ct_l3proto_put(l3proto);	return ret;}static const struct nla_policy proto_nla_policy[CTA_PROTO_MAX+1] = {	[CTA_PROTO_NUM]	= { .type = NLA_U8 },};static inline intctnetlink_parse_tuple_proto(struct nlattr *attr,			    struct nf_conntrack_tuple *tuple){	struct nlattr *tb[CTA_PROTO_MAX+1];	struct nf_conntrack_l4proto *l4proto;	int ret = 0;	ret = nla_parse_nested(tb, CTA_PROTO_MAX, attr, proto_nla_policy);	if (ret < 0)		return ret;	if (!tb[CTA_PROTO_NUM])		return -EINVAL;	tuple->dst.protonum = *(u_int8_t *)nla_data(tb[CTA_PROTO_NUM]);	l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum);	if (likely(l4proto->nlattr_to_tuple)) {		ret = nla_validate_nested(attr, CTA_PROTO_MAX,					  l4proto->nla_policy);		if (ret == 0)			ret = l4proto->nlattr_to_tuple(tb, tuple);	}	nf_ct_l4proto_put(l4proto);	return ret;}static inline intctnetlink_parse_tuple(struct nlattr *cda[], struct nf_conntrack_tuple *tuple,		      enum ctattr_tuple type, u_int8_t l3num){	struct nlattr *tb[CTA_TUPLE_MAX+1];	int err;	memset(tuple, 0, sizeof(*tuple));	nla_parse_nested(tb, CTA_TUPLE_MAX, cda[type], NULL);

⌨️ 快捷键说明

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