cpingpcapbpflibnet

Decoding ICMPv4 packets with libpcap and libnet


My program captures packets from the wireless interface and I can view all human-readable bytes using a function similar to hexdump -C. For one, I can't crack the right syntax for the BPF string so all packets addressed to my machine are flooding in without filtration - except that I am not using promiscuous mode. Let's assume I do have the BPF string, since it will only complicate things further.

Since I only want ICMP echo replies, I run Wireshark and my program in parallel. I verify that the ICMP echo requests and replies are valid by inspecting the packets in Wireshark on the loopback interface. However, the program dumps header fields which cannot be ICMP echo replies and do not match with the valid packets that were seen in Wireshark.

Edit: I should note that pcap_hdl is listening on all devices; including the loopback interface for testing purposes.

pcap_t *pcap_hdl;
struct pcap_pkthdr cap_info;
const u_char *reply_pkt;
struct libnet_icmpv4_hdr *icmp_hd;
...
...
...

reply_pkt = pcap_next(pcap_hdl, &cap_info);
if(reply_pkt == NULL)
        printf("skipped - no response.\n");
else {
        icmp_hd = (struct libnet_icmpv4_hdr *) (reply_pkt + LIBNET_IPV4_H);
        dump((const unsigned char *) reply_pkt, cap_info.caplen);
        printf("%d bytes; icmp_seq=%d\n", cap_info.caplen, icmp_hd->icmp_seq);
}

When I send an ICMP Echo Request, I define the sequence number. It starts at 1, and an ICMP Echo Response shares that same sequence, it is the next ICMP Echo Request that is incremented. However, even without the BPF string I am able to minimise output by performing a useful check such that:

if(icmp_hd->icmp_type == ICMP_ECHO_REPLY)

If this is true, there is a strong possibility that the packet is an ICMP Echo Reply. An ICMP_ECHO_REPLY is equivalent to zero, and lots of packets contain null bytes so it is no guarantee. Nonetheless, this should allow me to identify ICMP Echo Replies a little easier. What I found was that the sequence number was usually over 10,000, even for packets that were similar sizes to what I observed in Wireshark.

Also, BPF strings I have tried are:


Solution

  • The filter icmp[icmptype] == icmp-echoreply should do the job, at least it works with tcpdump so it should work with libpcap as well. Tested it with the following command sudo tcpdump -i any "icmp[icmptype] == icmp-echoreply". No need to to specify that the IP protocol should be ICMP, it implicitly check for that when filtering on icmptype.