www.pudn.com > nat.rar > ip_conntrack.cpp


#include  
#include  
 
#include "list.h" 
#include "ip_nat_tuple.h" 
#include "ip_conntrack.h" 
#include "nat.h" 
#include "ip_nat_proto.h" 
 
struct list_head	ip_conntrack_hash = {&ip_conntrack_hash,&ip_conntrack_hash}; 
 
static inline int	conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i, 
const struct ip_conntrack_tuple *tuple,const struct ip_conntrack *ignored_conntrack) 
{ 
	return i->ctrack != ignored_conntrack 
		&& ip_ct_tuple_equal(tuple, &i->tuple); 
} 
 
static struct ip_conntrack_tuple_hash *__ip_conntrack_find( 
const struct ip_conntrack_tuple *tuple,const struct ip_conntrack *ignored_conntrack) 
{ 
	struct list_head *h = &ip_conntrack_hash; 
	do  
	{						 
		h = h->next;			 
		if (h == (&ip_conntrack_hash))  
		{			 
			h = 0;			 
			break;				 
		}					 
	} while (!conntrack_tuple_cmp((ip_conntrack_tuple_hash *)h, tuple, ignored_conntrack));	 
 
	return (struct ip_conntrack_tuple_hash *)h; 
} 
 
int 
ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple, 
						 const struct ip_conntrack *ignored_conntrack) 
{ 
	struct ip_conntrack_tuple_hash *h; 
	h = __ip_conntrack_find(tuple, ignored_conntrack); 
	return h != 0; 
} 
 
int 
ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple, 
				  const struct ip_conntrack *ignored_conntrack) 
{ 
	return ip_conntrack_tuple_taken(tuple, ignored_conntrack); 
} 
 
struct ip_conntrack_tuple_hash * 
ip_conntrack_find(const struct ip_conntrack_tuple *tuple, 
					  const struct ip_conntrack *ignored_conntrack) 
{ 
	struct ip_conntrack_tuple_hash *h; 
	h = __ip_conntrack_find(tuple, ignored_conntrack); 
	return h; 
} 
 
static int 
invert_tuple(struct ip_conntrack_tuple *inverse, 
			 const struct ip_conntrack_tuple *orig, 
			 const struct ip_nat_protocol *protocol) 
{ 
	inverse->src.ip = orig->dst.ip; 
	inverse->dst.ip = orig->src.ip; 
	inverse->dst.proto = orig->dst.proto; 
	 
	return protocol->invert_tuple(inverse, orig); 
} 
 
void ip_conntrack_delete(struct ip_conntrack *ctrack) 
{ 
//	list_del(&ctrack->tuplehash[IP_CT_DIR_ORIGINAL].list); 
//	list_del(&ctrack->tuplehash[IP_CT_DIR_REPLY].list); 
	free(ctrack); 
} 
 
static void death_by_timeout(unsigned long ul_conntrack) 
{ 
	struct ip_conntrack *ct = (struct ip_conntrack *)ul_conntrack; 
	DEBUGP("\nTimeout delete connect track :\n"); 
	DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 
	DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); 
	ip_conntrack_delete(ct); 
} 
 
 
struct ip_conntrack_tuple_hash * 
ip_portforward_setup(struct ip_nat_protocol * proto,  
	  	  struct ip_conntrack_tuple *tuple, 
		  const struct ip_nat_multi_range *mr, 
		  u_long lanip) 
{ 
	struct ip_conntrack_tuple_hash * tuple_hash_original,*tuple_hash_rely; 
	struct ip_conntrack *ctrack; 
 
	ctrack = (struct ip_conntrack *)malloc(sizeof(struct ip_conntrack)); 
	if(ctrack == 0) 
		return 0; 
		 
	memset(ctrack, 0,sizeof(struct ip_conntrack)); 
 
	ctrack->timeout.function = death_by_timeout; 
	ctrack->timeout.data = (unsigned long)ctrack; 
	 
	tuple_hash_original = &ctrack->tuplehash[IP_CT_DIR_ORIGINAL]; 
	tuple_hash_rely =  &ctrack->tuplehash[IP_CT_DIR_REPLY]; 
	 
	tuple_hash_original->ctrack = ctrack; 
	tuple_hash_rely->ctrack = ctrack; 
	 
	memcpy(&tuple_hash_original->tuple,tuple,sizeof(struct ip_conntrack_tuple)); 
	memcpy(&tuple_hash_rely->tuple,tuple,sizeof(struct ip_conntrack_tuple)); 
 
	// trans IP 
	tuple_hash_rely->tuple.dst.ip= mr->range[0].min_ip;  
	tuple_hash_rely->tuple.src.ip= lanip;  
 
	// trans port, example 1024 
	if (!proto->unique_tuple(&tuple_hash_rely->tuple, 
		                &mr->range[0], 
				  IP_NAT_MANIP_SRC, 
				  ctrack)) 
	{ 
		DEBUGP("\nAdd tuple fail"); 
		free(ctrack); 
		return 0; 
	} 
 
	 
	list_prepend(&ip_conntrack_hash,tuple_hash_original); 
	list_prepend(&ip_conntrack_hash,tuple_hash_rely); 
 
	return &ctrack->tuplehash[IP_CT_DIR_ORIGINAL]; 
	 
} 
 
