http://www.perlmonks.org?node_id=170648

 

Introduction

 

Throughout its history, Perl has always found a home in the suite of tools employed by system administrators in the maintenance, monitoring and administration of computer systems. As the diversity of demands and requirements placed upon computer systems has grown, so too has the requirement for system administrators to take full advantage of the tools at their disposal. In this respect, Perl has proven to be a most valuable asset to system administrators with an ever expanding base of diverse application and tool components available from the comprensive perl archive network (CPAN, http://www.cpan.org).

This tutorial is intended to introduce the reader to another such component available from CPAN, the Net::Pcap library. This module provides an interface for Perl to the Lawrence Berkeley National Laboratory Network Research Group's pcap library, which is a system-independent interface for user-level packet capture. This library provides a portable framework for low-level network monitoring and can be used for a variety of network monitoring functions including network statistics collection, security monitoring and network debugging. Thus, it is with a focus on network administration that this tutorial on the usage of Net::Pcap is presented.

 

Setting the Device

 

The first step in building an application or tool using Net::Pcap and the underlying libpcap library for network monitoring is to determine an available network interface which can be used for this monitoring network traffic. This device can be specified by the user for specific network monitoring, particularly on multi-homed machines, or can be determined by the lookupdev method from Net::Pcap.

The syntax of the lookupdev method is as follows:

$dev = Net::Pcap::lookupdev(\$err)

This method returns the name of a network device which can be used for monitoring network traffic - For example:

use Net::Pcap; use strict; my $err; my $dev = Net::Pcap::lookupdev(\$err); if (defined $err) { die 'Unable to determine network device for monitoring - ', $err; }

The string reference $err is passed as an argument to this method and is returned with an error description in the event of method failure. Upon method failure, the returned device name is also undefined.

A second method from Net::Pcap which warrants introduction at this point is lookupnet, which can be used to determine the network address and netmask for a device. This method is useful for the validation of a device name supplied for network monitoring by a user.

The syntax of the lookupnet method is as follows:

Net::Pcap::lookupnet($dev, \$net, \$mask, \$err)

This method returns the network address and netmask for the device specified, $dev. This method also follows the conventions of the underlying library of returning 0 for success and -1 for failure and as such error checking for this and other Net::Pcap functions may use the pseudo-reverse mentality of the die if .. idiom. For example:

my ($address, $netmask, $err); if (Net::Pcap::lookupnet($dev, \$address, \$netmask, \$err)) { die 'Unable to look up device information for ', $dev, ' - ', $err +; } print STDOUT "$dev: addr/mask -> $addr/$mask\n";

 

Capturing Packets

 

Once an appropriate network device has been determined, the process of packet capturing can be initiated. The Net::Pcap function open_live returns a packet capture descriptor which can be used for capturing and examining network packets.

The syntax of the open_live method is as follows:

$object = Net::Pcap::open_live($dev, $snaplen, $promisc, $to_ms, \$err +)

The $dev parameter specifies the network interface from which to capture network packets while the $snaplen and $promisc parameters specify the maximum number of bytes to capture from each packet and whether to put the interface into promiscuous mode, respectively. The latter of these parameters, the promiscuous mode, places the network card into a "snooping" mode where network packets not necessarily directed to the packet capturing machine are captured - In a non-switched network environment, this could effectively capture all network traffic! The $to_ms parameter specifies a read time-out for packet capturing in milliseconds - A $to_ms value of 0 captures packets until an error occurs while a value of -1 captures packets indefinitely.

The next step in the packet capture process is to establish a callback function for Net::Pcap to pass captured packets to for analysis and reporting - For this, the loop method of Net::Pcap is called:

Net::Pcap::loop($object, $count, \&callback_function, $user_data)

This method takes four mandatory arguments, the Net::Pcap object returned from the Net::Pcap::open_live method, $object, a numeric indicating the number of packets to capture, $count and a subroutine reference to the callback function. If the numeric passed to this function is negative, the Net::Pcap::loop will capture packets indefinitely (or until an error occurs if the $to_ms argument of the open_live method is set to 0). The fourth argument passed to this method with arbitrary data that is passed with the callback function with captured packets and can be used as a method to 'tag' captured packets or distinguish between several open packet capture sessions.

The callback function specified by the Net::Pcap::loop method receives the following arguments when called:

  • The $user_data string passed to the Net::Pcap::loop method.
  • A reference to a hash containing packet header information - The fields of this hash of packet header information are as follows:

    • len - the total length of the packet,
    • caplen - the captured length of the packet; this corresponds to the $snaplen argument passed to the Net::Pcap::open_live method
    • tv_sec - the seconds value of the packet timestamp
    • tv_usec - the microseconds value of the packet timestamp
  • A copy of the entire packet

An example of the callback function associated with packet capture may look like the following:

sub callback_function { my ($user_data, $header, $packet) = @_; ... }

 

Filtering Packets

 

While the methods described above, provide the means by which to capture all network traffic, the real power offered by the libpcap library is to selective filter network packets to monitor specific traffic. The filtering of network packets can be set through use of a filter language specific to the libpcap library - A description of this filter language can be found in the libpcap source code or on the tcpdump(8) man page. The use of this filter language for the selective capture of network packets does require some knowledge of TCP/IP networking and the underlying packet structure - The description of this filter language in detail is beyond the scope of this tutorial.

The Net::Pcap module provides methods for the compilation and setting of filters for network packet capture by means of the Net::Pcap::compile and Net::Pcap::setfilter methods.

The arguments of the Net::Pcap::compile method are as follows:

Net::Pcap::compile($object, \$filter_compiled, $filter_string, $optimi +se, $netmask)

This method will compile and check the filter specified in $filter_string for Net::Pcap object $object and return the compiled filter in the scalar $filter_compiled. The filter is optimised where possible if the $optimise variable is true. This function, like other Net::Pcap functions, returns 0 if successful or -1 if an error occurs.

The compiled filter string, $filter_compiled, can then be applied against the Net::Pcap object using the Net::Pcap::setfilter method - For example:

Net::Pcap::setfilter($object, $filter_compiled);

 

Decoding Captured Packets

 

Once packets have been captured using the Net::Pcap interface to libpcap, the next step is to decode this packets and make sense of the network packet data collected. This can be performed by constructing unpack templates for captured data or more easily through the NetPacket:: collection of modules. These modules each contain methods for extracting information from and about network packets, the most useful of which is arguably, the decode method - This method returns a hash of meta-data about the passed packet, specific to the packet type.

For example, the NetPacket::Ethernet::decode method will return the following information on captured ethernet packets:

  • src_mac - the source MAC address for the ethernet packet as a hex string
  • dest_mac - the destination MAC address for the ethernet packet as a hex string
  • type - the protocol type of the ethernet packet, for example, IP, ARP, PPP, SNMP
  • data - the data payload for the ethernet packet

Further information on each of the NetPacket:: modules and the information returned by the decode function can be found on their respective man pages.

In addition to this, each of the NetPacket:: modules also contain a strip method which simply returns the data payload of the network packet - This is useful when the network encapsulation is of little or no concern to your application.

 

Cleaning Up

 

Once finished capturing packets, the Net::Pcap::close method should be called to close the packet capture device. For example:

Net::Pcap::close($object)

 

Putting It All Together

 

The following example shows a way of putting all of the techniques described above and putting them to use for network administration. In this example, details of all TCP packets with the SYN header flag set captured by a machine will be reported - These network packets are used by a client in initiating a connection with a server and can be used to initiate denial of service attacks against a network host. For further information on TCP packet structure and the SYN header flag, see RFC793.

use Net::Pcap; use NetPacket::Ethernet; use NetPacket::IP; use NetPacket::TCP; use strict; my $err; # Use network device passed in program arguments or if no # argument is passed, determine an appropriate network # device for packet sniffing using the # Net::Pcap::lookupdev method my $dev = $ARGV[0]; unless (defined $dev) { $dev = Net::Pcap::lookupdev(\$err); if (defined $err) { die 'Unable to determine network device for monitoring - ', $e +rr; } } # Look up network address information about network # device using Net::Pcap::lookupnet - This also acts as a # check on bogus network device arguments that may be # passed to the program as an argument my ($address, $netmask); if (Net::Pcap::lookupnet($dev, \$address, \$netmask, \$err)) { die 'Unable to look up device information for ', $dev, ' - ', $err +; } # Create packet capture object on device my $object; $object = Net::Pcap::open_live($dev, 1500, 0, 0, \$err); unless (defined $object) { die 'Unable to create packet capture on device ', $dev, ' - ', $er +r; } # Compile and set packet filter for packet capture # object - For the capture of TCP packets with the SYN # header flag set directed at the external interface of # the local host, the packet filter of '(dst IP) && (tcp # [13] & 2 != 0)' is used where IP is the IP address of # the external interface of the machine. For # illustrative purposes, the IP address of 127.0.0.1 is # used in this example. my $filter; Net::Pcap::compile( $object, \$filter, '(dst 127.0.0.1) && (tcp[13] & 2 != 0)', 0, $netmask ) && die 'Unable to compile packet capture filter'; Net::Pcap::setfilter($object, $filter) && die 'Unable to set packet capture filter'; # Set callback function and initiate packet capture loop Net::Pcap::loop($object, -1, \&syn_packets, '') || die 'Unable to perform packet capture'; Net::Pcap::close($object); sub syn_packets { my ($user_data, $header, $packet) = @_; # Strip ethernet encapsulation of captured packet my $ether_data = NetPacket::Ethernet::strip($packet); # Decode contents of TCP/IP packet contained within # captured ethernet packet my $ip = NetPacket::IP->decode($ether_data); my $tcp = NetPacket::TCP->decode($ip->{'data'}); # Print all out where its coming from and where its # going to! print $ip->{'src_ip'}, ":", $tcp->{'src_port'}, " -> ", $ip->{'dest_ip'}, ":", $tcp->{'dest_port'}, "\n"; }

 

From Here

 

This tutorial has touched upon the basic functionality of the Net::Pcap module and how it can be used in network administration. Other features of this excellent module which have not been covered in tutorial include saving captured network packets to files and interface statistics handling - These features will be covered, if there is sufficient interest and demand, in a follow-up tutorial.

 

References

 

Blank-Edelman, David N. (2000) "Perl for System Administration" O'Reilly, ISBN 1-56592-609-9

Carstens, Tim (2002) "Programming with pcap" http://broker.dhs.org/pcap.html

Casado, Martin "Packet Capture with libpcap and other Low Level Network Tricks" http://www.dbaseiv.net/sockets/pcap/Tutorials/section1.html