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

📄 nf_conntrack_netlink.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	nest_parms = nla_nest_start(skb, type | NLA_F_NESTED);	if (!nest_parms)		goto nla_put_failure;	if (ctnetlink_dump_tuples(skb, tuple) < 0)		goto nla_put_failure;	nla_nest_end(skb, nest_parms);	return 0;nla_put_failure:	return -1;}static inline intctnetlink_exp_dump_mask(struct sk_buff *skb,			const struct nf_conntrack_tuple *tuple,			const struct nf_conntrack_tuple_mask *mask){	int ret;	struct nf_conntrack_l3proto *l3proto;	struct nf_conntrack_l4proto *l4proto;	struct nf_conntrack_tuple m;	struct nlattr *nest_parms;	memset(&m, 0xFF, sizeof(m));	m.src.u.all = mask->src.u.all;	memcpy(&m.src.u3, &mask->src.u3, sizeof(m.src.u3));	nest_parms = nla_nest_start(skb, CTA_EXPECT_MASK | NLA_F_NESTED);	if (!nest_parms)		goto nla_put_failure;	l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);	ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto);	nf_ct_l3proto_put(l3proto);	if (unlikely(ret < 0))		goto nla_put_failure;	l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum);	ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto);	nf_ct_l4proto_put(l4proto);	if (unlikely(ret < 0))		goto nla_put_failure;	nla_nest_end(skb, nest_parms);	return 0;nla_put_failure:	return -1;}static inline intctnetlink_exp_dump_expect(struct sk_buff *skb,			  const struct nf_conntrack_expect *exp){	struct nf_conn *master = exp->master;	__be32 timeout = htonl((exp->timeout.expires - jiffies) / HZ);	__be32 id = htonl((unsigned long)exp);	if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)		goto nla_put_failure;	if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0)		goto nla_put_failure;	if (ctnetlink_exp_dump_tuple(skb,				 &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,				 CTA_EXPECT_MASTER) < 0)		goto nla_put_failure;	NLA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout);	NLA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id);	return 0;nla_put_failure:	return -1;}static intctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq,		    int event,		    int nowait,		    const struct nf_conntrack_expect *exp){	struct nlmsghdr *nlh;	struct nfgenmsg *nfmsg;	unsigned char *b = skb_tail_pointer(skb);	event |= NFNL_SUBSYS_CTNETLINK_EXP << 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 = exp->tuple.src.l3num;	nfmsg->version	    = NFNETLINK_V0;	nfmsg->res_id	    = 0;	if (ctnetlink_exp_dump_expect(skb, exp) < 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_expect_event(struct notifier_block *this,				  unsigned long events, void *ptr){	struct nlmsghdr *nlh;	struct nfgenmsg *nfmsg;	struct nf_conntrack_expect *exp = (struct nf_conntrack_expect *)ptr;	struct sk_buff *skb;	unsigned int type;	sk_buff_data_t b;	int flags = 0;	if (events & IPEXP_NEW) {		type = IPCTNL_MSG_EXP_NEW;		flags = NLM_F_CREATE|NLM_F_EXCL;	} else		return NOTIFY_DONE;	if (!nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW))		return NOTIFY_DONE;	skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);	if (!skb)		return NOTIFY_DONE;	b = skb->tail;	type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;	nlh   = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));	nfmsg = NLMSG_DATA(nlh);	nlh->nlmsg_flags    = flags;	nfmsg->nfgen_family = exp->tuple.src.l3num;	nfmsg->version	    = NFNETLINK_V0;	nfmsg->res_id	    = 0;	if (ctnetlink_exp_dump_expect(skb, exp) < 0)		goto nla_put_failure;	nlh->nlmsg_len = skb->tail - b;	nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0);	return NOTIFY_DONE;nlmsg_failure:nla_put_failure:	kfree_skb(skb);	return NOTIFY_DONE;}#endifstatic int ctnetlink_exp_done(struct netlink_callback *cb){	if (cb->args[1])		nf_ct_expect_put((struct nf_conntrack_expect *)cb->args[1]);	return 0;}static intctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb){	struct nf_conntrack_expect *exp, *last;	struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);	struct hlist_node *n;	u_int8_t l3proto = nfmsg->nfgen_family;	read_lock_bh(&nf_conntrack_lock);	last = (struct nf_conntrack_expect *)cb->args[1];	for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {restart:		hlist_for_each_entry(exp, n, &nf_ct_expect_hash[cb->args[0]],				     hnode) {			if (l3proto && exp->tuple.src.l3num != l3proto)				continue;			if (cb->args[1]) {				if (exp != last)					continue;				cb->args[1] = 0;			}			if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid,						    cb->nlh->nlmsg_seq,						    IPCTNL_MSG_EXP_NEW,						    1, exp) < 0) {				atomic_inc(&exp->use);				cb->args[1] = (unsigned long)exp;				goto out;			}		}		if (cb->args[1]) {			cb->args[1] = 0;			goto restart;		}	}out:	read_unlock_bh(&nf_conntrack_lock);	if (last)		nf_ct_expect_put(last);	return skb->len;}static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {	[CTA_EXPECT_TIMEOUT]	= { .type = NLA_U32 },	[CTA_EXPECT_ID]		= { .type = NLA_U32 },};static intctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,		     struct nlmsghdr *nlh, struct nlattr *cda[]){	struct nf_conntrack_tuple tuple;	struct nf_conntrack_expect *exp;	struct sk_buff *skb2;	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);	u_int8_t u3 = nfmsg->nfgen_family;	int err = 0;	if (nlh->nlmsg_flags & NLM_F_DUMP) {		return netlink_dump_start(ctnl, skb, nlh,					  ctnetlink_exp_dump_table,					  ctnetlink_exp_done);	}	if (cda[CTA_EXPECT_MASTER])		err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3);	else		return -EINVAL;	if (err < 0)		return err;	exp = nf_ct_expect_find_get(&tuple);	if (!exp)		return -ENOENT;	if (cda[CTA_EXPECT_ID]) {		__be32 id = *(__be32 *)nla_data(cda[CTA_EXPECT_ID]);		if (ntohl(id) != (u32)(unsigned long)exp) {			nf_ct_expect_put(exp);			return -ENOENT;		}	}	err = -ENOMEM;	skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);	if (!skb2)		goto out;	err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid,				      nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,				      1, exp);	if (err <= 0)		goto free;	nf_ct_expect_put(exp);	return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);free:	kfree_skb(skb2);out:	nf_ct_expect_put(exp);	return err;}static intctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,		     struct nlmsghdr *nlh, struct nlattr *cda[]){	struct nf_conntrack_expect *exp;	struct nf_conntrack_tuple tuple;	struct nf_conntrack_helper *h;	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);	struct hlist_node *n, *next;	u_int8_t u3 = nfmsg->nfgen_family;	unsigned int i;	int err;	if (cda[CTA_EXPECT_TUPLE]) {		/* delete a single expect by tuple */		err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);		if (err < 0)			return err;		/* bump usage count to 2 */		exp = nf_ct_expect_find_get(&tuple);		if (!exp)			return -ENOENT;		if (cda[CTA_EXPECT_ID]) {			__be32 id = *(__be32 *)nla_data(cda[CTA_EXPECT_ID]);			if (ntohl(id) != (u32)(unsigned long)exp) {				nf_ct_expect_put(exp);				return -ENOENT;			}		}		/* after list removal, usage count == 1 */		nf_ct_unexpect_related(exp);		/* have to put what we 'get' above.		 * after this line usage count == 0 */		nf_ct_expect_put(exp);	} else if (cda[CTA_EXPECT_HELP_NAME]) {		char *name = nla_data(cda[CTA_EXPECT_HELP_NAME]);		struct nf_conn_help *m_help;		/* delete all expectations for this helper */		write_lock_bh(&nf_conntrack_lock);		h = __nf_conntrack_helper_find_byname(name);		if (!h) {			write_unlock_bh(&nf_conntrack_lock);			return -EINVAL;		}		for (i = 0; i < nf_ct_expect_hsize; i++) {			hlist_for_each_entry_safe(exp, n, next,						  &nf_ct_expect_hash[i],						  hnode) {				m_help = nfct_help(exp->master);				if (m_help->helper == h				    && del_timer(&exp->timeout)) {					nf_ct_unlink_expect(exp);					nf_ct_expect_put(exp);				}			}		}		write_unlock_bh(&nf_conntrack_lock);	} else {		/* This basically means we have to flush everything*/		write_lock_bh(&nf_conntrack_lock);		for (i = 0; i < nf_ct_expect_hsize; i++) {			hlist_for_each_entry_safe(exp, n, next,						  &nf_ct_expect_hash[i],						  hnode) {				if (del_timer(&exp->timeout)) {					nf_ct_unlink_expect(exp);					nf_ct_expect_put(exp);				}			}		}		write_unlock_bh(&nf_conntrack_lock);	}	return 0;}static intctnetlink_change_expect(struct nf_conntrack_expect *x, struct nlattr *cda[]){	return -EOPNOTSUPP;}static intctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3){	struct nf_conntrack_tuple tuple, mask, master_tuple;	struct nf_conntrack_tuple_hash *h = NULL;	struct nf_conntrack_expect *exp;	struct nf_conn *ct;	struct nf_conn_help *help;	int err = 0;	/* caller guarantees that those three CTA_EXPECT_* exist */	err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);	if (err < 0)		return err;	err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK, u3);	if (err < 0)		return err;	err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER, u3);	if (err < 0)		return err;	/* Look for master conntrack of this expectation */	h = nf_conntrack_find_get(&master_tuple);	if (!h)		return -ENOENT;	ct = nf_ct_tuplehash_to_ctrack(h);	help = nfct_help(ct);	if (!help || !help->helper) {		/* such conntrack hasn't got any helper, abort */		err = -EINVAL;		goto out;	}	exp = nf_ct_expect_alloc(ct);	if (!exp) {		err = -ENOMEM;		goto out;	}	exp->expectfn = NULL;	exp->flags = 0;	exp->master = ct;	exp->helper = NULL;	memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple));	memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3));	exp->mask.src.u.all = mask.src.u.all;	err = nf_ct_expect_related(exp);	nf_ct_expect_put(exp);out:	nf_ct_put(nf_ct_tuplehash_to_ctrack(h));	return err;}static intctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,		     struct nlmsghdr *nlh, struct nlattr *cda[]){	struct nf_conntrack_tuple tuple;	struct nf_conntrack_expect *exp;	struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);	u_int8_t u3 = nfmsg->nfgen_family;	int err = 0;	if (!cda[CTA_EXPECT_TUPLE]	    || !cda[CTA_EXPECT_MASK]	    || !cda[CTA_EXPECT_MASTER])		return -EINVAL;	err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);	if (err < 0)		return err;	write_lock_bh(&nf_conntrack_lock);	exp = __nf_ct_expect_find(&tuple);	if (!exp) {		write_unlock_bh(&nf_conntrack_lock);		err = -ENOENT;		if (nlh->nlmsg_flags & NLM_F_CREATE)			err = ctnetlink_create_expect(cda, u3);		return err;	}	err = -EEXIST;	if (!(nlh->nlmsg_flags & NLM_F_EXCL))		err = ctnetlink_change_expect(exp, cda);	write_unlock_bh(&nf_conntrack_lock);	return err;}#ifdef CONFIG_NF_CONNTRACK_EVENTSstatic struct notifier_block ctnl_notifier = {	.notifier_call	= ctnetlink_conntrack_event,};static struct notifier_block ctnl_notifier_exp = {	.notifier_call	= ctnetlink_expect_event,};#endifstatic const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {	[IPCTNL_MSG_CT_NEW]		= { .call = ctnetlink_new_conntrack,					    .attr_count = CTA_MAX,					    .policy = ct_nla_policy },	[IPCTNL_MSG_CT_GET] 		= { .call = ctnetlink_get_conntrack,					    .attr_count = CTA_MAX,					    .policy = ct_nla_policy },	[IPCTNL_MSG_CT_DELETE]  	= { .call = ctnetlink_del_conntrack,					    .attr_count = CTA_MAX,					    .policy = ct_nla_policy },	[IPCTNL_MSG_CT_GET_CTRZERO] 	= { .call = ctnetlink_get_conntrack,					    .attr_count = CTA_MAX,					    .policy = ct_nla_policy },};static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {	[IPCTNL_MSG_EXP_GET]		= { .call = ctnetlink_get_expect,					    .attr_count = CTA_EXPECT_MAX,					    .policy = exp_nla_policy },	[IPCTNL_MSG_EXP_NEW]		= { .call = ctnetlink_new_expect,					    .attr_count = CTA_EXPECT_MAX,					    .policy = exp_nla_policy },	[IPCTNL_MSG_EXP_DELETE]		= { .call = ctnetlink_del_expect,					    .attr_count = CTA_EXPECT_MAX,					    .policy = exp_nla_policy },};static const struct nfnetlink_subsystem ctnl_subsys = {	.name				= "conntrack",	.subsys_id			= NFNL_SUBSYS_CTNETLINK,	.cb_count			= IPCTNL_MSG_MAX,	.cb				= ctnl_cb,};static const struct nfnetlink_subsystem ctnl_exp_subsys = {	.name				= "conntrack_expect",	.subsys_id			= NFNL_SUBSYS_CTNETLINK_EXP,	.cb_count			= IPCTNL_MSG_EXP_MAX,	.cb				= ctnl_exp_cb,};MODULE_ALIAS("ip_conntrack_netlink");MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP);static int __init ctnetlink_init(void){	int ret;	printk("ctnetlink v%s: registering with nfnetlink.\n", version);	ret = nfnetlink_subsys_register(&ctnl_subsys);	if (ret < 0) {		printk("ctnetlink_init: cannot register with nfnetlink.\n");		goto err_out;	}	ret = nfnetlink_subsys_register(&ctnl_exp_subsys);	if (ret < 0) {		printk("ctnetlink_init: cannot register exp with nfnetlink.\n");		goto err_unreg_subsys;	}#ifdef CONFIG_NF_CONNTRACK_EVENTS	ret = nf_conntrack_register_notifier(&ctnl_notifier);	if (ret < 0) {		printk("ctnetlink_init: cannot register notifier.\n");		goto err_unreg_exp_subsys;	}	ret = nf_ct_expect_register_notifier(&ctnl_notifier_exp);	if (ret < 0) {		printk("ctnetlink_init: cannot expect register notifier.\n");		goto err_unreg_notifier;	}#endif	return 0;#ifdef CONFIG_NF_CONNTRACK_EVENTSerr_unreg_notifier:	nf_conntrack_unregister_notifier(&ctnl_notifier);err_unreg_exp_subsys:	nfnetlink_subsys_unregister(&ctnl_exp_subsys);#endiferr_unreg_subsys:	nfnetlink_subsys_unregister(&ctnl_subsys);err_out:	return ret;}static void __exit ctnetlink_exit(void){	printk("ctnetlink: unregistering from nfnetlink.\n");#ifdef CONFIG_NF_CONNTRACK_EVENTS	nf_ct_expect_unregister_notifier(&ctnl_notifier_exp);	nf_conntrack_unregister_notifier(&ctnl_notifier);#endif	nfnetlink_subsys_unregister(&ctnl_exp_subsys);	nfnetlink_subsys_unregister(&ctnl_subsys);	return;}module_init(ctnetlink_init);module_exit(ctnetlink_exit);

⌨️ 快捷键说明

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