得到的数据ECHO REPLY从服务器到NAT后面的客户端 [英] get ECHO REPLY with data from server to client behind nat

查看:160
本文介绍了得到的数据ECHO REPLY从服务器到NAT后面的客户端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须编写发送ICMP回应请求来自手机(它是由移动ISP连接,并且它的背后NAT)来与服务器IP公共C程序。我写了一个简单的程序,发回显请求和接收回显应答,但现在我想从客户端发送回送请求到服务器,并从服务器接收ECHO REPLY一些数据(IP公共和ICMP ID)给客户端。我怎么能作出这样的?

Herre是我的code

 的#include<&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&string.h中GT;
#包括LT&; SYS / time.h中>
#包括LT&; netinet / ip.h>
#包括LT&; netinet / ip_icmp.h>
#包括LT&;&unistd.h中GT;
#包括LT&; ARPA / inet.h>
#包括LT&; SYS / socket.h中>的typedef unsigned char型U8;
typedef的无符号短整数U16;结构icmp_header {
   无符号的字符类型;
   unsigned char型code;
   无符号短校验;
   无符号短ID;
   无符号短序列;
};无符号短in_cksum(无符号短* PTR,诠释为nbytes);INT主(INT ARGC,字符** argv的){
INT C = 100;
INT LS; // lunghezza结构SOCKADDR_IN serveraddr
INT RF; //从接收无符号长DADDR;
无符号长SADDR;
INT payload_size = 0,发送= 0,sent_size;SADDR = inet_addr(IP专用);
DADDR = inet_addr(IP公);//原始套接字 - 如果你使用IPPROTO_ICMP,那么内核将填写正确的ICMP报头校验和,如果IPPROTO_RAW,那么它不会
INT的sockfd =插座(AF_INET,SOCK_RAW,IPPROTO_ICMP);如果(的sockfd℃,){
    PERROR(无法创建套接字);
    返回(0);
}INT在= 1;//我们将提供IP报头
如果(setsockopt的(的sockfd,IPPROTO_IP,IP_HDRINCL,(为const char *)及上的sizeof(上))== -1){
    PERROR(setsockopt的);
    返回(0);
}//允许套接字来发送数据包到广播地址
如果(setsockopt的(的sockfd,SOL_SOCKET,SO_BROADCAST,(为const char *)及上的sizeof(上))== -1){
    PERROR(setsockopt的);
    返回(0);
}//计算总包大小
INT PACKET_SIZE = sizeof的(结构iphdr)+的sizeof(结构icmp_header)+ payload_size;字符*缓冲=(字符*)malloc的(PACKET_SIZE);
字符*包=(字符*)malloc的(PACKET_SIZE);如果(!包){
    PERROR(内存不足);
    接近(的sockfd);
    返回(0);
}// IP报头
结构iphdr * IP =(结构iphdr *)包;
//结构icmphdr * ICMP =(结构icmphdr *)(包+的sizeof(结构iphdr));
结构icmp_header * icmphdr =(结构icmp_header *)(包+的sizeof(结构iphdr));
//零出数据包缓冲区
memset的(分组,0,PACKET_SIZE);
memset的(缓冲液,0,PACKET_SIZE);IP->版本= 4;
IP->国际人道法= 5;
IP-> TOS = 0;
IP-> tot_len = htons(PACKET_SIZE);
IP-和SEQ ID = RAND();
IP-> frag_off = 0;
IP-> TTL = 255;
IP->协议IPPROTO_ICMP =;
IP-> SADDR SADDR =;
IP-> DADDR = DADDR;
// IP-GT&;检查= in_cksum((U16 *)IP,的sizeof(结构iphdr));// icmp->类型= ICMP_ECHO标志意义echo请求
// icmp-> code = 0 E IL codice代echo请求
icmphdr->类型= ICMP_ECHO;
icmphdr-> code = 0;
icmphdr-> n = 5;
icmphdr->序列= 66;
//校验
icmphdr->校验= 0;结构SOCKADDR_IN servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = DADDR;
memset的(安培; servaddr.sin_zero,0,sizeof的(servaddr.sin_zero));看跌期权(泛滥......);//而(1)
而(c取代; 0){
    memset的(包+的sizeof(结构iphdr)+的sizeof(结构icmp_header),兰特()%255,payload_size);
    // memset的(缓冲区+的sizeof(结构iphdr)+的sizeof(结构icmphdr),兰特()%255,payload_size);    //重新计算ICMP报头校验和,因为我们填充每次随机字符有效载荷
    icmphdr->校验= 0;
    icmphdr->校验= in_cksum((无符号短*)icmphdr,sizeof的(结构icmp_header)+ payload_size);    如果((sent_size = SENDTO(的sockfd,分组,PACKET_SIZE,0,(结构sockaddr *)及servaddr,sizeof的(servaddr)))≤; 1){
        PERROR(发送失败\\ n);
        打破;
    }
    ++发送;
    (发送%d个包\\ r,即发送)printf的;
    fflush(标准输出);    LS = sizeof的(servaddr);
    // RF = recvfrom的(的sockfd,缓冲液,42,0,(结构sockaddr *)及servaddr,&放大器; LS);
RF = recvfrom的(的sockfd,缓冲器,PACKET_SIZE,0,(结构sockaddr *)及servaddr,&放大器; LS);
    如果(RF℃下){
       PERROR(Errore recvfrom的\\ n);
       打破;
    }
    其他{
       字符* CP;
       结构iphdr * ip_reply =(结构iphdr *)缓冲区;
       CP =(字符*)及ip_reply-> SADDR;
   的printf(收到%d个字节的答复从%U%U%U%U:。\\ n,还有ntohs(ip_reply-> tot_len),CP [0]放大器; 0xFF的,CP [1]安培; 0xFF的, CP [2]&放大器; 0xff的,CP [3]&放大器; 0xff的);
       的printf(ID数:%d \\ n,还有ntohs(ip_reply-> ID));
       的printf(TTL数:%d \\ n,ip_reply-> TTL);
    }
    usleep(10000); //微秒
    C - ;
}
免费(缓冲);
免费(包);
接近(的sockfd);
返回(0);
}/ *
函数计算校验和
* /
无符号短in_cksum(无符号短* PTR,诠释为nbytes){
注册长总和;
u_short oddbyte;
注册u_short的答案;总和= 0;
而(为nbytes→1){
    总和+ = * PTR ++;
    为nbytes - = 2;
}如果(为nbytes == 1){
    oddbyte = 0;
    *((u_char *)及oddbyte)= *(u_char *)ptr;可
    总和+ = oddbyte;
}总和=(总和>> 16)+(SUM&安培; 0xFFFF的);
总和+ =(总和>> 16);
回答=〜总和;返回(答案);
}


