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);
}
나는 당신의 질문을 이해하고 있습니까? 공유 한 코드에서 오류가 발생합니까? – user590028
내 코드가 좋고 오류가 없습니다. 이 코드에서는 ECHO REQUEST를 서버에 보내고 ECHO REPLY를 반환합니다. 나는 에코 요청을 서버에 보내고 (서버로부터), IP 공개 주소와 두 개의 숫자 같은 데이터를 포함하는 에코 응답을 어떻게받을 수 있는지 알고 싶다. – EmanueleRiso
먼저 서버에서'sysctl'를 사용하여 핑 응답을 비활성화해야한다. 그렇다면 그것은 쉬운 일입니다. 코드를 형식화하고 서버 측의 코드를 제공하십시오. – jfly