Using libpcap to capture packets under Linux

Keywords: C++ Linux

1. Background

Learning PF_ During ring, it is found that libpcap is overloaded. So back to basics, I learned the pcap packet capturing principle again.

2. Relevant knowledge

2.1 principle

This article is very clear< libpcap implementation mechanism and interface function>

The packet capture mechanism implemented here is to add a bypass processing in the data link layer, which does not interfere with the processing of the system's own network protocol stack. The transmitted and received packets are filtered and buffered through the Linux kernel, and finally directly transmitted to the upper application. Therefore, libpcap bypasses the traditional Linux protocol stack processing after capturing the packets arriving at the network card The link layer PF_PACKET protocol family transmits messages to the user space in the original socket mode.

2.2 common interfaces

  • pcap_lookupdev(): the function is used to find the network device and return the pointer of the network device name that can be called by pcap_open_live() function.
  • pcap_lookupnet(): the function obtains the network number and mask of the specified network device.
  • pcap_open_live(): the function is used to open the network device and return the packet capture descriptor used to capture the network packet. All operations on this network device should be based on this network device descriptor.
  • pcap_compile(): the function is used to compile the filter policy formulated by the user into the filter program. pcap_setfilter(): the function is used to set the filter.
  • pcap_loop(): the pcap_dispatch() function is used to capture data packets and process them after capture. In addition, pcap_next() and pcap_next_ex() functions can also be used to capture data packets.
  • pcap_close(): this function is used to close network devices and release resources.

2.3 programming ideas

Open network device > set filtering rules > capture data > user status processing > close network device

3. Simple example

class mod_pcap() directly implements three axe functions in the style of class: setup, dispatch and teardown.

#ifndef  _MOD_PCAP_H_
#define  _MOD_PCAP_H_

#include <pcap/pcap.h>
#include <string>

class mod_pcap
{
private:
    std::string _dev;
    pcap_t *_pcap = NULL;

    int _c_snaplen = 64 * SIZE_KB;
    int _c_promisc = 0;
    int _c_to_ms   = 100;
    char _errbuf[PCAP_ERRBUF_SIZE] = {0};

public:
    ~mod_pcap()
    {
        teardown();
    }

    int setup(const std::string &dev,
              const std::string &filter)
    {
        int res = -1;
        struct bpf_program fp;

        _dev = dev;
        _pcap = pcap_open_live(dev.c_str(), _c_snaplen, _c_promisc, _c_to_ms, _errbuf);
        if (!_pcap) {
            printf("pcap_open_live: %s, [%s]\n", dev.c_str(), _errbuf);
            return -1;
        }

        res = pcap_compile(_pcap, &fp, filter.c_str(), 0, PCAP_NETMASK_UNKNOWN);
        if (0 != res) {
            printf("pcap_compile: %s, [%s]\n", filter.c_str(), _errbuf);
            return -1;
        }
        printf("pcap_compile: %s, %s\n", dev.c_str(), filter.c_str());

        res = pcap_setfilter(_pcap, &fp);
        if (0 != res) {
            printf("pcap_setfilter\n");
            return -1;
        }
        return 0;
    }

    int dispatch(pcap_handler cb, uint8_t *args)
    {
        return pcap_loop(_pcap, 0, cb, args);
    }

    void teardown()
    {
        if (_pcap) {
            (void)pcap_close(_pcap);
            _pcap = NULL;
        }
    }
};

#endif // #ifndef _MOD_PCAP_H_

The main function uses this interface to grab UDP messages on eth0 and print the grab length:

#include "mod_pcap.h"

static void on_handle_pkt(uint8_t *args, const struct pcap_pkthdr *ph, const uint8_t *sp)
{
    printf("Capture: %u, len: %u\n", ph->caplen, ph->len);
}

int main(int argc, char *argv[])
{
    class mod_pcap pcap;

    if (pcap.setup("eth0", "udp") == 0) {
        pcap.dispatch(on_handle_pkt, NULL);
        pcap.teardown();
    }

    exit(EXIT_SUCCESS);
}

4. Result analysis

The experimental results are as follows:
1. Use iperf tool to open 1KB payload, smaller than MTU:

Capture: 1066, len: 1066
Capture: 1066, len: 1066
Capture: 1066, len: 1066
Capture: 1066, len: 1066
Capture: 1066, len: 1066
Capture: 1066, len: 1066
Capture: 1066, len: 1066
Capture: 1066, len: 1066
Capture: 1066, len: 1066
Capture: 1066, len: 1066
Capture: 1066, len: 1066
Capture: 1066, len: 1066

2. Use iperf tool to open 8KB payload, which is larger than MTU. libpcap is captured by data frame:

Capture: 1514, len: 1514
Capture: 1514, len: 1514
Capture: 1514, len: 1514
Capture: 1514, len: 1514
Capture: 1514, len: 1514
Capture: 834, len: 834
Capture: 1514, len: 1514
Capture: 1514, len: 1514
Capture: 1514, len: 1514
Capture: 1514, len: 1514
Capture: 1514, len: 1514
Capture: 834, len: 834
Capture: 1514, len: 1514
Capture: 1514, len: 1514
Capture: 1514, len: 1514
Capture: 1514, len: 1514
Capture: 1514, len: 1514
Capture: 834, len: 834

5. Summary

This article provides a demo for quick start-up testing, which is convenient for everyone to understand the effect of libpcap packet capturing.

Posted by Coreye on Mon, 11 Oct 2021 12:18:42 -0700