为啥打开wireshark抓包时没有发送ICMP ping请求?

Posted

技术标签:

【中文标题】为啥打开wireshark抓包时没有发送ICMP ping请求?【英文标题】:Why there are no ICMP ping requests sent when wireshark packet capture is opened?为什么打开wireshark抓包时没有发送ICMP ping请求? 【发布时间】:2019-05-23 23:38:40 【问题描述】:

总结:raw socket中的sendto api没有报错但是wireshark抓包中没有发送ICMP包。

我是原始套接字编程的新手,并试图从头开始创建 ICMP ping 数据包。我成功地创建了一个 ping 程序:https://www.geeksforgeeks.org/ping-in-c/ 但现在我希望自己构建以太网头,即从头开始所有数据包头。我确实按照以下方式编写了程序:https://opensourceforu.com/2015/03/a-guide-to-using-raw-sockets/ 但是当我运行它并使用 tcpdump 捕获数据包传输并使用 Wireshark 分析它时,我发现没有发送 ICMP 数据包,尽管根据我的编程逻辑我的数据包已成功发送(因为 sendto api 不报告任何错误)。我附上代码,任何帮助将不胜感激。

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h> 
#include <netinet/ip_icmp.h> 
#include <time.h> 
#include <fcntl.h> 
#include <signal.h> 
#include <time.h> 
#include <string.h>
#include <netinet/if_ether.h> 
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <sys/ioctl.h>


#define PING_PKT_S 64 
#define PORT_NO 0 
#define PING_SLEEP_RATE 1000000 
#define RECV_TIMEOUT 1 

int pingloop=1; 

struct ping_pkt 

   struct ethhdr eth; 
   struct ip ip;    
   struct icmphdr hdr; 
   char msg[PING_PKT_S-sizeof(struct icmphdr)]; 
g_pckt; 


typedef struct ping_ctx
int tos;
int ttl;
char srcIP[200];
char dstIP[200];
int r_sock;
ping_ctx;

unsigned short checksum(void *b, int len) 

unsigned short *buf = b; 
unsigned int sum=0; 
unsigned short result; 

for ( sum = 0; len > 1; len -= 2 ) 
    sum += *buf++; 
if ( len == 1 ) 
    sum += *(unsigned char*)buf; 
sum = (sum >> 16) + (sum & 0xFFFF); 
sum += (sum >> 16); 
result = ~sum; 
return result; 
 

  void intHandler(int dummy) 
   
pingloop=0; 
   

  void fill_ip_h(struct ip *ip, ping_ctx* ctx)
  
    ip->ip_src.s_addr = inet_addr(ctx->srcIP);
    ip->ip_dst.s_addr = inet_addr(ctx->dstIP);
    ip->ip_v = 4;
    ip->ip_hl = sizeof*ip >> 2;
    ip->ip_tos = (unsigned char)(ctx->tos);
    ip->ip_len = htons(sizeof(g_pckt));
    ip->ip_id = htons(4321);
    ip->ip_off = htons(0);
    ip->ip_ttl = (unsigned char)(ctx->ttl);
    ip->ip_p = 1;
    ip->ip_sum = 0; /* Let kernel fills in */
  

  void fill_icmp_h(struct icmphdr* hdr,int *msg_count)
  
    hdr->type = ICMP_ECHO;
    hdr->un.echo.id = 1; 
    hdr->un.echo.sequence = (*msg_count)++; 
  

  void fill_data(unsigned char * data)
  
memset(data, 'J', PING_PKT_S-sizeof(struct icmphdr));
  

  void fill_eth(struct ethhdr* eth)
eth->h_source[0] = 0x08;
eth->h_source[1] = 0x00;
eth->h_source[2] = 0x27;
eth->h_source[3] = 0xe8;
eth->h_source[4] = 0xb5;
eth->h_source[5] = 0x12;
eth->h_dest[0] = 0x08;
eth->h_dest[1] = 0x00;
eth->h_dest[2] = 0x27;
eth->h_dest[3] = 0xe8;
eth->h_dest[4] = 0xb5;
eth->h_dest[5] = 0x12;
eth->h_proto = htons(ETH_P_IP);
  

