得到的数据ECHO REPLY从服务器到NAT后面的客户端 [英] get ECHO REPLY with data from server to client behind 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屋!