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


 
/***************************************************************** 
[NAPT example] 
 
wan ip		192.168.10.158 
lan ip		192.168.0.36 
server		192.168.10.48:80 
client		192.168.0.63:2085  
================= LAN ======================= 
 lan recv  
 	orig0		192.168.0.63:2085 -> 192.168.10.48:80 
 make hash0 & add to list 
	reply0		192.168.10.158:1030 -> 192.168.10.48:80 
	orig0		192.168.0.63:2085 -> 192.168.10.48:80 
 make & timeouts set & lan send 
 	reply0		192.168.10.158:1030 -> 192.168.10.48:80 
 ----------------------WAN----------------------------	 
 wan recv 
	orig1		192.168.10.48:80 -> 192.168.10.158:1030 
 invert 
 	invert1		192.168.10.158:1030 -> 192.168.10.48:80 
 find hash in list if(invert1 == replyN) 
	reply0(hash0)	192.168.10.158:1030 -> 192.168.10.48:80 
	orig0(hash0)	192.168.0.63:2085 -> 192.168.10.48:80 
 make & wan send  
 	invert orig0 	192.168.10.48:80-> 192.168.0.63:2085	 
 
================= DEBUG ====================== 
lan in  
orig tuple 0x80603090: 6 192.168.0.63:2187 -> 131.220.99.11:80 
 
can't find conntrack,build new 
Translation list : 
tuple 0x80528934: 6 192.168.10.158:1043 -> 131.220.99.11:80 
tuple 0x80528918: 6 192.168.0.63:2187 -> 131.220.99.11:80 
 
tcp_manip_pkt 
orig 192.168.10.158:2187, new 192.168.10.158:1043 
 
manip_pkt  
str_ip : 192.168.10.158,  dst_ip: 131.220.99.11 
 
ip_forward 
ip_output=0, bcm (unit number 0) 
 
 
wan in 
orig tuple 0x80603090: 6 131.220.99.11:80 -> 192.168.10.158:1043 
invert tuple 0x80603080: 6 192.168.10.158:1043 -> 131.220.99.11:80 
 
find tuple_hash 
Translation list : 
tuple 0x80528934: 6 192.168.10.158:1043 -> 131.220.99.11:80 
tuple 0x80528918: 6 192.168.0.63:2187 -> 131.220.99.11:80 
 
tcp_manip_pkt 
orig 192.168.0.63:1043, new 192.168.0.63:2187 
 
manip_pkt  
str_ip : 131.220.99.11,  dst_ip: 192.168.0.63 
 
ip_forward  
ip_output=0, bcm (unit number 1)	 
 
//////////////////////////////////////////////////////// 
 
[Port Forward example] 
 
wan ip		192.168.10.158 
lan ip		192.168.0.36 
open port		192.168.0.63:80 
client		192.168.10.63:3244 
================= WAN ======================= 
 wan recv  
 	orig0		192.168.10.63:3244 -> 192.168.10.158:80 
 find port 
 	port0		192.168.0.63:80 
 make hash0 & add to list 
	reply0		192.168.0.36:1024 -> 192.168.0.63:80 (port0) 
	orig0 		192.168.10.63:3244 -> 192.168.10.158:80 
 make & timeouts set & wan send 
 	reply0		192.168.0.36:1024 -> 192.168.0.63:80 
 ----------------------LAN -----------------------------	 
 lan recv 
	orig1		192.168.0.63:80 -> 192.168.0.36:1024 
 invert 
 	invert1		192.168.0.36:1024 -> 192.168.0.63:80 
 find hash in list if(invert1 == replyN) 
	reply0(hash0)	192.168.0.36:1024 -> 192.168.0.63:80 
	orig0(hash0)	192.168.10.63:3244 -> 192.168.10.158:80 
 make & wan send  
 	invert orig0 	192.168.10.158:80 -> 192.168.10.63:3244	 
 
================= DEBUG ====================== 
wan in 
 
orig tuple 0x80603090: 6 192.168.10.63:3244 -> 192.168.10.158:80 
 
DMZ or port forward, build new 
Translation list : 
tuple 0x80528934: 6 192.168.0.36:1024 -> 192.168.0.63:80 
tuple 0x80528918: 6 192.168.10.63:3244 -> 192.168.10.158:80 
 
tcp_manip_pkt 
orig 192.168.0.36:3244, new 192.168.0.36:1024 
 
manip_pkt  
str_ip : 192.168.0.36,  dst_ip: 192.168.0.63 
 
ip_forward 
ip_output=0, bcm (unit number 1) 
 
 
lan in 
orig tuple 0x80603090: 6 192.168.0.63:80 -> 192.168.0.36:1024 
invert tuple 0x80603080: 6 192.168.0.36:1024 -> 192.168.0.63:80 
 
find tuple_hash 
Translation list : 
tuple 0x80528934: 6 192.168.0.36:1024 -> 192.168.0.63:80 
tuple 0x80528918: 6 192.168.10.63:3244 -> 192.168.10.158:80 
 
tcp_manip_pkt 
orig 192.168.10.63:1024, new 192.168.10.158:80 
 
manip_pkt  
str_ip : 192.168.10.158,  dst_ip: 192.168.10.63 
 
ip_forward  
ip_output=0, bcm (unit number 0) 
 
******************************************************************/ 
 
 
#include  
 