void send_ping(ping_ctx* ctx)
 
    int  msg_count=0, i, addr_len, pkt_sent=1, 
    msg_received_count=0,on =1; 
    struct sockaddr_ll remote_addr; 
    struct ip *ip = NULL;
    struct icmphdr* icmph = NULL;
    unsigned  char* data = NULL;
    struct ethhdr* eth = NULL;
    struct sockaddr_ll r_addr; 
    struct timespec time_start, time_end, tfs, tfe; 
    long double rtt_msec=0, total_msec=0; 
    struct timeval tv_out;

/*Set params*/ 
char *to = ctx->dstIP;
char *from = ctx->srcIP;
int   ping_sockfd = ctx->r_sock;
int ttl = ctx->ttl;
int tos =ctx->tos;

/*Timer Settings*/
tv_out.tv_sec = RECV_TIMEOUT; 
tv_out.tv_usec = 0; 
clock_gettime(CLOCK_MONOTONIC, &tfs); 

//GET INTERFACE INDEX FOR INTERFACE enp0s3
/*struct ifreq ifr;
size_t if_name_len = strlen(if_name);
if(if_name_len<sizeof(ifr.ifr_name))
     memcpy(ifr.ifr_name,if_name,if_name_len);
     ifr.ifr_name[if_name_len]=0;

else
     die("Interface name is too long");

memset(&ifr,0,sizeof(ifr));
strncpy(ifr.ifr_name,enp0s3,IFNAMSIZ-1);
int fd = socket(AF_UNIX,SOCK_DGRAM,0);
if(fd==-1)
     printf("Error opening socket");
if(ioctl(fd,SIOCGIFINDEX,&ifr)==-1)
     printf("Error getting index name");
*/
//int ifindex = ifr.ifr_ifindex;
int ifindex = if_nametoindex("enp0s3");
printf("The interface number is : %d \n",ifindex);

remote_addr.sll_ifindex = ifindex;
remote_addr.sll_halen = ETH_ALEN;
remote_addr.sll_addr[0] = 0x08;
remote_addr.sll_addr[1] = 0x00;
remote_addr.sll_addr[2] = 0x27;
remote_addr.sll_addr[3] = 0xe8;
remote_addr.sll_addr[4] = 0xb5;
remote_addr.sll_addr[5] = 0x12;



if(setsockopt(ping_sockfd, SOL_SOCKET, SO_RCVTIMEO, 
            (const char*)&tv_out, sizeof tv_out) < 0)

    printf("Setting socket options failed for SO_RCVTIMEO\n");
    return;



/*if(setsockopt(ping_sockfd, IPPROTO_RAW, IP_HDRINCL, &on, sizeof(on)) < 0)

    printf("Setting socket options failed for IP_HDRINCL");
    return;
*/

while(pingloop) 
 
    pkt_sent=1; 
    memset(&g_pckt, 0, sizeof(g_pckt));

    /*ETHERNET Header*/
    eth = (struct ethhdr *)&g_pckt;
    fill_eth(eth);

    /*IP Header*/        
    ip = (struct ip *)(eth + 1); 
    fill_ip_h(ip, ctx);

    /*ICMP Header*/
    icmph = (struct icmphdr*)(ip + 1);
    fill_icmp_h(icmph, &msg_count); 

    /*Data*/
    data = (unsigned char *)(icmph + 1);
    fill_data(data);

    /*ICMP Checksum*/
    icmph->checksum = checksum(icmph, PING_PKT_S);

    usleep(PING_SLEEP_RATE); 

    /*TX*/ 
    clock_gettime(CLOCK_MONOTONIC, &time_start); 
    if ( sendto(ping_sockfd, &g_pckt, sizeof(g_pckt), 0, 
                (struct sockaddr*) &remote_addr, 
                sizeof(remote_addr)) <= 0) 
     
        printf("\nPacket Sending Failed!\n"); 
        pkt_sent=0; 
     

    /*RX*/ 
    /*addr_len=sizeof(r_addr); 

    if ( recvfrom(ping_sockfd, icmph, PING_PKT_S, 0, 
                (struct sockaddr*)&r_addr, &addr_len) <= 0 
            && msg_count>1) 
     
        printf("\nPacket receive failed!\n"); 
     */

    else
     
        clock_gettime(CLOCK_MONOTONIC, &time_end); 

        double timeElapsed = ((double)(time_end.tv_nsec - 
                    time_start.tv_nsec))/1000000.0; 
        rtt_msec = (time_end.tv_sec- 
                time_start.tv_sec) * 1000.0 
            + timeElapsed; 

        // if packet was not sent, don't receive 
        if(pkt_sent) 
         
            if(!(g_pckt.hdr.type ==69 && g_pckt.hdr.code==0)) 
             
                printf("Error..Packet received with ICMP" 
                        "type %d code %d\n", 
                        g_pckt.hdr.type, g_pckt.hdr.code); 
             
            else
             
                printf("%d bytes Received reply from %s: icmp_seq=:%d ttl=%d time=%Lf ms\n",PING_PKT_S, ctx->dstIP, msg_count, ctx->ttl, rtt_msec); 
                msg_received_count++; 
             
         
        
 
