【问题标题】:how to sniff all ICMP packets using RAW sockets如何使用 RAW 套接字嗅探所有 ICMP 数据包
【发布时间】:2013-01-28 01:10:18
【问题描述】:

我正在学习 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

【问题讨论】:

  • 您正在打印 buf%s 可能是您在 60 个字节内得到一些空字符串。你从客户那里寄来了什么?我可以在这里找到错误
  • @GrijeshChauhan 我只是通过 ping 到 eth0 来生成一些 ICMP 消息。

标签: c linux sockets raw-sockets


【解决方案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 (echo request) 和 msgtype 0 (echo reply)。请注意,当以这种方式从数组访问数据时,您可能会遇到对齐问题(x86/x64 很乐意为您处理它,但其他架构可能不会那么慷慨)。我将把它作为练习留给读者;)。

【讨论】:

  • 当我 ping 到 8.8.8.8 或任何远程 ip 时,此代码不会输出 ping 请求数据包,而只会输出来自 8.8.8.8 的 ping 回复数据包
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
  • 1970-01-01
  • 1970-01-01
  • 2016-05-14
  • 1970-01-01
  • 2020-02-22
相关资源
最近更新 更多