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