2016-06-12 9 views
0

Мне нужно написать программу c, которая отправляет ICMP ECHO REQUEST с телефона (она связана с Mobile isp и находится за NAT) на сервер с IP PUBLIC. Я написал простую программу, которая отправляет эхо-запрос и получает ответ эха, но теперь я хочу отправить ECHO REQUEST с клиента на сервер и получить ECHO REPLY с некоторыми данными (IP PUBLIC и ICMP ID) от сервера к клиенту. Как я могу это сделать?получить ECHO REPLY с данными от сервера к клиенту за nat

Herre в мой код

#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

Я не уверен, что я понимаю ваш вопрос? Совместимый код генерирует ошибку? – user590028

+0

мой код хороший, без предупреждения. в этом коде я отправляю ECHO REQUEST на сервер и возвращаю ECHO REPLY, без проблем. Я хочу знать, как я могу отправить ECHO REQUEST на сервер и вернуть обратно ECHO REPLY (с сервера), данные, такие как IP PUBLIC ADDRESS и два номера. – EmanueleRiso

+0

Вы должны отключить ответ ping с помощью 'sysctl' сначала на сервере. Тогда это непростая задача. Отформатируйте свой код и укажите код сервера. – jfly

ответ

0

ОТВЕТ. Хорошо, я решаю проблему. Я создаю собственный заголовок icmp с массивом unsigned char в качестве полезной нагрузки (оплата в этом примере). Я использую этот массив на стороне сервера, чтобы хранить данные таким образом.
.

Тогда я готовлю отправку буфера

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; 

Тогда я создавать собственные эха-ответ и пользовательский пакет Ip, что я должен послать от сервера к клиенту

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

Затем отправить ICMP-пакет от сервера клиент

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

 Смежные вопросы

  • Нет связанных вопросов^_^