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


#include  
#include  
 
#include "rawping.h" 
#include "list.h" 
#include "ip_nat_tuple.h" 
#include "ip_conntrack.h" 
#include "nat.h" 
#include "ip_nat_proto.h" 
 
#define ICMP_TIMEOUT 30 
 
 
 
static int icmp_pkt_to_tuple(const void *datah, unsigned int datalen, 
			     struct ip_conntrack_tuple *tuple) 
{ 
	const struct icmp_hdr *hdr =(struct icmp_hdr * )datah; 
 
	tuple->dst.u.icmp.type = hdr->type; 
	tuple->src.u.icmp.id = hdr->id; 
	tuple->dst.u.icmp.code = hdr->code; 
 
	return 1; 
} 
 
/* Invert the per-proto part of the tuple: ie. turn xmit into reply. 
 * Some packets can't be inverted: return 0 in that case.*/ 
static int icmp_invert_tuple(struct ip_conntrack_tuple *tuple, 
			     const struct ip_conntrack_tuple *orig) 
{ 
	/*/ 
		#define ICMP_ECHO 8			//请求报文的类型值 
		#define ICMP_ECHOREPLY 0    //应答报文的类型值 
 
		static unsigned char invmap[] 
		= { [ICMP_ECHO] = ICMP_ECHOREPLY + 1, 
		    [ICMP_ECHOREPLY] = ICMP_ECHO + 1, 
		    [ICMP_TSTAMP] = ICMP_TSTAMPREPLY + 1, 
		    [ICMP_TSTAMPREPLY] = ICMP_TSTAMP + 1, 
		    [ICMP_IREQ] = ICMP_IREQREPLY + 1, 
		    [ICMP_IREQREPLY] = ICMP_IREQ + 1, 
		    [ICMP_MASKREQ] = ICMP_MASKREPLY + 1, 
		    [ICMP_MASKREPLY] = ICMP_MASKREQ + 1}; 
	//*/ 
	static unsigned char invmap[] = {8+1,0,0,0,0,0,0,0,1,0,0,0,0,15,14,17,16,19,18 }; 
 
	if (orig->dst.u.icmp.type >= sizeof(invmap) || !invmap[orig->dst.u.icmp.type]) 
		return 0; 
 
	tuple->src.u.icmp.id = orig->src.u.icmp.id; 
	tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1; 
	tuple->dst.u.icmp.code = orig->dst.u.icmp.code; 
	return 1; 
} 
 
static int 
icmp_in_range(const struct ip_conntrack_tuple *tuple, 
	      enum ip_nat_manip_type maniptype, 
	      const union ip_conntrack_manip_proto *min, 
	      const union ip_conntrack_manip_proto *max) 
{ 
	return (tuple->src.u.icmp.id >= min->icmp.id 
		&& tuple->src.u.icmp.id <= max->icmp.id); 
} 
 
/* Alter the per-proto part of the tuple (depending on maniptype), 
to give a unique tuple in the given range if possible; return false if not.   
Per-protocol part of tuple is initialized to the incoming packet. */ 
static int 
icmp_unique_tuple(struct ip_conntrack_tuple *tuple, 
		  const struct ip_nat_range *range, 
		  enum ip_nat_manip_type maniptype, 
		  const struct ip_conntrack *conntrack) 
{ 
	static unsigned short	id = 0; 
	unsigned int	range_size	=  
		(unsigned int)range->max.icmp.id - range->min.icmp.id + 1; 
	unsigned int	i; 
 
	// If no range specified... 
	if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) 
	{ 
		range_size = 0xFFFF; 
	} 
 
	for (i = 0; i < range_size; i++, id++)  
	{ 
		tuple->src.u.icmp.id = range->min.icmp.id + (id % range_size); 
		if (!ip_nat_used_tuple(tuple, conntrack)) 
		{ 
			return 1; 
		} 
	} 
	return 0; 
} 
 
static void 
icmp_manip_pkt(struct ip_hdr *iph, unsigned int len, 
	       const struct ip_conntrack_manip *manip, 
	       enum ip_nat_manip_type maniptype) 
{ 
 
	struct icmp_hdr *hdr = (struct icmp_hdr *)((unsigned long *)iph + iph->hl); 
	 
	//printf("\t old icmp_id\t %d\n",hdr->id); 
	printf("\t old chsum\t 0x%x\n",hdr->checksum); 
	 
	checksumadjust((unsigned char *)&hdr->checksum, 
		(unsigned char *)&manip->u.icmp.id,	2, 
		(unsigned char *)&hdr->id,2); 
	 
	hdr->id = manip->u.icmp.id; 
 
	//printf("\t new icmp_id\t %d\n",hdr->id); 
	printf("\t new chsum\t 0x%x\n",hdr->checksum); 
 
} 
 
static unsigned int 
icmp_print(char *buffer, 
	   const struct ip_conntrack_tuple *match, 
	   const struct ip_conntrack_tuple *mask) 
{ 
	unsigned int len = 0; 
 
	if (mask->src.u.icmp.id) 
		len += sprintf(buffer + len, "id=%u ", 
			       ntohs(match->src.u.icmp.id)); 
 
	if (mask->dst.u.icmp.type) 
		len += sprintf(buffer + len, "type=%u ", 
			       ntohs(match->dst.u.icmp.type)); 
 
	if (mask->dst.u.icmp.code) 
		len += sprintf(buffer + len, "code=%u ", 
			       ntohs(match->dst.u.icmp.code)); 
 
	return len; 
} 
 
static unsigned int 
icmp_print_range(char *buffer, const struct ip_nat_range *range) 
{ 
	if (range->min.icmp.id != 0 || range->max.icmp.id != 0xFFFF) 
		return sprintf(buffer, "id %u-%u ", 
			       ntohs(range->min.icmp.id), 
			       ntohs(range->max.icmp.id)); 
	else return 0; 
} 
 
 
static int icmp_packet(struct ip_conntrack *ct, 
	struct ip_hdr *iph, unsigned int len,enum ip_nat_manip_type maniptype) 
{ 
	if (maniptype == IP_CT_DIR_REPLY)  
	{ 
		if ((--ct->proto.icmp.count <= 0) && del_timer(&ct->timeout)) 
		{ 
			ct->timeout.function((unsigned long)ct); 
		} 
	} else  
	{ 
		ct->proto.icmp.count++; 
		ip_ct_refresh(ct, ICMP_TIMEOUT); 
	} 
 
	return 1; 
} 
 
struct ip_nat_protocol  
ip_nat_protocol_icmp =  
{  
	{ 0, 0 },   
	IPPROTO_ICMP, 
    icmp_pkt_to_tuple, 
    icmp_invert_tuple, 
	icmp_manip_pkt, 
    icmp_in_range, 
    icmp_unique_tuple, 
    icmp_print, 
    icmp_print_range, 
	icmp_packet 
};