如何使用RAW套接字嗅探所有ICMP数据包

我正在学习RAW套接字。 在下面的代码中,我试图打印所有ICMP数据包标头信息。 看起来代码中有些错误。 任何人都可以帮助我,我错了。

# include  # include  # include  # include  # include  # include  # include main(){ int sockfd,retval,n; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; char buf[10000]; sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (sockfd < 0){ perror("sock:"); exit(1); } clilen = sizeof(struct sockaddr_in); while(1){ printf(" before recvfrom\n"); n=recvfrom(sockfd,buf,10000,0,(struct sockaddr *)&cliaddr,&clilen); printf(" rec'd %d bytes\n",n); buf[n]='\0'; printf(" msg from client = %s\n",buf); } } o/p before recvfrom rec'd 60 bytes msg from client = E before recvfrom rec'd 52 bytes 

您正在尝试将原始数据包数据(包括标头)打印为字符串。 在这种情况下,ascii 0x45 E是IP头的第一个字节。 高4位表示“IPv4”,低4位表示IHL(IP报头中32位字的数量),即5 * 4 = 20字节。

要正确访问此数据,您应该使用linux提供的IP / ICMP头结构。 我稍微更新了你的代码来说明:

 # include  # include  # include  # include  # include  # include  # include #include  #include  main(){ int sockfd,retval,n; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; char buf[10000]; int i; sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (sockfd < 0){ perror("sock:"); exit(1); } clilen = sizeof(struct sockaddr_in); while(1){ printf(" before recvfrom\n"); n=recvfrom(sockfd,buf,10000,0,(struct sockaddr *)&cliaddr,&clilen); printf(" rec'd %d bytes\n",n); struct iphdr *ip_hdr = (struct iphdr *)buf; printf("IP header is %d bytes.\n", ip_hdr->ihl*4); for (i = 0; i < n; i++) { printf("%02X%s", (uint8_t)buf[i], (i + 1)%16 ? " " : "\n"); } printf("\n"); struct icmphdr *icmp_hdr = (struct icmphdr *)((char *)ip_hdr + (4 * ip_hdr->ihl)); printf("ICMP msgtype=%d, code=%d", icmp_hdr->type, icmp_hdr->code); } } 

现在,如果我运行并ping 127.0.0.1 :您会看到如下输出:

  before recvfrom rec'd 84 bytes IP header is 20 bytes. 45 00 00 54 00 00 40 00 40 01 3C A7 7F 00 00 01 7F 00 00 01 08 00 A9 DF 11 66 00 01 9A 77 1A 51 00 00 00 00 BA 1D 0F 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 ICMP msgtype=8, code=0 before recvfrom rec'd 84 bytes IP header is 20 bytes. 45 00 00 54 8D F3 00 00 40 01 EE B3 7F 00 00 01 7F 00 00 01 00 00 B1 DF 11 66 00 01 9A 77 1A 51 00 00 00 00 BA 1D 0F 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 ICMP msgtype=0, code=0 before recvfrom 

这里显示了msgtype 8(echo请求)和msgtype 0(echo reply)。 请注意,当从arrays以这种方式访问​​数据时,您可能遇到对齐问题(x86 / x64很乐意为您处理它,但其他架构可能不那么慷慨)。 我将把它作为练习留给读者;)。