#include "list.h" 
#include "ip_nat_tuple.h" 
#include "ip_conntrack.h" 
#include "nat.h" 
#include "ip_nat_proto.h" 
 
#define MAX_PF		10 
 
struct port_forward_range 
{ 
	unsigned long					lanip; 
	unsigned short					proto; 
	union ip_conntrack_manip_proto	min, max; 
}; 
 
struct nat_config 
{ 
	unsigned long  wan_ip; 
	unsigned long  wan_mask; 
	unsigned long  lan_ip; 
	unsigned long  lan_mask; 
 
	unsigned long pf_list_size; 
	struct port_forward_range port_forward[MAX_PF]; 
 
}; 
static struct nat_config natcfg; 
 
struct list_head nat_timer ={&nat_timer,&nat_timer}; 
 
int del_timer(struct timer_list * list) 
{ 
	if(list_empty(&nat_timer) || list->list.next==NULL) 
		return 1; 
 
	list_del(&list->list); 
	list->list.next = NULL; 
	list->list.prev = NULL; 
 
	return 1; 
} 
 
int add_timer(struct timer_list * list) 
{ 
	list_prepend(&nat_timer,list); 
	return 1; 
} 
 
 
unsigned short checksum(unsigned short* buffer, int size)  
{ 
    unsigned long cksum = 0; 
     
    // Sum all the words together, adding the final byte if size is odd 
    while (size > 1)  
	{ 
        cksum += *buffer++; 
        size -= sizeof(unsigned short); 
    } 
    if (size)  
	{ 
        cksum += *(unsigned char*)buffer; 
    } 
 
    // Do a little shuffling 
    cksum = (cksum >> 16) + (cksum & 0xffff); 
    cksum += (cksum >> 16); 
     
    // Return the bitwise complement of the resulting mishmash 
    return (unsigned short)(~cksum); 
} 
 
void nat_watch_dog() 
{ 
//	int s; 
	register struct list_head *__i = nat_timer.next; 
	struct timer_list * tl; 
	//s = splnet(); 
			 
	while(__i != &nat_timer) 
	{	 
		tl = (struct timer_list *)__i; 
//		DEBUGP("\ndata %x expires %d",tl->data,tl->expires); 
		tl->expires -= 10; 
		if(tl->expires <=0 && tl->function) 
		{ 
			list_del(__i); 
			tl->function(tl->data); 
		} 
		__i = __i->next;			 
						 
	} 	 
//	splx (s); 
	 
	//wdStart (watch_dog_id, sysClkRateGet() * 10, (FUNCPTR) netJobAdd,(int) nat_watch_dog); 
	 
} 
 
 
int  natInit() 
{ 
		 
	ip_conntrack_protocol_register(&ip_nat_protocol_icmp); 
	ip_conntrack_protocol_register(&ip_nat_protocol_udp); 
	ip_conntrack_protocol_register(&ip_nat_protocol_tcp); 
 
	// Port forward 
	natcfg.pf_list_size = 1; 
	natcfg.port_forward[0].protonum = 6 ; // 1 icmp , 6 tcp , 17 udp. 
	natcfg.port_forward[0].min.all = 8080; 
	natcfg.port_forward[0].max.all = 8080; 
 
	return 1; 
} 
 
/////////////////////////////////////////////////////////////////////// 
 
