2013-02-12 67 views
1

我正在学习RAW套接字。在下面的代码中,我试图打印所有的ICMP数据包标题信息。看起来像代码中的一些错误。任何人都可以帮助我,我错了。如何使用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 
+0

您正在用'%s'打印'buf',可能是您在60个字节内获得了一些空字符串。你从客户那里寄出了什么?我可以在这里找到错误 – 2013-02-12 16:49:28

+0

@GrijeshChauhan我只是通过ping到eth0来生成一些ICMP消息。 – Goutham 2013-02-12 16:51:43

回答

7

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

要正确地访问这些数据,你应该使用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 

这里这显示了信息类型8(echo请求)和msgtype 0(回应回复)。请注意,当从数组中以这种方式访问​​数据时,您可能遇到对齐问题(x86/x64很乐意为您处理,但其他体系结构可能并不那么慷慨)。我将把它作为练习给读者;)。