Inspecting network traffic with Net::Pcap

[ Perl tips index ]
[ Subscribe to Perl tips ]

One of the most versatile ways to determine what a machine or network is doing is to inspect network traffic. This can be used to gather statistics, to detect attacks, to test and debug programs, and to diagnose network faults.

Many tools exist for inspecting network traffic, including command line utilities such as tcpdump, and graphical applications such as ethereal. These provide an excellent mechanism for capturing packets and allowing humans to inspect them, but are not well-suited for automatic processing.

Perl's Net::Pcap module works on both Windows and Unix systems and provides access to raw network traffic using the same pcap layer as tcpdump and ethereal.

Finding an interface

To use Net::Pcap we need to determine on which interface we want to capture packets. On Unix systems this is a device identifier such as eth0, on Windows it's the Device ID, which usually in the form \\Device\\NPF_{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.

Rather than hard-coding an interface, it's recommended to use one of Net::Pcap's helper functions to find it.

        use Net::Pcap;
        # Find the first suitable interface
        my $interface = Net::Pcap::lookupdev(\$err);
        # Find all interfaces.
        my @interfaces = Net::Pcap::findalldevs(\%devinfo, \$err);

Using the %devinfo it's possible to look for particular interfaces. For example, under Windows we can select the wireless device like this:

        use List::Util qw(first);
        my @interfaces = Net::Pcap::findalldevs(\%dev_info,\$err);
        my $wireless = first { $dev_info{$_} =~ /Wireless/ } @interfaces;

There's also a Net::Pcap::lookupnet function for finding which network is attached to a particular device.

Capturing packets

Once we have our interface, we can start capturing packets:

        my $pcap = Net::Pcap::open_live(
                $interface,$snaplen,$promisc,$timeout,\$err
        );

$snaplen is how many bytes we wish to capture. If we're just interested in headers, this can be set to a small number. If we want to capture whole packets, it needs to be set much larger.

You should realise that for most transports $snaplen is the number of bytes captured from the wire itself. Under ethernet the maximum data segment is 1500 bytes. However to capture the whole packet, including the 14 byte header, you need to set $snaplen to at least 1514. It doesn't hurt to have $snaplen set to a longer length than you really need.

$promisc should be true if you want to capture packets in promiscious mode, or false if you only want packets intended for your host. $timeout is the maximum time to wait for a packet in milliseconds, or zero for no timeout.

Once we've called open_live we can then begin to capture packets with the Net::Pcap::loop function:

        Net::Pcap::loop($pcap, $count, \&callback, $user_data);

$count is the number of packets we wish to capture. For an endless capturing loop set $count to zero. For every packet, the subroutine passed in &callback is called. $user_data is any data we wish to pass to the callback subroutine in addition to the packet data, and is useful in keeping state.

Our callback subroutine is provided with three arguments: the $user_data, a hashref containing header data, and the packet itself:

        sub callback {
            my ($user_data, $header_ref, $packet) = @_;
            # ...
        }

The $user_data is whatever information was supplied to the Net::Pcap::loop call, and $header_ref contains a hash reference with timestamp and capture size data.

Here's an example that searches for packets containing the string ``awesome'':

        sub find_awesome_packets {
            my (undef, undef, $packet) = @_;
            print "This packet is awesome!\n" if $packet =~ m{awesome}i;
        }

Testing

Instead of using Net::Pcap::open_live to capture packets in real-time, the Net::Pcap::open_offline function can be used to open a file containing saved packets. This allows applications to be tested against known data, or allows data captured by other applications to be processed at a later stage.

To be continued...

Our next tip will cover the use of NetPacket modules to extract data from the packet, inspection of TCP flags and other fields, and how to use filters to only capture interesting packets.

[ Perl tips index ]
[ Subscribe to Perl tips ]


This Perl tip and associated text is copyright Perl Training Australia. You may freely distribute this text so long as it is distributed in full with this Copyright noticed attached.

If you have any questions please don't hesitate to contact us:

Email: contact@perltraining.com.au
Phone: 03 9354 6001 (Australia)
International: +61 3 9354 6001

Valid XHTML 1.0 Valid CSS