如何使用RAW插槽嗅出所有的ICMP数据包 [英] how to sniff all ICMP packets using RAW sockets

查看:188
本文介绍了如何使用RAW插槽嗅出所有的ICMP数据包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我学习RAW插槽。在下面的code我试图打印所有的ICMP报文标题的信息。貌似在code一些错误。任何人都可以请帮我在哪里我错了。

 #包括LT&;&unistd.h中GT;
#包括LT&; SYS / socket.h中>
#包括LT&; SYS / types.h中>
#包括LT&;&string.h中GT;
#包括LT&; netinet / in.h中>
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;主要(){
INT的sockfd,RETVAL,N;
socklen_t的clilen;
结构SOCKADDR_IN cliaddr,servaddr;
焦炭BUF [10000]的sockfd =插座(AF_INET,SOCK_RAW,IPPROTO_ICMP);
如果(的sockfd℃,){
    PERROR(袜子);
    出口(1);
}
clilen = sizeof的(结构SOCKADDR_IN);
而(1){
    的printf(recvfrom的之前\\ n);
    N = recvfrom的(的sockfd,BUF,10000,0,(结构sockaddr *)及cliaddr,&安培; clilen);
    的printf(REC'D%d字节\\ N,N);
    BUF [N] ='\\ 0';
    的printf(,BUF从客户=%s的\\ n消息);
}
}O / Precvfrom的前
REC'D 60个字节
味精从客户= E
recvfrom的前
REC'D 52个字节


解决方案

您要打印原始数据包数据(包括标题),作为一个字符串。在这种情况下,电子这是ASCII ×45 是IP报头的第一个字节。的高4位表示IPv4的和低4位是IHL(编号的IP报头中的32位字),其是5 * 4 = 20个字节。

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

 #包括LT&;&unistd.h中GT;
#包括LT&; SYS / socket.h中>
#包括LT&; SYS / types.h中>
#包括LT&;&string.h中GT;
#包括LT&; netinet / in.h中>
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;#包括LT&; netinet / ip.h>
#包括LT&; netinet / ip_icmp.h>主要(){
  INT的sockfd,RETVAL,N;
  socklen_t的clilen;
  结构SOCKADDR_IN cliaddr,servaddr;
  焦炭BUF [10000]
  INT I;  的sockfd =插座(AF_INET,SOCK_RAW,IPPROTO_ICMP);
  如果(的sockfd℃,){
    PERROR(袜子);
    出口(1);
  }
  clilen = sizeof的(结构SOCKADDR_IN);
  而(1){
    的printf(recvfrom的之前\\ n);
    N = recvfrom的(的sockfd,BUF,10000,0,(结构sockaddr *)及cliaddr,&安培; clilen);
    的printf(REC'D%d字节\\ N,N);    结构iphdr * ip_hdr =(结构iphdr *)BUF;    的printf(IP报头为%d字节\\ n,ip_hdr->国际人道法* 4);    对于(i = 0; I< N;我++){
      的printf(%02X%的,(uint8_t有)的buf [I]中,第(i + 1)%16:吗?\\ n);
    }
    的printf(\\ n);    结构icmphdr * icmp_hdr =(结构icmphdr *)((字符*)ip_hdr +(4 * ip_hdr-> IHL));    的printf(ICMP MSGTYPE =%d个,code =%d个,icmp_hdr->类型,icmp_hdr-> code);
  }
}

现在,如果我运行和平127.0.0.1 :你看到这样的输出:

  recvfrom的前
 REC'D 84字节
IP报头是20个字节。
45 00 00 54 00 00 40 0​​0 40 0​​1 3C A7 7F 00 00 01
7F 00 00 01 08 00 A9 DF 11 66 00 01 77 9A 51 1A
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信息类型= 8,code = 0 recvfrom的前
 REC'D 84字节
IP报头是20个字节。
45 00 00 54 8D F3 00 00 40 0​​1 EE B3 7F 00 00 01
7F 00 00 01 00 00 B1 DF 11 66 00 01 77 9A 51 1A
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 recvfrom的前

下面这显示了MSGTYPE 8(echo请求)和MSGTYPE 0(回送应答)。要注意的是从一个数组访问数据时,这种方式,您可以运行到对齐的问题(在x86 / x64很高兴能为您处理,但其他架构可能不会这么大方)。我会离开,作为一个练习留给读者。)

I am learning RAW sockets. In the below code i am trying to print all ICMP packets headers information. Looks like some error in the code. Can anyone please help me where i am wrong.

# 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

解决方案

You are trying to print raw packet data (including headers) as a string. In this case, E which is ascii 0x45 is the first byte of the IP header. The upper 4 bits mean "IPv4" and the lower 4 bits is the IHL (number of 32-bit words in the IP header) which is 5*4 = 20 bytes.

To properly access this data you should use the IP/ICMP header structs provided by linux. I've updated your code a little to illustrate:

# 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);
  }
}

Now, if I run that and ping 127.0.0.1: you see output like this:

 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

Here this shows a msgtype 8 (echo request) and msgtype 0 (echo reply). Beware that when accessing data this way from an array you can run into alignment problems (x86/x64 are happy to handle it for you, but other architectures may not be so generous). I'll leave that as an exercise to the reader ;).

这篇关于如何使用RAW插槽嗅出所有的ICMP数据包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