#!/usr/bin/perl use strict; use warnings; use Socket; use Getopt::Long qw(:config posix_default bundling); use Net::Pcap qw(:functions); use Net::Inspect::Debug qw(:DEFAULT %TRACE $DEBUG); use Net::Inspect::L2::Pcap; use Net::Inspect::L3::IP; use Net::Inspect::L4::TCP; use Net::Inspect::L4::UDP; ############################################################################ # Options ############################################################################ my ($infile,$dev,$nopromisc,@trace,$outdir); GetOptions( 'r=s' => \$infile, 'i=s' => \$dev, 'p' => \$nopromisc, 'h|help' => sub { usage() }, 'd|debug' => \$DEBUG, 'T|trace=s' => sub { push @trace,split(m/,/,$_[1]) }, 'D|dir=s' => \$outdir, ) or usage(); usage('only interface or file can be set') if $infile and $dev; $infile ||= '/dev/stdin' if ! $dev; my $pcapfilter = join(' ',@ARGV); $TRACE{$_} = 1 for(@trace); die "cannot write to $outdir: $!" if $outdir and ! -w $outdir || ! -d _; sub usage { print STDERR "ERROR: @_\n" if @_; print STDERR <new( ConnWriter->new("$outdir/tcp-")); my $udp = Net::Inspect::L4::UDP->new( ConnWriter->new("$outdir/udp-")); my $raw = Net::Inspect::L3::IP->new([$tcp,$udp]); my $pc = Net::Inspect::L2::Pcap->new($pcap,$raw); # Mainloop ############################################################################ my $time; pcap_loop($pcap,-1,sub { my (undef,$hdr,$data) = @_; if ( ! $time || $hdr->{tv_sec}-$time>10 ) { $tcp->expire($time = $hdr->{tv_sec}); $udp->expire($time = $hdr->{tv_sec}); } return $pc->pktin($data,$hdr); },undef); package ConnWriter; use base 'Net::Inspect::Connection'; use fields qw(prefix flowid saddr sport daddr dport time); use Net::Inspect::Debug; my $flowid = 0; sub new { my ($class,$dir) = @_; my $self = $class->SUPER::new; if ( ref $class ) { $self->{prefix} = $dir || $class->{prefix}; $self->{flowid} = ++$flowid; } else { $self->{prefix} = $dir; } return $self; } sub syn { 1 } sub new_connection { my ($self,$meta) = @_; my $obj = $self->new; # clones attached flows %$obj = ( %$obj, saddr => $meta->{saddr}, sport => $meta->{sport}, daddr => $meta->{daddr}, dport => $meta->{dport}, time => $meta->{time}, ); return $obj; } sub in { my ($self,$dir,$data,$eof,$time) = @_; my $fname = sprintf("%s%05d.%d-%s.%s-%s.%s-%d", $self->{prefix}, $self->{flowid}, $self->{time}, $self->{saddr}, $self->{sport}, $self->{daddr}, $self->{dport}, $dir ); open( my $fh,'>>',$fname ) or die "open $fname: $!"; print $fh $data; return length($data); } # UDP sub pktin { my $self = shift; if ( ref($_[1])) { # packet w/o connection my ($data,$meta) = @_; # create connection my $conn = $self->new_connection($meta); $conn->in(0,$data,0,$meta->{time}); return $conn; } else { # already connection my ($dir,$data,$time) = @_; return $self->in($dir,$data,0,$time); } } sub fatal { my ($self,$reason) = @_; warn "fatal: $reason\n"; }