Reviving Net::Pcap

Tags:

... in which I look at how existing patches floating on the internet can be integrated into Net::Pcap to make it compile again.

Net::Pcap is dear to me, as I have a module implementing an HTTP sniffer using its network capture. So I like it when the module compiles without too much manual work.

Analysis

Net::Pcap only compiles with old versions of libpcap. Many distributions have a newer version of libpcap (1.9 onwards). RHEL7 still needs the old compilation, as it ships with libpcap 1.5.3. Libpcap 1.9 needs the new compilation declarations. There is a patch by Petr Pisar which I found via Slaven's distroprefs but that one breaks RHEL7 compatibility.

Deeper analysis

The existing patch essentially does two things:

  1. In Makefile.PL, it adds a -DHAVE_PCAP_SETSAMPLING define. A quick inspection of my local libpcap shows that this name is not a function exported by libpcap:

    nm -D /lib/x86_64-linux-gnu/libpcap.so |grep -i set_sampling

    Having this #define on pre-1.9 versions will not compile. Looking in the libpcap source code, the function is guarded by a macro PCAP_AVAILABLE_1_9, so any version of libpcap before that will not have it.

  2. In stubs.inc it removes the definitions of the types pcap_samp and pcap_rmtauth, because these are already defined in libpcap 1.9.x. So, to work around this, we also need to know the version of the libpcap library on this machine.

Fixing

The nicest approach would be if libpcap declares its version as #define constants. Then the C preprocessor would do all the necessary work for us. But this is not how things are.

The second nicest approach would be if Perl had a convenient way to dynamically load an arbitrary loadable library and call a parameterless function that returns a char*. But Perl has no such thing built-in.

The next best approach is to write a minimal C program to output that string and then to capture that string from Perl using backticks:

#include <stdio.h>
#include <pcap.h>

int main(int argc, char *argv[]) {
    printf("%s\n", pcap_lib_version());
}

This is the approach I took.

Future improvements

There are some improvements for my quick fix:

  1. Error handling

    Currently, if compiling pcap_version.c fails, the Makefile.PL will simply assume PCAP version 1.8. Some better diagnostics might be in order.

  2. Compilation of the C program

    Using ExtUtils::CBuilder instead of manually calling system() might improve the stability. But ExtUtils::CBuilder is only in core since 5.9.3, while Net::Pcap claims compatibility down to 5.6.1.

Releasing

With the version number in hand, it becomes easy to change the removal of the struct definitions to conditionals on the version number. After adding the new file pcap_version.c to the MANIFEST, I submitted the pull request on Github , in the hope that the author will release it or maybe at least other people can reuse it.