static void 
manip_pkt(struct ip_nat_protocol * proto,  
	  struct ip_hdr *iph, int len, 
	  const struct ip_conntrack_manip *manip, 
	  enum ip_nat_manip_type maniptype) 
{ 
 
	//set new PORT(ICMP:ID) 
	proto->manip_pkt(iph, len, manip, maniptype); 
 
	//set new IP 
	if (maniptype == IP_NAT_MANIP_SRC) 
	{ 
		checksumadjust((unsigned char *)&iph->checksum,(unsigned char *)&iph->source_ip,4, 
					(unsigned char *)&manip->ip,4); 
 
		iph->source_ip = manip->ip; 
 
	}  
	else  
	{ 
		checksumadjust((unsigned char *)&iph->checksum,(unsigned char *)&iph->dest_ip,4, 
					(unsigned char *)&manip->ip,4); 
		 
		iph->dest_ip = manip->ip; 
	} 
} 
 
 
 void 
forward_manip_pkt(struct ip_nat_protocol * proto,  
	  struct ip_hdr *iph, unsigned int len, 
	  const struct ip_conntrack_tuple *tuple,  
	  enum ip_nat_manip_type maniptype) 
{	 
 
	if (maniptype == IP_NAT_MANIP_SRC) 
	{ 
		proto->manip_pkt(iph, len, (struct ip_conntrack_manip *)&tuple->src, IP_NAT_MANIP_SRC); 
		proto->manip_pkt(iph, len, (struct ip_conntrack_manip *)&tuple->dst, IP_NAT_MANIP_DST); 
		 
		iph->source_ip = tuple->src.ip; 
		iph->dest_ip = tuple->dst.ip; 
	} 
	else 
	{ 
		proto->manip_pkt(iph, len, (struct ip_conntrack_manip *)&tuple->src, IP_NAT_MANIP_DST); 
		proto->manip_pkt(iph, len, (struct ip_conntrack_manip *)&tuple->dst, IP_NAT_MANIP_SRC); 
		 
		iph->source_ip = tuple->dst.ip; 
		iph->dest_ip = tuple->src.ip; 
	} 
 
} 
 
int need_add_tuple(const struct ip_conntrack_tuple *tuple, 
					struct ip_nat_protocol *proto) 
{ 
	int i = -1; 
 
	for(i = 0; i < (int)natcfg.pf_list_size; i++) 
	{ 
		if(natcfg.port_forward[i].proto == tuple->dst.proto 
			&& proto->in_range(tuple,IP_NAT_MANIP_SRC, 
						&natcfg.port_forward[i].min, 
						&natcfg.port_forward[i].max)) 
		{ 
			return i; 
		} 
	} 
	return -1; 
	 
} 
 
