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

📄 ip_conntrack_netlink.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	int err;	DEBUGP("entered %s\n", __FUNCTION__);	memset(tuple, 0, sizeof(*tuple));	nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);	if (!tb[CTA_TUPLE_IP-1])		return -EINVAL;	err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple);	if (err < 0)		return err;	if (!tb[CTA_TUPLE_PROTO-1])		return -EINVAL;	err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple);	if (err < 0)		return err;	/* orig and expect tuples get DIR_ORIGINAL */	if (type == CTA_TUPLE_REPLY)		tuple->dst.dir = IP_CT_DIR_REPLY;	else		tuple->dst.dir = IP_CT_DIR_ORIGINAL;	DUMP_TUPLE(tuple);	DEBUGP("leaving\n");	return 0;}#ifdef CONFIG_IP_NF_NAT_NEEDEDstatic const size_t cta_min_protonat[CTA_PROTONAT_MAX] = {	[CTA_PROTONAT_PORT_MIN-1]	= sizeof(u_int16_t),	[CTA_PROTONAT_PORT_MAX-1]	= sizeof(u_int16_t),};static int ctnetlink_parse_nat_proto(struct nfattr *attr,				     const struct ip_conntrack *ct,				     struct ip_nat_range *range){	struct nfattr *tb[CTA_PROTONAT_MAX];	struct ip_nat_protocol *npt;	DEBUGP("entered %s\n", __FUNCTION__);	nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);	if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))		return -EINVAL;	npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);	if (!npt->nfattr_to_range) {		ip_nat_proto_put(npt);		return 0;	}	/* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */	if (npt->nfattr_to_range(tb, range) > 0)		range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;	ip_nat_proto_put(npt);	DEBUGP("leaving\n");	return 0;}static const size_t cta_min_nat[CTA_NAT_MAX] = {	[CTA_NAT_MINIP-1]       = sizeof(u_int32_t),	[CTA_NAT_MAXIP-1]       = sizeof(u_int32_t),};static inline intctnetlink_parse_nat(struct nfattr *cda[],		    const struct ip_conntrack *ct, struct ip_nat_range *range){	struct nfattr *tb[CTA_NAT_MAX];	int err;	DEBUGP("entered %s\n", __FUNCTION__);	memset(range, 0, sizeof(*range));		nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]);	if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat))		return -EINVAL;	if (tb[CTA_NAT_MINIP-1])		range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]);	if (!tb[CTA_NAT_MAXIP-1])		range->max_ip = range->min_ip;	else		range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]);	if (range->min_ip)		range->flags |= IP_NAT_RANGE_MAP_IPS;	if (!tb[CTA_NAT_PROTO-1])		return 0;	err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range);	if (err < 0)		return err;	DEBUGP("leaving\n");	return 0;}#endifstatic inline intctnetlink_parse_help(struct nfattr *attr, char **helper_name){	struct nfattr *tb[CTA_HELP_MAX];	DEBUGP("entered %s\n", __FUNCTION__);	nfattr_parse_nested(tb, CTA_HELP_MAX, attr);	if (!tb[CTA_HELP_NAME-1])		return -EINVAL;	*helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]);	return 0;}static const size_t cta_min[CTA_MAX] = {	[CTA_STATUS-1] 		= sizeof(u_int32_t),	[CTA_TIMEOUT-1] 	= sizeof(u_int32_t),	[CTA_MARK-1]		= sizeof(u_int32_t),	[CTA_USE-1]		= sizeof(u_int32_t),	[CTA_ID-1]		= sizeof(u_int32_t)};static intctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, 			struct nlmsghdr *nlh, struct nfattr *cda[], int *errp){	struct ip_conntrack_tuple_hash *h;	struct ip_conntrack_tuple tuple;	struct ip_conntrack *ct;	int err = 0;	DEBUGP("entered %s\n", __FUNCTION__);	if (nfattr_bad_size(cda, CTA_MAX, cta_min))		return -EINVAL;	if (cda[CTA_TUPLE_ORIG-1])		err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);	else if (cda[CTA_TUPLE_REPLY-1])		err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY);	else {		/* Flush the whole table */		ip_conntrack_flush();		return 0;	}	if (err < 0)		return err;	h = ip_conntrack_find_get(&tuple, NULL);	if (!h) {		DEBUGP("tuple not found in conntrack hash\n");		return -ENOENT;	}	ct = tuplehash_to_ctrack(h);		if (cda[CTA_ID-1]) {		u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1]));		if (ct->id != id) {			ip_conntrack_put(ct);			return -ENOENT;		}	}		if (del_timer(&ct->timeout))		ct->timeout.function((unsigned long)ct);	ip_conntrack_put(ct);	DEBUGP("leaving\n");	return 0;}static intctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, 			struct nlmsghdr *nlh, struct nfattr *cda[], int *errp){	struct ip_conntrack_tuple_hash *h;	struct ip_conntrack_tuple tuple;	struct ip_conntrack *ct;	struct sk_buff *skb2 = NULL;	int err = 0;	DEBUGP("entered %s\n", __FUNCTION__);	if (nlh->nlmsg_flags & NLM_F_DUMP) {		struct nfgenmsg *msg = NLMSG_DATA(nlh);		u32 rlen;		if (msg->nfgen_family != AF_INET)			return -EAFNOSUPPORT;		if (NFNL_MSG_TYPE(nlh->nlmsg_type) ==					IPCTNL_MSG_CT_GET_CTRZERO) {#ifdef CONFIG_IP_NF_CT_ACCT			if ((*errp = netlink_dump_start(ctnl, skb, nlh,						ctnetlink_dump_table_w,						ctnetlink_done)) != 0)				return -EINVAL;#else			return -ENOTSUPP;#endif		} else {			if ((*errp = netlink_dump_start(ctnl, skb, nlh,		      		                        ctnetlink_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 (nfattr_bad_size(cda, CTA_MAX, cta_min))		return -EINVAL;	if (cda[CTA_TUPLE_ORIG-1])		err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);	else if (cda[CTA_TUPLE_REPLY-1])		err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY);	else		return -EINVAL;	if (err < 0)		return err;	h = ip_conntrack_find_get(&tuple, NULL);	if (!h) {		DEBUGP("tuple not found in conntrack hash");		return -ENOENT;	}	DEBUGP("tuple found\n");	ct = tuplehash_to_ctrack(h);	err = -ENOMEM;	skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);	if (!skb2) {		ip_conntrack_put(ct);		return -ENOMEM;	}	NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;	err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 				  IPCTNL_MSG_CT_NEW, 1, ct);	ip_conntrack_put(ct);	if (err <= 0)		goto free;	err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);	if (err < 0)		goto out;	DEBUGP("leaving\n");	return 0;free:	kfree_skb(skb2);out:	return err;}static inline intctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[]){	unsigned long d;	unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]));	d = ct->status ^ status;	if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))		/* unchangeable */		return -EINVAL;		if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY))		/* SEEN_REPLY bit can only be set */		return -EINVAL;		if (d & IPS_ASSURED && !(status & IPS_ASSURED))		/* ASSURED bit can only be set */		return -EINVAL;	if (cda[CTA_NAT-1]) {#ifndef CONFIG_IP_NF_NAT_NEEDED		return -EINVAL;#else		unsigned int hooknum;		struct ip_nat_range range;		if (ctnetlink_parse_nat(cda, ct, &range) < 0)			return -EINVAL;		DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n", 		       NIPQUAD(range.min_ip), NIPQUAD(range.max_ip),		       htons(range.min.all), htons(range.max.all));				/* This is tricky but it works. ip_nat_setup_info needs the		 * hook number as parameter, so let's do the correct 		 * conversion and run away */		if (status & IPS_SRC_NAT_DONE)			hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */		else if (status & IPS_DST_NAT_DONE)			hooknum = NF_IP_PRE_ROUTING;  /* IP_NAT_MANIP_DST */		else 			return -EINVAL; /* Missing NAT flags */		DEBUGP("NAT status: %lu\n", 		       status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));				if (ip_nat_initialized(ct, HOOK2MANIP(hooknum)))			return -EEXIST;		ip_nat_setup_info(ct, &range, hooknum);                DEBUGP("NAT status after setup_info: %lu\n",                       ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK));#endif	}	/* Be careful here, modifying NAT bits can screw up things,	 * so don't let users modify them directly if they don't pass	 * ip_nat_range. */	ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);	return 0;}static inline intctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[]){	struct ip_conntrack_helper *helper;	char *helpname;	int err;	DEBUGP("entered %s\n", __FUNCTION__);	/* don't change helper of sibling connections */	if (ct->master)		return -EINVAL;	err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname);	if (err < 0)		return err;	helper = __ip_conntrack_helper_find_byname(helpname);	if (!helper) {		if (!strcmp(helpname, ""))			helper = NULL;		else			return -EINVAL;	}	if (ct->helper) {		if (!helper) {			/* we had a helper before ... */			ip_ct_remove_expectations(ct);			ct->helper = NULL;		} else {			/* need to zero data of old helper */			memset(&ct->help, 0, sizeof(ct->help));		}	}		ct->helper = helper;	return 0;}static inline intctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[]){	u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));		if (!del_timer(&ct->timeout))		return -ETIME;	ct->timeout.expires = jiffies + timeout * HZ;	add_timer(&ct->timeout);	return 0;}static inline intctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[]){	struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1];	struct ip_conntrack_protocol *proto;	u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;	int err = 0;	nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr);	proto = ip_conntrack_proto_find_get(npt);	if (proto->from_nfattr)		err = proto->from_nfattr(tb, ct);	ip_conntrack_proto_put(proto); 	return err;}static intctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[]){	int err;	DEBUGP("entered %s\n", __FUNCTION__);	if (cda[CTA_HELP-1]) {		err = ctnetlink_change_helper(ct, cda);		if (err < 0)			return err;	}	if (cda[CTA_TIMEOUT-1]) {		err = ctnetlink_change_timeout(ct, cda);		if (err < 0)			return err;	}	if (cda[CTA_STATUS-1]) {		err = ctnetlink_change_status(ct, cda);		if (err < 0)			return err;	}	if (cda[CTA_PROTOINFO-1]) {		err = ctnetlink_change_protoinfo(ct, cda);		if (err < 0)			return err;	}#if defined(CONFIG_IP_NF_CONNTRACK_MARK)	if (cda[CTA_MARK-1])		ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));#endif	DEBUGP("all done\n");	return 0;}static intctnetlink_create_conntrack(struct nfattr *cda[], 			   struct ip_conntrack_tuple *otuple,			   struct ip_conntrack_tuple *rtuple){	struct ip_conntrack *ct;	int err = -EINVAL;	DEBUGP("entered %s\n", __FUNCTION__);	ct = ip_conntrack_alloc(otuple, rtuple);	if (ct == NULL || IS_ERR(ct))		return -ENOMEM;		if (!cda[CTA_TIMEOUT-1])		goto err;	ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));	ct->timeout.expires = jiffies + ct->timeout.expires * HZ;	ct->status |= IPS_CONFIRMED;	err = ctnetlink_change_status(ct, cda);	if (err < 0)		goto err;	if (cda[CTA_PROTOINFO-1]) {		err = ctnetlink_change_protoinfo(ct, cda);		if (err < 0)			return err;	}	ct->helper = ip_conntrack_helper_find_get(rtuple);	add_timer(&ct->timeout);	ip_conntrack_hash_insert(ct);	if (ct->helper)		ip_conntrack_helper_put(ct->helper);#if defined(CONFIG_IP_NF_CONNTRACK_MARK)	if (cda[CTA_MARK-1])		ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));#endif	DEBUGP("conntrack with id %u inserted\n", ct->id);	return 0;err:		ip_conntrack_free(ct);	return err;}static int ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, 			struct nlmsghdr *nlh, struct nfattr *cda[], int *errp){	struct ip_conntrack_tuple otuple, rtuple;	struct ip_conntrack_tuple_hash *h = NULL;	int err = 0;	DEBUGP("entered %s\n", __FUNCTION__);	if (nfattr_bad_size(cda, CTA_MAX, cta_min))		return -EINVAL;	if (cda[CTA_TUPLE_ORIG-1]) {		err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG);		if (err < 0)			return err;	}	if (cda[CTA_TUPLE_REPLY-1]) {		err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY);		if (err < 0)			return err;	}	write_lock_bh(&ip_conntrack_lock);	if (cda[CTA_TUPLE_ORIG-1])		h = __ip_conntrack_find(&otuple, NULL);	else if (cda[CTA_TUPLE_REPLY-1])		h = __ip_conntrack_find(&rtuple, NULL);	if (h == NULL) {		write_unlock_bh(&ip_conntrack_lock);		DEBUGP("no such conntrack, create new\n");

⌨️ 快捷键说明

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