ip_nat_core.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,042 行 · 第 1/3 页

C
1,042
字号
				best.score = score;				best.tuple = *tuple;				best.range = &mr->range[i];			}		}	}	*tuple = best.tuple;	/* Discard const. */	return (struct ip_nat_range *)best.range;}/* Fast version doesn't iterate through hash chains, but only handles   common case of single IP address (null NAT, masquerade) */static struct ip_nat_range *find_best_ips_proto_fast(struct ip_conntrack_tuple *tuple,			 const struct ip_nat_multi_range *mr,			 const struct ip_conntrack *conntrack,			 unsigned int hooknum){	if (mr->rangesize != 1	    || (mr->range[0].flags & IP_NAT_RANGE_FULL)	    || ((mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)		&& mr->range[0].min_ip != mr->range[0].max_ip))		return find_best_ips_proto(tuple, mr, conntrack, hooknum);	if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {		if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)			tuple->src.ip = mr->range[0].min_ip;		else {			/* Only do extra mangle when required (breaks                           socket binding) */#ifdef CONFIG_IP_NF_NAT_LOCAL			if (tuple->dst.ip != mr->range[0].min_ip			    && hooknum == NF_IP_LOCAL_OUT			    && !do_extra_mangle(mr->range[0].min_ip,						&tuple->src.ip))				return NULL;#endif			tuple->dst.ip = mr->range[0].min_ip;		}	}	/* Discard const. */	return (struct ip_nat_range *)&mr->range[0];}static intget_unique_tuple(struct ip_conntrack_tuple *tuple,		 const struct ip_conntrack_tuple *orig_tuple,		 const struct ip_nat_multi_range *mrr,		 struct ip_conntrack *conntrack,		 unsigned int hooknum){	struct ip_nat_protocol *proto		= find_nat_proto(orig_tuple->dst.protonum);	struct ip_nat_range *rptr;	unsigned int i;	int ret;	/* We temporarily use flags for marking full parts, but we	   always clean up afterwards */	struct ip_nat_multi_range *mr = (void *)mrr;	/* 1) If this srcip/proto/src-proto-part is currently mapped,	   and that same mapping gives a unique tuple within the given	   range, use that.	   This is only required for source (ie. NAT/masq) mappings.	   So far, we don't do local source mappings, so multiple	   manips not an issue.  */	if (hooknum == NF_IP_POST_ROUTING) {		struct ip_conntrack_manip *manip;		manip = find_appropriate_src(orig_tuple, mr);		if (manip) {			/* Apply same source manipulation. */			*tuple = ((struct ip_conntrack_tuple)				  { *manip, orig_tuple->dst });			DEBUGP("get_unique_tuple: Found current src map\n");			if (!ip_nat_used_tuple(tuple, conntrack))				return 1;		}	}	/* 2) Select the least-used IP/proto combination in the given	   range.	*/	*tuple = *orig_tuple;	while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))	       != NULL) {		DEBUGP("Found best for "); DUMP_TUPLE(tuple);		/* 3) The per-protocol part of the manip is made to		   map into the range to make a unique tuple. */		/* Only bother mapping if it's not already in range		   and unique */		if ((!(rptr->flags & IP_NAT_RANGE_PROTO_SPECIFIED)		     || proto->in_range(tuple, HOOK2MANIP(hooknum),					&rptr->min, &rptr->max))		    && !ip_nat_used_tuple(tuple, conntrack)) {			ret = 1;			goto clear_fulls;		} else {			if (proto->unique_tuple(tuple, rptr,						HOOK2MANIP(hooknum),						conntrack)) {				/* Must be unique. */				IP_NF_ASSERT(!ip_nat_used_tuple(tuple,								conntrack));				ret = 1;				goto clear_fulls;			} else if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {				/* Try implicit source NAT; protocol                                   may be able to play with ports to                                   make it unique. */				struct ip_nat_range r					= { IP_NAT_RANGE_MAP_IPS, 					    tuple->src.ip, tuple->src.ip,					    { 0 }, { 0 } };				DEBUGP("Trying implicit mapping\n");				if (proto->unique_tuple(tuple, &r,							IP_NAT_MANIP_SRC,							conntrack)) {					/* Must be unique. */					IP_NF_ASSERT(!ip_nat_used_tuple						     (tuple, conntrack));					ret = 1;					goto clear_fulls;				}			}			DEBUGP("Protocol can't get unique tuple %u.\n",			       hooknum);		}		/* Eliminate that from range, and try again. */		rptr->flags |= IP_NAT_RANGE_FULL;		*tuple = *orig_tuple;	}	ret = 0; clear_fulls:	/* Clear full flags. */	IP_NF_ASSERT(mr->rangesize >= 1);	for (i = 0; i < mr->rangesize; i++)		mr->range[i].flags &= ~IP_NAT_RANGE_FULL;	return ret;}static inline inthelper_cmp(const struct ip_nat_helper *helper,	   const struct ip_conntrack_tuple *tuple){	return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);}/* Where to manip the reply packets (will be reverse manip). */static unsigned int opposite_hook[NF_IP_NUMHOOKS]= { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,    [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING,#ifdef CONFIG_IP_NF_NAT_LOCAL    [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN,    [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT,#endif};unsigned intip_nat_setup_info(struct ip_conntrack *conntrack,		  const struct ip_nat_multi_range *mr,		  unsigned int hooknum){	struct ip_conntrack_tuple new_tuple, inv_tuple, reply;	struct ip_conntrack_tuple orig_tp;	struct ip_nat_info *info = &conntrack->nat.info;	int in_hashes = info->initialized;	MUST_BE_WRITE_LOCKED(&ip_nat_lock);	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING		     || hooknum == NF_IP_POST_ROUTING		     || hooknum == NF_IP_LOCAL_IN		     || hooknum == NF_IP_LOCAL_OUT);	IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);	IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));	/* What we've got will look like inverse of reply. Normally	   this is what is in the conntrack, except for prior	   manipulations (future optimization: if num_manips == 0,	   orig_tp =	   conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */	invert_tuplepr(&orig_tp,		       &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);#if 0	{	unsigned int i;	DEBUGP("Hook %u (%s), ", hooknum,	       HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST");	DUMP_TUPLE(&orig_tp);	DEBUGP("Range %p: ", mr);	for (i = 0; i < mr->rangesize; i++) {		DEBUGP("%u:%s%s%s %u.%u.%u.%u - %u.%u.%u.%u %u - %u\n",		       i,		       (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS)		       ? " MAP_IPS" : "",		       (mr->range[i].flags			& IP_NAT_RANGE_PROTO_SPECIFIED)		       ? " PROTO_SPECIFIED" : "",		       (mr->range[i].flags & IP_NAT_RANGE_FULL)		       ? " FULL" : "",		       NIPQUAD(mr->range[i].min_ip),		       NIPQUAD(mr->range[i].max_ip),		       mr->range[i].min.all,		       mr->range[i].max.all);	}	}#endif	do {		if (!get_unique_tuple(&new_tuple, &orig_tp, mr, conntrack,				      hooknum)) {			DEBUGP("ip_nat_setup_info: Can't get unique for %p.\n",			       conntrack);			return NF_DROP;		}#if 0		DEBUGP("Hook %u (%s) %p\n", hooknum,		       HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",		       conntrack);		DEBUGP("Original: ");		DUMP_TUPLE(&orig_tp);		DEBUGP("New: ");		DUMP_TUPLE(&new_tuple);#endif		/* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):		   the original (A/B/C/D') and the mangled one (E/F/G/H').		   We're only allowed to work with the SRC per-proto		   part, so we create inverses of both to start, then		   derive the other fields we need.  */		/* Reply connection: simply invert the new tuple                   (G/H/E/F') */		invert_tuplepr(&reply, &new_tuple);		/* Alter conntrack table so it recognizes replies.                   If fail this race (reply tuple now used), repeat. */	} while (!ip_conntrack_alter_reply(conntrack, &reply));	/* FIXME: We can simply used existing conntrack reply tuple           here --RR */	/* Create inverse of original: C/D/A/B' */	invert_tuplepr(&inv_tuple, &orig_tp);	/* Has source changed?. */	if (!ip_ct_tuple_src_equal(&new_tuple, &orig_tp)) {		/* In this direction, a source manip. */		info->manips[info->num_manips++] =			((struct ip_nat_info_manip)			 { IP_CT_DIR_ORIGINAL, hooknum,			   IP_NAT_MANIP_SRC, new_tuple.src });		IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);		/* In the reverse direction, a destination manip. */		info->manips[info->num_manips++] =			((struct ip_nat_info_manip)			 { IP_CT_DIR_REPLY, opposite_hook[hooknum],			   IP_NAT_MANIP_DST, orig_tp.src });		IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);	}	/* Has destination changed? */	if (!ip_ct_tuple_dst_equal(&new_tuple, &orig_tp)) {		/* In this direction, a destination manip */		info->manips[info->num_manips++] =			((struct ip_nat_info_manip)			 { IP_CT_DIR_ORIGINAL, hooknum,			   IP_NAT_MANIP_DST, reply.src });		IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);		/* In the reverse direction, a source manip. */		info->manips[info->num_manips++] =			((struct ip_nat_info_manip)			 { IP_CT_DIR_REPLY, opposite_hook[hooknum],			   IP_NAT_MANIP_SRC, inv_tuple.src });		IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);	}	/* If there's a helper, assign it; based on new tuple. */	if (!conntrack->master)		info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,					 &reply);	/* It's done. */	info->initialized |= (1 << HOOK2MANIP(hooknum));	if (in_hashes) {		IP_NF_ASSERT(info->bysource.conntrack);		replace_in_hashes(conntrack, info);	} else {		place_in_hashes(conntrack, info);	}	return NF_ACCEPT;}void replace_in_hashes(struct ip_conntrack *conntrack,		       struct ip_nat_info *info){	/* Source has changed, so replace in hashes. */	unsigned int srchash		= hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]			      .tuple.src,			      conntrack->tuplehash[IP_CT_DIR_ORIGINAL]			      .tuple.dst.protonum);	/* We place packet as seen OUTGOUNG in byips_proto hash           (ie. reverse dst and src of reply packet. */	unsigned int ipsprotohash		= hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]				   .tuple.dst.ip,				   conntrack->tuplehash[IP_CT_DIR_REPLY]				   .tuple.src.ip,				   conntrack->tuplehash[IP_CT_DIR_REPLY]				   .tuple.dst.protonum);	IP_NF_ASSERT(info->bysource.conntrack == conntrack);	MUST_BE_WRITE_LOCKED(&ip_nat_lock);	list_del(&info->bysource.list);	list_del(&info->byipsproto.list);	list_prepend(&bysource[srchash], &info->bysource);	list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);}void place_in_hashes(struct ip_conntrack *conntrack,		     struct ip_nat_info *info){	unsigned int srchash		= hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]			      .tuple.src,

⌨️ 快捷键说明

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