static int ip_nat_wan_in(char *data, int len) 
{	 
	struct ip_nat_protocol			*proto; 
	struct ip_conntrack_tuple		tuple,orig; 
	struct ip_conntrack_tuple_hash	*tuple_hash; 
	struct ip_hdr					*iph; 
	int								i; 
 
 
	iph = (struct ip_hdr *)data; 
	proto = find_proto(iph->proto); 
	if(!proto) 
		return 0; 
 
	//get origin_packet 
	orig.src.ip = iph->source_ip; 
	orig.dst.ip = iph->dest_ip; 
	orig.dst.proto = iph->proto; 
	proto->pkt_to_tuple((unsigned long  *)(data + IPH_SIZE), len - IPH_SIZE, &orig); 
	DEBUGP("orig "); 
	DUMP_TUPLE(&orig); 
 
	//get invert_packet 
	tuple.src.ip = orig.dst.ip; 
	tuple.dst.ip = orig.src.ip; 
	tuple.dst.proto = orig.dst.proto; 
	proto->invert_tuple(&tuple,&orig);  // if ICMP, set id/type/code. 
	DEBUGP("invert "); 
	DUMP_TUPLE(&tuple); 
 
	i = need_add_tuple(&tuple,proto); 
	if( i >= 0) 
	{ 
		struct ip_nat_multi_range mr 
			= 
		{ 1,  
			{  
				{  
					IP_NAT_RANGE_MAP_IPS,  
					natcfg.port_forward[i].lanip, //inet_addr("192.168.0.63"),  
					natcfg.port_forward[i].lanip, //inet_addr("192.168.0.63"),  
					{ tuple.src.u.all}, // min port 
					{ tuple.src.u.all } // max port 
				}  
			}  
		}; 
		DEBUGP("\nport forward ,build new\n"); 
 
		tuple_hash = ip_portforward_setup(proto,&orig,&mr, natcfg.lan_ip); 
		if(!tuple_hash) 
		{ 
			return FALSE; 
		} 
		 
		conntrack_print(); 
				 
		// set dst_ip and checksum use new dst_ip 
		forward_manip_pkt(proto, iph, len, 
			&tuple_hash->ctrack->tuplehash[IP_CT_DIR_REPLY].tuple, 
			IP_NAT_MANIP_SRC); 
		 
		// set timeout 
		proto->packet(tuple_hash->ctrack,iph,len, IP_NAT_MANIP_SRC); 
 
	}else 
	{ 
		tuple_hash = ip_conntrack_find(&tuple,0); 
		if(tuple_hash) 
		{ 
			printf("NAPT find\n"); 
			conntrack_print(); 
 
			manip_pkt(proto,iph,len, 
				&tuple_hash->ctrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src,IP_NAT_MANIP_DST); 
 
			tuple_hash->ctrack->status |= IPS_SEEN_REPLY; 
			proto->packet(tuple_hash->ctrack,iph,len,IP_NAT_MANIP_DST); 
			 
			//ip_forward(*pPtrMbuf,0); 
 
			return 1;	 
		} 
	} 
	return 0;	 
} 
 
 
// Program entry point 
static  int ip_nat_lan_in(char *data, unsigned int len) 
{ 
	struct ip_nat_protocol			*proto; 
	struct ip_conntrack_tuple		tuple,invert; 
	struct ip_conntrack_tuple_hash	*tuple_hash; 
	struct ip_hdr					*iph; 
 
	iph = (struct ip_hdr *)data; 
	proto = find_proto(iph->proto); 
	if(!proto) 
		return 0; 
 
 
	tuple.src.ip = iph->source_ip; 
	tuple.dst.ip = iph->dest_ip; 
	tuple.dst.proto = iph->proto; 
 
	proto->pkt_to_tuple((unsigned long  *)(data + IPH_SIZE), len - IPH_SIZE, &tuple); 
	DEBUGP("orig "); 
	DUMP_TUPLE(&tuple); 
 
	invert.src.ip = tuple.dst.ip; 
	invert.dst.ip = tuple.src.ip; 
	invert.dst.proto = tuple.dst.proto; 
	proto->invert_tuple(&invert,&tuple); 
 
	tuple_hash = ip_conntrack_find(&invert,NULL); 
	if(tuple_hash) /* Port Forward*/ 
	{ 
		forward_manip_pkt(proto,	iph,len, 
			&tuple_hash->ctrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple, 
			IP_NAT_MANIP_DST); 
 
		proto->packet(tuple_hash->ctrack,iph,len,IP_NAT_MANIP_DST); 
 
 
	}else/* NAPT */ 
	{ 
		tuple_hash = ip_conntrack_find(&tuple,NULL); 
		if(!tuple_hash) 
		{ 
			struct ip_nat_multi_range mr =  
			{	1,  
			{ 
				{ 
					IP_NAT_RANGE_MAP_IPS|IP_NAT_RANGE_PROTO_SPECIFIED,  
						natcfg.wan_ip,  // min ip 
						natcfg.wan_ip,  // max ip 
					{htons(1024)}, // min port 
					{htons(4096)}  // max port 
				} 
			} 
			}; 
			DEBUGP("can't find conntrack,build new\n"); 
			tuple_hash = ip_nat_setup(proto,&tuple,&mr); 
			if(!tuple_hash) 
				return 0; 
		} 
		conntrack_print(); 
 
		//modify IP&PORT(icmp :ID), adjust checksum. 
		manip_pkt(proto,  iph, len, 
			&tuple_hash->ctrack->tuplehash[IP_CT_DIR_REPLY].tuple.src, IP_NAT_MANIP_SRC); 
 
		// set timeout 
		proto->packet(tuple_hash->ctrack,iph,len,IP_NAT_MANIP_SRC); 
	} 
 
	//continue forward send 
	//ip_forward(*pPtrMbuf,0); 
	return 1; 
}