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; }