解决方案

答案。
好吧,我解决了问题。我创建自定义的ICMP报头unsigned char型数组作为有效载荷(在本例收费)。我用这个阵列,在服务器端,将数据存储在这种方式搜索
的memcpy(工资,(无符号字符*)及icmp-> ID,2); //我在这里存储传入ICMP回应请求ID

然后我prepare发送缓冲区

 结构eth_frame * eths =(结构eth_frame *)缓冲区;
crea_eth(eths,为0x0800,mactarget); //创建ETH框架
结构ip_datagram * IPS =(结构ip_datagram *)eths->有效载荷;
结构icmp_packet * icmps =(结构icmp_packet *)IPS-GT和有效载荷;

然后,我创建自定义的ICMP应答和自定义IP数据包,我必须从服务器发送给客户端

 的memcpy(icmps->有效载荷,和放大器;支付,10);
icmps->类型= 0;
icmps-> code = 0;
icmps->校验= 0;
icmps-> ID =(icmp-> ID); //我用同一接收ICMP ID
icmps->序列= htons(1);
icmps->校验= //计算校验和IPS-GT&; ver_ihl =×45;
IPS-GT&; TOS = 0×00;
IPS-> totlen = htons(20 + 8 + 8);
IPS-和SEQ ID = 0xABCD;
IPS-> flags_offs = 0;
IPS-GT&; TTL = 255;
IPS-GT&;原= IPPROTO_ICMP;
IPS-GT&;校验= 0;
IPS-GT&; SRC = *(unsigned int类型*)SERVERIP;
IPS-GT&; DST = *(unsigned int类型*)clientip; //使用的客户机IP地址​​PUBLIC填写!
IPS-GT&;校验= htons(calcola_checksum((无符号字符*)IPS,20));

