如何使用RAW插槽嗅出所有的ICMP数据包(how to sniff all ICMP packet

2019-08-16 22:23发布

我学习RAW插槽。 在下面的代码我试图打印所有的ICMP数据包报头信息。 看起来像在代码中的一些错误。 任何人都可以请帮我在哪里,我错了。

# include <unistd.h>
# include <sys/socket.h>
# include <sys/types.h>
# include <string.h>
# include <netinet/in.h>
# include <stdio.h>
# include<stdlib.h>

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

Answer 1:

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

要正确地访问这些数据,你应该使用Linux所提供的IP / ICMP报头结构。 我已经更新了你的代码一点来说明:

# include <unistd.h>
# include <sys/socket.h>
# include <sys/types.h>
# include <string.h>
# include <netinet/in.h>
# include <stdio.h>
# include<stdlib.h>

#include <netinet/ip.h>
#include <netinet/ip_icmp.h>

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(回声请求)和MSGTYPE 0(回波答复)。 要注意的是从一个数组访问数据时,这种方式可以运行到对齐的问题(在x86 / x64很高兴为您处理,但其他架构可能不会这么大方)。 我会离开,作为一个练习留给读者)。



文章来源: how to sniff all ICMP packets using RAW sockets