#!/usr/bin/perl -w # # Author: Kyle Haugsness # # Date: October 4, 2006 # # This program shows how to do a tail on a pcap file. # It utilizes the Net::Pcap and NetPacket perl modules to # do all of the hard work. # # Problem to be solved: I had a tcpdump command writing # to a pcap file. I wanted to extract very specific information # out of the file and keep it running in tail mode. # I couldn't find any examples of how to do this, so # I figured out through a little trial-and-error. The # NetPacket modules are very handy and let you decode # ICMP, TCP, and UDP traffic also. # # This script will start at the beginning of the file and # process all existing packets immediately, then start following # it while sleeping. It is a little more difficult to start # at the end of the file and only examine new packets. # (Left as an exercise to the reader. :) # # There appears to be equivalent ways of doing this in C # and Python. So use whatever you like. # use strict; # force good code use Net::Pcap; # packet capture library use NetPacket::Ethernet qw(:ALL); # parse packets use NetPacket::IP; # parse packets # Global variables my $input_file; # tcpdump input file my $pcap; # pcap object handle my %header; # header of a packet (returned by pcap::next) my $packet; # packet data (returned by pcap::next) my $err; # pcap error my $pkt_cnt = 0; # packet count sub usage { print "tail-pcap.pl \n"; exit(1); } sub process_packet { # This function gets called every time tcpdump reads a packet my($user_data, $header, $packet) = @_; my $eth_obj; my $ip_obj; my $tcp_obj; my $udp_obj; my $icmp_obj; my $data_bytes; # Decode the layer 2 data $eth_obj = NetPacket::Ethernet->decode($packet); if ($eth_obj->{type} != ETH_TYPE_IP) { #print "Not handling ethertype: " . $eth_obj->{type} . "\n"; } else { # Decode the packet to get IP data $ip_obj = NetPacket::IP->decode($eth_obj->{data}); # Print some information print "Packet: $pkt_cnt\t"; print localtime($header->{tv_sec}) . "\t"; print $header->{len} . " bytes\t"; print "Src: " . $ip_obj->{src_ip} . "\t"; print "Dst: " . $ip_obj->{dest_ip} . "\t"; print "Proto: " . $ip_obj->{proto} . "\n"; } $pkt_cnt += 1; } # Main script starts here if (! $ARGV[0] || $ARGV[0] eq '-h' || $ARGV[0] eq '--help') { usage(); } else { # Get the input file from the command line $input_file = $ARGV[0]; } # Verify that the file exists die "Unable to open input file $input_file: $!" if (! -f $input_file); # If the file exists but size of 0, the open_offline call will fail # which isn't what we want in the tail mode until (((stat($input_file))[7]) > 0) { sleep 1; } # Open the pcap file $pcap = Net::Pcap::open_offline($input_file, \$err) or die "Can't open tcpdump file $input_file: $!"; # Infinite loop in tail mode while (1) { # Read all available packets or sleep 5 seconds while (!($packet = Net::Pcap::next($pcap, \%header))) { # No packet available, so wait sleep 5; } # Do the magic process_packet("My string", \%header, $packet); } # Close the tcpdump capture Net::Pcap::close($pcap);