再从服务器发送ICMP数据包到客户端

 无符号的char * p =(无符号字符*)及地址;
对于(i = 0; I<的sizeof(结构sockaddr_ll);我++)
   P [I] = 0;
addr.sll_family = AF_PACKET;
addr.sll_ifindex = 3;
/*发给*/
N = SENDTO(S,缓冲液,14 + 20 + 8 + 13,0,(结构sockaddr *)及地址,sizeof的(地址));

I have to write c program that send ICMP ECHO REQUEST from phone(it is connected by Mobile isp and it is behind NAT)to server with IP PUBLIC. i wrote a simple program that sends echo request and receives echo reply but now i want to send ECHO REQUEST from client to server and receive ECHO REPLY with some data(an IP PUBLIC and ICMP ID) from server to client. How can i make that?

Herre's my code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

typedef unsigned char u8;
typedef unsigned short int u16;

struct icmp_header{
   unsigned char type;
   unsigned char code;
   unsigned short checksum;
   unsigned short id;
   unsigned short seq;
};

unsigned short in_cksum(unsigned short *ptr, int nbytes);    

int main(int argc, char **argv){
int c=100;
int ls;//lunghezza struct sockaddr_in serveraddr
int rf;//receive from    

unsigned long daddr;
unsigned long saddr;
int payload_size = 0, sent = 0, sent_size;

saddr = inet_addr("IP PRIVATE");
daddr = inet_addr("IP PUBLIC");

//Raw socket - if you use IPPROTO_ICMP, then kernel will fill in the correct ICMP header checksum, if IPPROTO_RAW, then it wont
int sockfd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);

if (sockfd < 0){
    perror("could not create socket");
    return (0);
}

int on = 1;

// We shall provide IP headers
if (setsockopt (sockfd, IPPROTO_IP, IP_HDRINCL, (const char*)&on, sizeof (on)) == -1){
    perror("setsockopt");
    return (0);
}

//allow socket to send datagrams to broadcast addresses
if (setsockopt (sockfd, SOL_SOCKET, SO_BROADCAST, (const char*)&on, sizeof (on)) == -1){
    perror("setsockopt");
    return (0);
}   

//Calculate total packet size
int packet_size = sizeof (struct iphdr) + sizeof (struct icmp_header) + payload_size;

char *buffer = (char *) malloc (packet_size);   
char *packet = (char *) malloc (packet_size);    

if (!packet){
    perror("out of memory");
    close(sockfd);
    return (0);
}

//ip header
struct iphdr *ip = (struct iphdr *) packet;
//struct icmphdr *icmp = (struct icmphdr *) (packet + sizeof (struct iphdr));
struct icmp_header *icmphdr = (struct icmp_header *) (packet + sizeof(struct iphdr)); 
//zero out the packet buffer
memset (packet, 0, packet_size);
memset (buffer, 0, packet_size);

ip->version = 4;
ip->ihl = 5;
ip->tos = 0;
ip->tot_len = htons (packet_size);
ip->id = rand ();
ip->frag_off = 0;
ip->ttl = 255;
ip->protocol = IPPROTO_ICMP;
ip->saddr = saddr;
ip->daddr = daddr;
//ip->check = in_cksum ((u16 *) ip, sizeof (struct iphdr));

//icmp->type = ICMP_ECHO significa ECHO REQUEST
//icmp->code = 0 è il codice dei ECHO REQUEST
icmphdr->type = ICMP_ECHO;
icmphdr->code = 0;
icmphdr->id = 5;
icmphdr->seq = 66;
//checksum
icmphdr->checksum = 0;

struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = daddr;
memset(&servaddr.sin_zero, 0, sizeof (servaddr.sin_zero));

puts("flooding...");

