📄 dump.pm
字号:
## $Id: Dump.pm,v 1.3.2.12 2006/10/29 11:49:45 gomor Exp $#package Net::Packet::Dump;use strict;use warnings;use Carp;require Class::Gomor::Array;our @ISA = qw(Class::Gomor::Array);use Net::Packet::Env qw($Env);require Net::Packet::Frame;use Net::Packet::Utils qw(getRandom32bitsInt);use Net::Packet::Consts qw(:dump);use Net::Pcap;use Time::HiRes qw(gettimeofday);use Storable qw(lock_store lock_retrieve);our @AS = qw( dev env file filter overwrite timeoutOnNext timeout promisc link nextFrame isRunning unlinkOnClean noStore noLayerWipe mode keepTimestamp _pid _pcapd _dumper _stats _firstTime _sName _sDataAwaiting);our @AA = qw( frames);our @AO = qw( framesSorted);__PACKAGE__->cgBuildIndices;__PACKAGE__->cgBuildAccessorsScalar(\@AS);__PACKAGE__->cgBuildAccessorsArray(\@AA);no strict 'vars';BEGIN { my $osname = { cygwin => \&_killTcpdumpWin32, MSWin32 => \&_killTcpdumpWin32, }; *_killTcpdump = $osname->{$^O} || \&_killTcpdumpOther;}sub new { my $self = shift->SUPER::new( dev => $Env->dev, env => $Env, file => "netpacket-tmp-$$.@{[getRandom32bitsInt()]}.pcap", filter => '', overwrite => 0, timeout => 0, promisc => 0, timeoutOnNext => 3, isRunning => 0, unlinkOnClean => 1, noStore => 0, noLayerWipe => 0, framesSorted => {}, frames => [], mode => NP_DUMP_MODE_ONLINE, keepTimestamp => 0, _sDataAwaiting => 0, _sName => "netpacket-tmp-$$.@{[getRandom32bitsInt()]}.storable", @_, ); unless ($self->[$__file]) { confess("You MUST set `file' attribute\n"); } $Env->dump($self) unless $Env->noDumpAutoSet; $self;}sub isModeOnline { shift->[$__mode] eq NP_DUMP_MODE_ONLINE }sub isModeOffline { shift->[$__mode] eq NP_DUMP_MODE_OFFLINE }sub isModeWriter { shift->[$__mode] eq NP_DUMP_MODE_WRITER }sub start { my $self = shift; $self->cgDebugPrint(1, 'will run in mode: '.$self->mode); $self->[$__isRunning] = 1; if ($self->isModeOnline) { if (-f $self->[$__file] && ! $self->[$__overwrite]) { croak("We will not overwrite a file by default. Use `overwrite' ". "attribute to do it\n"); } $self->_sStore(0); $self->_waitFileSize($self->[$___sName]); $self->_startTcpdump; $self->_openFileOffline; } elsif ($self->isModeOffline) { if (! -f $self->[$__file]) { croak("File does not exists: ".$self->[$__file]."\n"); } $self->_openFileOffline; $self->_setFilter; } elsif ($self->isModeWriter) { if (-f $self->[$__file] && ! $self->[$__overwrite]) { croak("We will not overwrite a file by default. Use `overwrite' ". "attribute to do it\n"); } $self->_openFileWriter; } 1;}sub stop { my $self = shift; return unless $self->[$__isRunning]; return if $self->isSon; if ($self->isModeOnline) { $self->_killTcpdump; $self->[$___pid] = undef; if ($self->[$___sName] && -f $self->[$___sName]) { unlink($self->[$___sName]); } } elsif ($self->isModeWriter) { Net::Pcap::dump_close($self->[$___dumper]); } elsif ($self->isModeOffline) { # Nothing to do here } Net::Pcap::close($self->[$___pcapd]); $self->[$__isRunning] = 0; 1;}sub isFather { shift->[$___pid] }sub isSon { ! shift->[$___pid] }sub _sStore { lock_store(\$_[1], $_[0]->[$___sName]) or carp("@{[(caller(0))[3]]}: lock_store: @{[$_[0]->[$___sName]]}: $!\n");}sub _sRetrieve { ${lock_retrieve(shift->[$___sName])} }sub _sonPrintStats { my $self = shift; my $stats = $self->getStats; Net::Pcap::breakloop($self->[$___pcapd]); Net::Pcap::close($self->[$___pcapd]); $self->cgDebugPrint(1, 'Frames received : '.$stats->{ps_recv}); $self->cgDebugPrint(1, 'Frames dropped : '.$stats->{ps_drop}); $self->cgDebugPrint(1, 'Frames if dropped: '.$stats->{ps_ifdrop}); exit(0);}sub _waitFile { my $self = shift; my ($file) = @_; my $startTime = gettimeofday(); my $thisTime = $startTime; while (! -f $file) { if ($thisTime - $startTime > 10) { croak("@{[(caller(0))[3]]}: too long for file creation: $file\n") } $thisTime = gettimeofday(); }}sub _waitFileSize { my $self = shift; my ($file) = @_; $self->_waitFile($file); my $startTime = gettimeofday(); my $thisTime = $startTime; while (! ((stat($file))[7] > 0)) { if ($thisTime - $startTime > 10) { $self->clean; croak("@{[(caller(0))[3]]}: too long for file creation2: $file\n") } $thisTime = gettimeofday(); }}sub _startTcpdump { my $self = shift; my $err; my $pd = Net::Pcap::open_live( $self->[$__dev], 1514, $self->[$__promisc], 1000, \$err, ); unless ($pd) { croak("@{[(caller(0))[3]]}: open_live: $err\n"); } my $net = 0; my $mask = 0; Net::Pcap::lookupnet($self->[$__dev], \$net, \$mask, \$err); if ($err) { carp("@{[(caller(0))[3]]}: lookupnet: $err\n"); } my $fcode; if (Net::Pcap::compile($pd, \$fcode, $self->[$__filter], 0, $mask) < 0) { croak("@{[(caller(0))[3]]}: compile: ". Net::Pcap::geterr($pd). "\n"); } if (Net::Pcap::setfilter($pd, $fcode) < 0) { croak("@{[(caller(0))[3]]}: setfilter: ". Net::Pcap::geterr($pd). "\n"); } my $p = Net::Pcap::dump_open($pd, $self->[$__file]); unless ($p) { croak("@{[(caller(0))[3]]}: dump_open: ". Net::Pcap::geterr($pd). "\n"); } Net::Pcap::dump_flush($p); $SIG{CHLD} = 'IGNORE'; my $pid = fork(); croak("@{[(caller(0))[3]]}: fork: $!\n") unless defined $pid; if ($pid) { $self->[$___pid] = $pid; return 1; } else { $self->[$___pcapd] = $pd; $SIG{INT} = sub { $self->_sonPrintStats }; $SIG{TERM} = sub { $self->_sonPrintStats }; $self->cgDebugPrint(1, "dev: [@{[$self->[$__dev]]}]\n". "file: [@{[$self->[$__file]]}]\n". "filter: [@{[$self->[$__filter]]}]"); Net::Pcap::loop($pd, -1, \&_tcpdumpCallback, [ $p, $self ]); Net::Pcap::close($pd); exit(0); }}sub _tcpdumpCallback { my ($data, $hdr, $pkt) = @_; my $p = $data->[0]; my $self = $data->[1]; Net::Pcap::dump($p, $hdr, $pkt); Net::Pcap::dump_flush($p); my $n = $self->_sRetrieve; $self->_sStore(++$n);}sub _killTcpdumpWin32 { my $self = shift; return unless $self->[$___pid]; kill('KILL', $self->[$___pid]);}sub _killTcpdumpOther { my $self = shift; return unless $self->[$___pid]; kill('TERM', $self->[$___pid]);}sub clean { my $self = shift; if ($self->isModeOnline) { if ($self->[$__unlinkOnClean] && $self->[$__file] && -f $self->[$__file]) { unlink($self->[$__file]); $self->cgDebugPrint(1, "@{[$self->[$__file]]} removed"); } } 1;}sub getStats { my $self = shift; unless ($self->[$___pcapd]) { carp("@{[(caller(0))[3]]}: unable to get stats, no pcap descriptor ". "opened\n"); return undef; } my %stats; Net::Pcap::stats($self->[$___pcapd], \%stats); $self->[$___stats] = \%stats; \%stats;}sub flush { my $self = shift; $self->[$__frames] = []; $self->[$__framesSorted] = {};}sub _setFilter { my $self = shift; my $str = $self->[$__filter]; return unless $str; my ($net, $mask, $err); Net::Pcap::lookupnet($self->[$__dev], \$net, \$mask, \$err); if ($err) { croak("@{[(caller(0))[3]]}: Net::Pcap::lookupnet: @{[$self->[$__dev]]}: ". "$err\n"); } my $filter; Net::Pcap::compile($self->[$___pcapd], \$filter, $str, 0, $mask); unless ($filter) { croak("@{[(caller(0))[3]]}: Net::Pcap::compile: error\n"); } Net::Pcap::setfilter($self->[$___pcapd], $filter);}sub _openFileOffline { my $self = shift; my $err; $self->[$___pcapd] = Net::Pcap::open_offline($self->[$__file], \$err); unless ($self->[$___pcapd]) { croak("@{[(caller(0))[3]]}: Net::Pcap::open_offline: ". "@{[$self->[$__file]]}: $err\n"); } $self->[$__link] = Net::Pcap::datalink($self->[$___pcapd]);}sub _getPcapHeader { my $self = shift; # 24 bytes header of a DLT_RAW pcap file "\xd4\xc3\xb2\xa1\x02\x00\x04\x00\x00\x00\x00\x00". "\x00\x00\x00\x00\xdc\x05\x00\x00\x0c\x00\x00\x00";}sub _openFileWriter { my $self = shift; my $file = $self->[$__file]; my $hdr = $self->_getPcapHeader; open(my $fh, '>', $file) or croak("@{[(caller(0))[3]]}: open: $file: $!\n"); syswrite($fh, $hdr, length($hdr)); close($fh); my $err; my $pcapd = Net::Pcap::open_offline($file, \$err); unless ($pcapd) { croak("@{[(caller(0))[3]]}: Net::Pcap::open_offline: ". "$file: $err\n"); } $self->[$___pcapd] = $pcapd; $self->[$___dumper] = Net::Pcap::dump_open($pcapd, $file); unless ($self->[$___dumper]) { croak("@{[(caller(0))[3]]}: Net::Pcap::dump_open: ". Net::Pcap::geterr($pcapd)."\n"); } 1;}sub _addToFramesSorted { my $self = shift; my ($frame) = @_; $self->framesSorted($frame); push @{$self->[$__frames]}, $frame;}sub _getTimestamp { my $self = shift; my ($hdr) = @_; $hdr->{tv_sec}.'.'.sprintf("%06d", $hdr->{tv_usec});}sub _setTimestamp { my $self = shift; my @time = Time::HiRes::gettimeofday(); $time[0].'.'.sprintf("%06d", $time[1]);}sub _pcapNext { my $self = shift; my %hdr; if (my $raw = Net::Pcap::next($self->[$___pcapd], \%hdr)) { my $ts = $self->[$__keepTimestamp] ? $self->_getTimestamp(\%hdr) : $self->_setTimestamp; my $frame = Net::Packet::Frame->new( env => $self->env, raw => $raw, timestamp => $ts, ) or return undef; $self->_addToFramesSorted($frame) unless $self->[$__noStore]; return $frame; } undef;}sub _getNextAwaitingFrameOffline { my $self = shift; $self->_pcapNext;}sub _getNextAwaitingFrameOnline { my $self = shift; my $last = $self->[$___sDataAwaiting]; my $new = $self->_sRetrieve; # Return if nothing new is awaiting
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -