2016-06-12 19 views
0

Ich muss c Programm schreiben, die ICMP ECHO REQUEST von Telefon senden (es ist durch Mobile ISP verbunden und es ist hinter NAT) zu Server mit IP PUBLIC. Ich schrieb ein einfaches Programm, das Echo-Anfrage sendet und Echo-Antwort empfängt, aber jetzt möchte ich ECHO REQUEST von Client zu Server senden und ECHO REPLY mit einigen Daten (eine IP PUBLIC und ICMP ID) von Server zu Client erhalten. Wie kann ich das machen?bekommen ECHO REPLY mit Daten vom Server zum Client hinter nat

Herres meinen 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); 
} 
+0

Ich bin mir nicht sicher, ob ich Ihre Frage verstehe? Erzeugt der Code, den Sie freigegeben haben, einen Fehler? – user590028

+0

mein Code ist gut, kein Fehler. In diesem Code sende ich ECHO REQUEST an Server und bekomme ECHO REPLY zurück, kein Problem. Ich möchte wissen, wie kann ich ECHO REQUEST an Server senden und ECHO REPLY (vom Server) mit Daten wie eine IP PUBLIC ADRESSE und zwei Nummer – EmanueleRiso

+0

zurück Sie sollten Ping-Antwort mit 'sysctl' zuerst auf dem Server deaktivieren. Dann ist es eine leichte Aufgabe. Formatieren Sie Ihren Code und geben Sie den Code der Serverseite ein. – jfly

Antwort

0

ANTWORT. Ok, ich löse das Problem. Ich erstelle benutzerdefinierte ICMP Header mit unsigned char Array als Nutzlast (in diesem Beispiel zahlen). Ich verwende dieses Array serverseitig, um Daten auf diese Weise zu speichern
memcpy(pay, (unsigned char *)&icmp->id, 2); //here i store incoming icmp echo request id.

Dann prepare Senden i Puffer

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; 

Dann bauen i benutzerdefinierte ICMP-Echo-Antwort und benutzerdefiniertes IP-Paket, das ich habe vom Server zum Client senden

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

Dann ICMP-Paket vom Server senden 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));