//while (1)
while(c>0){
    memset(packet + sizeof(struct iphdr) + sizeof(struct icmp_header), rand() % 255, payload_size);
    //memset(buffer + sizeof(struct iphdr) + sizeof(struct icmphdr), rand() % 255, payload_size);

    //recalculate the icmp header checksum since we are filling the payload with random characters everytime
    icmphdr->checksum = 0;
    icmphdr->checksum = in_cksum((unsigned short *)icmphdr, sizeof(struct icmp_header) + payload_size);

    if ( (sent_size = sendto(sockfd, packet, packet_size, 0, (struct sockaddr*) &servaddr, sizeof (servaddr))) < 1){
        perror("send failed\n");
        break;
    }
    ++sent;
    printf("%d packets sent\r", sent);
    fflush(stdout);

    ls = sizeof(servaddr);
    //rf = recvfrom(sockfd, buffer, 42, 0, (struct sockaddr *)&servaddr, &ls);
rf = recvfrom(sockfd, buffer, packet_size, 0, (struct sockaddr *)&servaddr, &ls);
    if(rf < 0){
       perror("Errore recvfrom\n");
       break;
    }
    else{
       char *cp;
       struct iphdr *ip_reply = (struct iphdr *)buffer;
       cp = (char *)&ip_reply->saddr;
   printf("Received %d byte reply from %u.%u.%u.%u:\n", ntohs(ip_reply->tot_len), cp[0]&0xff,cp[1]&0xff,cp[2]&0xff,cp[3]&0xff);
       printf("ID: %d\n", ntohs(ip_reply->id));
       printf("TTL: %d\n", ip_reply->ttl);
    }         
    usleep(10000);  //microseconds
    c--;
}    
free (buffer); 
free(packet);
close(sockfd);     
return (0);
}

/*
Function calculate checksum
*/
unsigned short in_cksum(unsigned short *ptr, int nbytes){
register long sum;
u_short oddbyte;
register u_short answer;

sum = 0;
while (nbytes > 1) {
    sum += *ptr++;
    nbytes -= 2;
}

if (nbytes == 1) {
    oddbyte = 0;
    *((u_char *) & oddbyte) = *(u_char *) ptr;
    sum += oddbyte;
}

sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;

return (answer);
}

解决方案

ANSWER. Ok, i solve problem. I create custom icmp header with unsigned char array as payload (pay in this example). i use this array, in server side, to store data in this way
memcpy(pay, (unsigned char *)&icmp->id, 2); //here i store incoming icmp echo request id.

Then i prepare sending buffer

struct eth_frame *eths = (struct eth_frame *) buffer;
crea_eth(eths,0x0800,mactarget);//create eth frame
struct ip_datagram *ips = (struct ip_datagram*) eths->payload;
struct icmp_packet *icmps = (struct icmp_packet*) ips->payload;

Then i build custom icmp echo reply and custom ip packet that i have to send from server to client

memcpy(icmps->payload, &pay, 10);
icmps->type = 0;
icmps->code = 0;
icmps->checksum = 0;
icmps->id = (icmp->id);//i use same receiving icmp id
icmps->seq = htons(1);                          
icmps->checksum = //calculate checksum

ips->ver_ihl = 0x45;
ips->tos = 0x00;
ips->totlen = htons(20 + 8 + 8);
ips->id = 0xABCD;
ips->flags_offs = 0;
ips->ttl = 255;
ips->proto = IPPROTO_ICMP;
ips->checksum = 0;
ips->src = *(unsigned int *)serverip;
ips->dst = *(unsigned int *)clientip;//fill with IP PUBLIC ADDRESS OF CLIENT!!
ips->checksum = htons(calcola_checksum((unsigned char*)ips,20));

Then send icmp packet from server to client

unsigned char *p = (unsigned char *)&addr;
for(i = 0;i < sizeof(struct sockaddr_ll);i++)
   p[i] = 0;
addr.sll_family = AF_PACKET;
addr.sll_ifindex = 3;
/*send to*/
n=sendto(s, buffer, 14 + 20 + 8 + 8 , 0 , (struct sockaddr*) &addr , sizeof(addr));

这篇关于得到的数据ECHO REPLY从服务器到NAT后面的客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