ICMP数据包已过时或格式错误

时间:2015-06-01 18:58:33

标签: sockets ping icmp

我正在尝试使用RAW套接字来创建ping程序。我编写的程序只适用于localhost(127.0.0.1),不适用于其他IP地址。在Wireshark中分析生成的数据包时,我收到一条消息“未知ICMP(过时或格式不正确?)”。它还告诉我 ICMP校验和不正确。我在这里发布我的代码

char source[20], destination[20];
struct sockaddr_in src, dst;
int addrlen= sizeof(src), recvSize, packetSize;
char *packet;
char *buffer;
struct iphdr* ip;
struct iphdr* ip_reply;
struct icmphdr* icmp;

unsigned short csum(unsigned short *, int);
char* getip();

int main(int argc, char* argv[]){

int pingSocket, optval;
struct protoent *protocol;


if(*(argv + 1) && (!(*(argv + 2)))){
    //only one argument provided,assume it is the destination server
    strncpy(destination, *(argv + 1), 15);
    strncpy(source, getip(), 15);
}

inet_pton(AF_INET, destination, &(dst.sin_addr));
inet_pton(AF_INET, source, &(src.sin_addr));


protocol= getprotobyname("ICMP");
printf("Protocol number for ICMP is %d\n",protocol->p_proto);
pingSocket= socket(AF_INET, SOCK_RAW, protocol->p_proto);       // Create socket
if(pingSocket< 0){
    perror("Error creating socket: ");
    exit(3);
}
printf("Socket created with identifier %d\n", pingSocket);

packetSize= sizeof(struct iphdr) + sizeof(struct icmphdr);

packet = (char *) malloc(packetSize);
buffer = (char *) malloc(packetSize);

ip= (struct iphdr*) packet;
icmp= (struct icmphdr*) (packet+ sizeof(struct iphdr));

memset(packet, 0, packetSize);

//Fill up the IP header
ip->ihl= 5;
ip->version= 4;
ip->tos= 0;
ip->tot_len = htons(packetSize);
ip->id = htons(0);
ip->frag_off= 0;
ip->ttl = 255;
ip->protocol= protocol->p_proto;
ip->saddr= src.sin_addr.s_addr;
ip->daddr= dst.sin_addr.s_addr;

setsockopt(pingSocket, protocol->p_proto, IP_HDRINCL, &optval, sizeof(int));    //HDRINCL to tell the kernel that the header is already included


icmp->type= ICMP_ECHO;
icmp->code= 0;
icmp->un.echo.id= rand();
icmp->un.echo.sequence= rand();
icmp->checksum= 0;
    icmp->checksum = csum((unsigned short *)icmp, sizeof(struct icmphdr));


dst.sin_family= AF_INET;

sendto(pingSocket, packet, packetSize, 0, (struct sockaddr *)&dst, sizeof(dst));
printf("Sent ping request with size %d to %s\n", ip->tot_len, destination);
printf("Request's IP ID: %d and IP TTL: %d\n", ip->id, ip->ttl);
printf("Packet: \n%s\n", packet);


// Wait for response
if( (recvSize= recvfrom(pingSocket, buffer, sizeof(struct iphdr)+sizeof(struct icmphdr), 0, (struct sockaddr *)&dst, &addrlen)) < 0){
    perror("Receive error: ");
}
else{
    printf("Received a reply from %s of size %d\n", destination, recvSize);
    ip_reply= (struct iphdr*) buffer;
    printf("Reply's IP ID: %d and IP TTL: %d\n", ip_reply->id, ip_reply->ttl);
}

free(packet);
free(buffer);
close(pingSocket);

return 0;
}
unsigned short csum(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);
}

char* getip()
{
char buffer[256];
struct hostent* h;

gethostname(buffer, 256);
h = gethostbyname(buffer);

return inet_ntoa(*(struct in_addr *)h->h_addr);

}

我读到有人通过首先将ICMP校验和设置为零然后计算它来修复此问题。然而,这对我不起作用。请帮帮我:))

0 个答案:

没有答案