clock_gettime(CLOCK_MONOTONIC, &tfe); 
double timeElapsed = ((double)(tfe.tv_nsec - 
            tfs.tv_nsec))/1000000.0; 

total_msec = (tfe.tv_sec-tfs.tv_sec)*1000.0+ 
    timeElapsed ;

printf("\n%d packets sent, %d packets received, %f percent "
        "packet loss. Total time: %Lf ms.\n\n", 
        msg_count, msg_received_count, 
        ((msg_count - msg_received_count)/msg_count) * 100.0, 
        total_msec); 
 

int main(int argc, char *argv[]) 
 
ping_ctx ctx = 0;

if(argc!=3) 
 
    printf("sudo ./myping 10.117.157.6 10.39.51.117\n"); 
    return 0; 
 

signal(SIGINT, intHandler); 
ctx.r_sock = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); 
if(ctx.r_sock <0) 
 
    printf("\nSocket file descriptor not received\n"); 
    return 0; 
 

ctx.tos = 0;
ctx.ttl = 64;
strncpy(ctx.dstIP, argv[1],strlen(argv[1]));
strncpy(ctx.srcIP, argv[2],strlen(argv[2]));

send_ping(&ctx); 

return 0; 

当使用 tcpdump 捕获数据包并在 wireshark 中打开捕获时,看不到 ICMP 数据包。

【问题讨论】:

【参考方案1】:

您的以太网标头有一些错误填充。 我运行您的程序并使用wireshark 捕获一些错误的包。 您的程序可以发送包,但与 ICMP 协议不匹配。因此,如果您使用过滤器 ICMP,则不会捕获任何内容。以太网报头有一些错误导致后续协议(ICMP)无法解析。

//Wireshark capture packet like below
Linux cooked capture
    Packet type: Send by us (4)
    Link-layer address type: 1
    Link-layer address length: 6
    Source: PcsCompu_e8:b5:12(08:00:27:e8:b5:12)
    Unused: 0000
    Protocol: Unknown (0xd370)

【讨论】:

您好,感谢您的回答。您能否提供更多有关它的信息?比如到底填错了什么?我正在尝试做的是通过自己填充数据包向同一设备发送 ping 请求。【参考方案2】:

我终于弄清楚了代码的所有问题。好的,所以问题是 -

    目标 MAC 和源 MAC 不应该相同。 未提供 IP 校验和。

完整的解决方案是 - Why is the echo ping not reaching the destination?(如果对任何人有帮助)

【讨论】:

以上是关于为啥打开wireshark抓包时没有发送ICMP ping请求?的主要内容,如果未能解决你的问题,请参考以下文章

我用Wireshark抓包时过滤关键词用了http。 但是为啥我抓的包没有http协议,里面只有SSDP的协议。上个图

为啥fildder对app抓包时在手机上操作了单在fildder上没有反应

wireshark如何查看有多少个icmp包?我用虚拟机向物理机随机的发送了ping请求,我要怎么用wireshark查看?

网络报文抓包分析——ICMP

网络报文抓包分析——ICMP

wireshark抓包工具