2016-06-12 10 views
0

IP PUBLIC을 사용하는 서버에 전화 (ICMP에 의해 연결되어 있으며 NAT 뒤에 있음)에서 ICMP ECHO REQUEST를 보내는 C 프로그램을 작성해야합니다. 에코 요청을 보내고 반향 응답을받는 간단한 프로그램을 작성했지만 이제 클라이언트에서 서버로 에코 요청을 보내고 서버 (클라이언트)와 클라이언트 (서버)에 데이터 (IP PUBLIC 및 ICMP ID)가있는 에코 응답을 보내려고합니다. 내가 어떻게 만들 수 있니?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를 반환합니다. 나는 에코 요청을 서버에 보내고 (서버로부터), IP 공개 주소와 두 개의 숫자 같은 데이터를 포함하는 에코 응답을 어떻게받을 수 있는지 알고 싶다. – EmanueleRiso

+0

먼저 서버에서'sysctl'를 사용하여 핑 응답을 비활성화해야한다. 그렇다면 그것은 쉬운 일입니다. 코드를 형식화하고 서버 측의 코드를 제공하십시오. – jfly

답변

0

답변. 좋아, 문제는 해결된다. 페이로드로 unsigned char 어레이가있는 사용자 지정 icmp 헤더를 만듭니다 (이 예제에서는 지불). 서버 측에서이 배열을 사용하여 데이터를이 방식으로 저장합니다.
memcpy(pay, (unsigned char *)&icmp->id, 2); //here i store incoming icmp echo request id.

그럼 난

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 패킷을 전송

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; 

그런 다음 내가 서버에서 클라이언트로 보내야 할 사용자 정의 ICMP 에코 응답 및 사용자의 IP 패킷을 구축 버퍼 전송 준비 고객

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