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

📄 ip_conntrack_netlink.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
		err = -ENOENT;		if (nlh->nlmsg_flags & NLM_F_CREATE)			err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);		return err;	}	/* implicit 'else' */	/* we only allow nat config for new conntracks */	if (cda[CTA_NAT-1]) {		err = -EINVAL;		goto out_unlock;	}	/* We manipulate the conntrack inside the global conntrack table lock,	 * so there's no need to increase the refcount */	DEBUGP("conntrack found\n");	err = -EEXIST;	if (!(nlh->nlmsg_flags & NLM_F_EXCL))		err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda);out_unlock:	write_unlock_bh(&ip_conntrack_lock);	return err;}/***********************************************************************  * EXPECT  ***********************************************************************/ static inline intctnetlink_exp_dump_tuple(struct sk_buff *skb,			 const struct ip_conntrack_tuple *tuple,			 enum ctattr_expect type){	struct nfattr *nest_parms = NFA_NEST(skb, type);		if (ctnetlink_dump_tuples(skb, tuple) < 0)		goto nfattr_failure;	NFA_NEST_END(skb, nest_parms);	return 0;nfattr_failure:	return -1;}			static inline intctnetlink_exp_dump_expect(struct sk_buff *skb,                          const struct ip_conntrack_expect *exp){	struct ip_conntrack *master = exp->master;	u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ);	u_int32_t id = htonl(exp->id);	if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)		goto nfattr_failure;	if (ctnetlink_exp_dump_tuple(skb, &exp->mask, CTA_EXPECT_MASK) < 0)		goto nfattr_failure;	if (ctnetlink_exp_dump_tuple(skb,				 &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,				 CTA_EXPECT_MASTER) < 0)		goto nfattr_failure;		NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout);	NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id);	return 0;	nfattr_failure:	return -1;}static intctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq,		    int event, 		    int nowait, 		    const struct ip_conntrack_expect *exp){	struct nlmsghdr *nlh;	struct nfgenmsg *nfmsg;	unsigned char *b;	b = skb->tail;	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 = AF_INET;	nfmsg->version	    = NFNETLINK_V0;	nfmsg->res_id	    = 0;	if (ctnetlink_exp_dump_expect(skb, exp) < 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_expect_event(struct notifier_block *this,				  unsigned long events, void *ptr){	struct nlmsghdr *nlh;	struct nfgenmsg *nfmsg;	struct ip_conntrack_expect *exp = (struct ip_conntrack_expect *)ptr;	struct sk_buff *skb;	unsigned int type;	unsigned char *b;	int flags = 0;	u16 proto;	if (events & IPEXP_NEW) {		type = IPCTNL_MSG_EXP_NEW;		flags = NLM_F_CREATE|NLM_F_EXCL;	} else		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 = AF_INET;	nfmsg->version	    = NFNETLINK_V0;	nfmsg->res_id	    = 0;	if (ctnetlink_exp_dump_expect(skb, exp) < 0)		goto nfattr_failure;	nlh->nlmsg_len = skb->tail - b;	proto = exp->tuple.dst.protonum;	nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0);	return NOTIFY_DONE;nlmsg_failure:nfattr_failure:	kfree_skb(skb);	return NOTIFY_DONE;}#endifstatic intctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb){	struct ip_conntrack_expect *exp = NULL;	struct list_head *i;	u_int32_t *id = (u_int32_t *) &cb->args[0];	DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);	read_lock_bh(&ip_conntrack_lock);	list_for_each_prev(i, &ip_conntrack_expect_list) {		exp = (struct ip_conntrack_expect *) i;		if (exp->id <= *id)			continue;		if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid,					    cb->nlh->nlmsg_seq,					    IPCTNL_MSG_EXP_NEW,					    1, exp) < 0)			goto out;		*id = exp->id;	}out:		read_unlock_bh(&ip_conntrack_lock);	DEBUGP("leaving, last id=%llu\n", *id);	return skb->len;}static const size_t cta_min_exp[CTA_EXPECT_MAX] = {	[CTA_EXPECT_TIMEOUT-1]          = sizeof(u_int32_t),	[CTA_EXPECT_ID-1]               = sizeof(u_int32_t)};static intctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, 		     struct nlmsghdr *nlh, struct nfattr *cda[], int *errp){	struct ip_conntrack_tuple tuple;	struct ip_conntrack_expect *exp;	struct sk_buff *skb2;	int err = 0;	DEBUGP("entered %s\n", __FUNCTION__);	if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))		return -EINVAL;	if (nlh->nlmsg_flags & NLM_F_DUMP) {		struct nfgenmsg *msg = NLMSG_DATA(nlh);		u32 rlen;		if (msg->nfgen_family != AF_INET)			return -EAFNOSUPPORT;		if ((*errp = netlink_dump_start(ctnl, skb, nlh,		    				ctnetlink_exp_dump_table,						ctnetlink_done)) != 0)			return -EINVAL;		rlen = NLMSG_ALIGN(nlh->nlmsg_len);		if (rlen > skb->len)			rlen = skb->len;		skb_pull(skb, rlen);		return 0;	}	if (cda[CTA_EXPECT_MASTER-1])		err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER);	else		return -EINVAL;	if (err < 0)		return err;	exp = ip_conntrack_expect_find(&tuple);	if (!exp)		return -ENOENT;	if (cda[CTA_EXPECT_ID-1]) {		u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);		if (exp->id != ntohl(id)) {			ip_conntrack_expect_put(exp);			return -ENOENT;		}	}		err = -ENOMEM;	skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);	if (!skb2)		goto out;	NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;		err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, 				      nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,				      1, exp);	if (err <= 0)		goto free;	ip_conntrack_expect_put(exp);	return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);free:	kfree_skb(skb2);out:	ip_conntrack_expect_put(exp);	return err;}static intctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, 		     struct nlmsghdr *nlh, struct nfattr *cda[], int *errp){	struct ip_conntrack_expect *exp, *tmp;	struct ip_conntrack_tuple tuple;	struct ip_conntrack_helper *h;	int err;	if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))		return -EINVAL;	if (cda[CTA_EXPECT_TUPLE-1]) {		/* delete a single expect by tuple */		err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);		if (err < 0)			return err;		/* bump usage count to 2 */		exp = ip_conntrack_expect_find(&tuple);		if (!exp)			return -ENOENT;		if (cda[CTA_EXPECT_ID-1]) {			u_int32_t id = 				*(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);			if (exp->id != ntohl(id)) {				ip_conntrack_expect_put(exp);				return -ENOENT;			}		}		/* after list removal, usage count == 1 */		ip_conntrack_unexpect_related(exp);		/* have to put what we 'get' above. 		 * after this line usage count == 0 */		ip_conntrack_expect_put(exp);	} else if (cda[CTA_EXPECT_HELP_NAME-1]) {		char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]);		/* delete all expectations for this helper */		write_lock_bh(&ip_conntrack_lock);		h = __ip_conntrack_helper_find_byname(name);		if (!h) {			write_unlock_bh(&ip_conntrack_lock);			return -EINVAL;		}		list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,					 list) {			if (exp->master->helper == h 			    && del_timer(&exp->timeout)) {				ip_ct_unlink_expect(exp);				ip_conntrack_expect_put(exp);			}		}		write_unlock_bh(&ip_conntrack_lock);	} else {		/* This basically means we have to flush everything*/		write_lock_bh(&ip_conntrack_lock);		list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list,					 list) {			if (del_timer(&exp->timeout)) {				ip_ct_unlink_expect(exp);				ip_conntrack_expect_put(exp);			}		}		write_unlock_bh(&ip_conntrack_lock);	}	return 0;}static intctnetlink_change_expect(struct ip_conntrack_expect *x, struct nfattr *cda[]){	return -EOPNOTSUPP;}static intctnetlink_create_expect(struct nfattr *cda[]){	struct ip_conntrack_tuple tuple, mask, master_tuple;	struct ip_conntrack_tuple_hash *h = NULL;	struct ip_conntrack_expect *exp;	struct ip_conntrack *ct;	int err = 0;	DEBUGP("entered %s\n", __FUNCTION__);	/* caller guarantees that those three CTA_EXPECT_* exist */	err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);	if (err < 0)		return err;	err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK);	if (err < 0)		return err;	err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER);	if (err < 0)		return err;	/* Look for master conntrack of this expectation */	h = ip_conntrack_find_get(&master_tuple, NULL);	if (!h)		return -ENOENT;	ct = tuplehash_to_ctrack(h);	if (!ct->helper) {		/* such conntrack hasn't got any helper, abort */		err = -EINVAL;		goto out;	}	exp = ip_conntrack_expect_alloc(ct);	if (!exp) {		err = -ENOMEM;		goto out;	}		exp->expectfn = NULL;	exp->flags = 0;	exp->master = ct;	memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple));	memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple));	err = ip_conntrack_expect_related(exp);	ip_conntrack_expect_put(exp);out:		ip_conntrack_put(tuplehash_to_ctrack(h));	return err;}static intctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,		     struct nlmsghdr *nlh, struct nfattr *cda[], int *errp){	struct ip_conntrack_tuple tuple;	struct ip_conntrack_expect *exp;	int err = 0;	DEBUGP("entered %s\n", __FUNCTION__);		if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))		return -EINVAL;	if (!cda[CTA_EXPECT_TUPLE-1]	    || !cda[CTA_EXPECT_MASK-1]	    || !cda[CTA_EXPECT_MASTER-1])		return -EINVAL;	err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);	if (err < 0)		return err;	write_lock_bh(&ip_conntrack_lock);	exp = __ip_conntrack_expect_find(&tuple);	if (!exp) {		write_unlock_bh(&ip_conntrack_lock);		err = -ENOENT;		if (nlh->nlmsg_flags & NLM_F_CREATE)			err = ctnetlink_create_expect(cda);		return err;	}	err = -EEXIST;	if (!(nlh->nlmsg_flags & NLM_F_EXCL))		err = ctnetlink_change_expect(exp, cda);	write_unlock_bh(&ip_conntrack_lock);	DEBUGP("leaving\n");		return err;}#ifdef CONFIG_IP_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 struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {	[IPCTNL_MSG_CT_NEW]		= { .call = ctnetlink_new_conntrack,					    .attr_count = CTA_MAX, },	[IPCTNL_MSG_CT_GET] 		= { .call = ctnetlink_get_conntrack,					    .attr_count = CTA_MAX, },	[IPCTNL_MSG_CT_DELETE]  	= { .call = ctnetlink_del_conntrack,					    .attr_count = CTA_MAX, },	[IPCTNL_MSG_CT_GET_CTRZERO] 	= { .call = ctnetlink_get_conntrack,					    .attr_count = CTA_MAX, },};static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {	[IPCTNL_MSG_EXP_GET]		= { .call = ctnetlink_get_expect,					    .attr_count = CTA_EXPECT_MAX, },	[IPCTNL_MSG_EXP_NEW]		= { .call = ctnetlink_new_expect,					    .attr_count = CTA_EXPECT_MAX, },	[IPCTNL_MSG_EXP_DELETE]		= { .call = ctnetlink_del_expect,					    .attr_count = CTA_EXPECT_MAX, },};static struct nfnetlink_subsystem ctnl_subsys = {	.name				= "conntrack",	.subsys_id			= NFNL_SUBSYS_CTNETLINK,	.cb_count			= IPCTNL_MSG_MAX,	.cb				= ctnl_cb,};static 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_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);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_IP_NF_CONNTRACK_EVENTS	ret = ip_conntrack_register_notifier(&ctnl_notifier);	if (ret < 0) {		printk("ctnetlink_init: cannot register notifier.\n");		goto err_unreg_exp_subsys;	}	ret = ip_conntrack_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_IP_NF_CONNTRACK_EVENTSerr_unreg_notifier:	ip_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_IP_NF_CONNTRACK_EVENTS	ip_conntrack_unregister_notifier(&ctnl_notifier_exp);	ip_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 + -