#!/usr/bin/perl use strict; use Data::Dumper; use Date::Format; use Net::Pcap; my $expression = "port 80 or port 443"; my $snaplen = 256; my $promisc = 0; my $filebase = "pcap_"; my $suffixfmt = '%Y-%m-%dT%H:%M:%S'; my $ringsize = 5*60; my @ringbuf; my $ringptr = 0; # current slot my $ptrdate = 0; # timestamp for current slot (tv_sec) # init ringbuffer, one slot per second for (0 .. $ringsize-1) { $ringbuf[$_] = []; } # get device my $errmsg; my $dev = Net::Pcap::lookupdev(\$errmsg); die $errmsg unless $dev; my ($netaddr, $netmask); Net::Pcap::lookupnet($dev, \$netaddr, \$netmask, \$errmsg); die $errmsg unless $dev; # open capture my $pcap = Net::Pcap::open_live($dev, $snaplen, $promisc, 1000, \$errmsg); die $errmsg unless $pcap; # set filter my $filter; unless (Net::Pcap::compile($pcap, \$filter, $expression, 1, $netmask)) { Net::Pcap::setfilter($pcap, $filter); } # main loop (eternal) my $finish = 0; my $dodump = 0; $SIG{'HUP'} = sub { $finish = 1 }; $SIG{'TERM'} = sub { $finish = 1 }; $SIG{'INT'} = sub { $finish = 1 }; $SIG{'USR1'} = sub { $dodump = 1 }; while (not $finish) { # capture pending packets Net::Pcap::dispatch($pcap, -1, \&capture, undef); # dump buffer? if ($dodump) { # dump buffer my $filename = time2str($filebase.$suffixfmt, time()); # reorder buffer by copying array refs my @buf; if ($ringptr+1 < $ringsize) { push @buf, @ringbuf[$ringptr+1 .. $ringsize-1]; } push @buf, @ringbuf[0 .. $ringptr]; # open dump file my $pcapdump = Net::Pcap::dump_open($pcap, $filename) or die "cannot open dumpfile: ", Net::Pcap::geterr($pcap); # dump reordered buffer for my $slot (@buf) { for my $pkg (@$slot) { Net::Pcap::dump($pcapdump, @$pkg); } } # close dump file Net::Pcap::dump_close($pcapdump); # done, reset flag $dodump = 0; } } # close capture # you want to do this to restore previous promiscous mode on the device Net::Pcap::close($pcap); # store packets to ringbuffer (pcap callback) sub capture { my $user_data = shift; my $hdr = shift; my $pkt = shift; # init timestamp on first packet $ptrdate = $hdr->{'tv_sec'} unless ($ptrdate); while ($hdr->{'tv_sec'} > $ptrdate) { # advance ringptr to next slot $ptrdate++; $ringptr++; $ringptr = 0 if ($ringptr >= $ringsize); # clear current slot $ringbuf[$ringptr] = []; } # store captured data in slot push @{$ringbuf[$ringptr]}, [$hdr, $pkt]; } # dump ringbuffer contents to file sub dumpring { } # end of file