struct ip_conntrack_tuple_hash * 
ip_nat_setup(struct ip_nat_protocol * proto,  
	  	  struct ip_conntrack_tuple *tuple, 
		  const struct ip_nat_multi_range *mr) 
{ 
	struct ip_conntrack_tuple_hash *tuple_hash_original,*tuple_hash_rely; 
	struct ip_conntrack *ctrack; 
 
 
	ctrack = (struct ip_conntrack *)malloc(sizeof(struct ip_conntrack)); 
	if(ctrack == 0) 
		return 0; 
		 
	memset(ctrack, 0,sizeof(struct ip_conntrack)); 
 
	ctrack->timeout.function = death_by_timeout; 
	ctrack->timeout.data = (unsigned long)ctrack; 
	 
	tuple_hash_original = &ctrack->tuplehash[IP_CT_DIR_ORIGINAL]; 
	tuple_hash_rely =  &ctrack->tuplehash[IP_CT_DIR_REPLY]; 
	 
	tuple_hash_original->ctrack = ctrack; 
	tuple_hash_rely->ctrack = ctrack; 
	 
	memcpy(&tuple_hash_original->tuple,tuple,sizeof(struct ip_conntrack_tuple)); 
	memcpy(&tuple_hash_rely->tuple,tuple,sizeof(struct ip_conntrack_tuple)); 
 
	tuple_hash_rely->tuple.src.ip = mr->range[0].min_ip; 
 
	// trans port OR id 
	if (!proto->unique_tuple(&tuple_hash_rely->tuple, 
		                &mr->range[0], 
				  IP_NAT_MANIP_SRC, 
				  ctrack)) 
	{ 
		printf("\nAdd tuple fail"); 
		free(ctrack); 
		return 0; 
	} 
 
	list_prepend(&ip_conntrack_hash,tuple_hash_original); 
	list_prepend(&ip_conntrack_hash,tuple_hash_rely); 
 
	return &ctrack->tuplehash[IP_CT_DIR_ORIGINAL]; 
	 
} 
 
 
void conntrack_print() 
{ 
	struct list_head * p = ip_conntrack_hash.next; 
	struct ip_conntrack_tuple_hash * tuple; 
 
	DEBUGP("\nTranslation list :\n"); 
 
	while(p != &ip_conntrack_hash) 
	{ 
		tuple = (struct ip_conntrack_tuple_hash *)p; 
		DUMP_TUPLE(&tuple->tuple); 
		p = p->next; 
	} 
} 
 
/* NAT修正以每个包为准的,能够准确计算,因为除了简单域转换外,它们包括一个或多个  
校验和修正。下面的算法,它能简单有效地调整IP,TCP,UDP和ICMP 报头校验和。 
因为所有这些报头用一个辅助校验和在转换时计算差距和把它加到校验和是足够的。 
下面的算法只有对偶偏移有效(如:下面optr是从报头开始必须是偶偏移)和偶数 长度 
(如,下面的olen和nlen)。 
 
assuming:unsigned char is 8 bits, long is 32 bits.  
	- chksum points to the chksum in the packet  
	- optr points to the old data in the packet  
	- nptr points to the new data in the packet */  
//*/ 
void checksumadjust(unsigned char *chksum, unsigned char *optr, int olen,  
					unsigned char *nptr, int nlen) 
{  
	long	x,old_tmp,new_tmp;  
 
	x = chksum[0]*256 + chksum[1];  
	x = x & 0xFFFF;  
 
	while(olen)  
	{  
		old_tmp = optr[0]*256 + optr[1];  
		optr += 2;  
		x -= old_tmp & 0xffff;  
		if(x<=0 )	{ x--; x&=0xffff;}  
		olen-=2;  
	}  
	while(nlen)  
	{  
		new_tmp = nptr[0]*256 + nptr[1];  
		nptr += 2;  
		x += new_tmp & 0xffff;  
		if(x & 0x10000){ x++; x &= 0xffff;} 
		nlen -= 2;  
	}  
	x = x & 0xffff;  
	chksum[0] = x/256;  
	chksum[1] = x&0xff;  
}  
 
 
void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies) 
{ 
	if (ct->timeout.list.next != NULL) 
	{ 
		ct->timeout.expires = extra_jiffies; 
	} 
	else  
	{ 
		if (del_timer(&ct->timeout))  
		{ 
			ct->timeout.expires = extra_jiffies; 
			add_timer(&ct->timeout); 
		} 
	} 
}