# # $Id: Online2.pm 349 2011-03-26 13:12:44Z gomor $ # package Net::Frame::Dump::Online2; use strict; use warnings; use base qw(Net::Frame::Dump); our @AS = qw( dev timeoutOnNext timeout promisc snaplen _firstTime ); __PACKAGE__->cgBuildIndices; __PACKAGE__->cgBuildAccessorsScalar(\@AS); BEGIN { my $osname = { cygwin => [ \&_checkWin32, ], MSWin32 => [ \&_checkWin32, ], }; *_check = $osname->{$^O}->[0] || \&_checkOther; } use Net::Frame::Dump qw(:consts); use Carp; use Net::Pcap; use Time::HiRes qw(gettimeofday); use Net::Frame::Layer qw(:subs); sub _checkWin32 { return 1; } sub _checkOther { if ($>) { warn("Must be EUID 0 (or equivalent) to open a device for live ". "capture.\n"); return; } return 1; } sub new { my $self = shift->SUPER::new( timeoutOnNext => 3, timeout => 0, promisc => 0, snaplen => 1514, @_, ); if (!defined($self->dev)) { warn("You MUST pass `dev' attribute\n"); return; } return $self; } sub start { my $self = shift; _check() or return; $self->isRunning(1); my $err; my $pd = Net::Pcap::open_live( $self->dev, $self->snaplen, $self->promisc, 100, \$err, ); unless ($pd) { warn("@{[(caller(0))[3]]}: open_live: $err\n"); return; } my $net = 0; my $mask = 0; Net::Pcap::lookupnet($self->dev, \$net, \$mask, \$err); if ($err) { warn("@{[(caller(0))[3]]}: lookupnet: $err\n"); } my $fcode; if (Net::Pcap::compile($pd, \$fcode, $self->filter, 0, $mask) < 0) { warn("@{[(caller(0))[3]]}: compile: ". Net::Pcap::geterr($pd). "\n"); return; } if (Net::Pcap::setfilter($pd, $fcode) < 0) { warn("@{[(caller(0))[3]]}: setfilter: ". Net::Pcap::geterr($pd). "\n"); return; } my $r = Net::Pcap::setnonblock($pd, 1, \$err); if ($r == -1) { warn("@{[(caller(0))[3]]}: setnonblock: $err\n"); return; } $self->_pcapd($pd); $self->getFirstLayer; #$SIG{INT} = sub { $self->_printStats }; #$SIG{TERM} = sub { $self->_printStats }; #$self->cgDebugPrint(1, "dev: [@{[$self->dev]}]\n". #"file: [@{[$self->file]}]\n". #"filter: [@{[$self->filter]}]"); return 1; } sub stop { my $self = shift; if (!$self->isRunning) { return; } Net::Pcap::close($self->_pcapd); $self->_pcapd(undef); $self->isRunning(0); return 1; } sub getStats { my $self = shift; if (!defined($self->_pcapd)) { carp("@{[(caller(0))[3]]}: unable to get stats, no pcap descriptor ". "opened.\n"); return; } my %stats; Net::Pcap::stats($self->_pcapd, \%stats); return \%stats; } sub _printStats { my $self = shift; my $stats = $self->getStats; 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}); return 1; } sub _getNextAwaitingFrame { my $self = shift; return $self->nextEx; } sub _nextTimeoutHandle { my $self = shift; # Handle timeout my $thisTime = gettimeofday(); if ($self->timeoutOnNext && !$self->_firstTime) { $self->_firstTime($thisTime); } if ($self->timeoutOnNext && $self->_firstTime) { if (($thisTime - $self->_firstTime) > $self->timeoutOnNext) { $self->timeout(1); $self->_firstTime(0); $self->cgDebugPrint(1, "Timeout occured"); return; } } return 1; } sub _nextTimeoutReset { shift->_firstTime(0) } sub timeoutReset { shift->timeout(0) } sub next { my $self = shift; $self->_nextTimeoutHandle or return; my $frame = $self->_getNextAwaitingFrame; $self->_nextTimeoutReset if $frame; return $frame; } 1; __END__ =head1 NAME Net::Frame::Dump::Online2 - tcpdump like implementation, online mode and non-blocking =head1 SYNOPSIS use Net::Frame::Dump::Online2; # # Simply create a Dump object # my $oDump = Net::Frame::Dump::Online2->new( dev => 'eth0', ); $oDump->start; # Gather frames while (1) { if (my $f = $oDump->next) { my $raw = $f->{raw}; my $firstLayerType = $f->{firstLayer}; my $timestamp = $f->{timestamp}; } } $oDump->stop; # # Default parameters on creation # my $oDumpDefault = Net::Frame::Dump::Online->new( dev => undef, timeoutOnNext => 3, timeout => 0, promisc => 0, filter => '', isRunning => 0, keepTimestamp => 0, frames => [], ); =head1 DESCRIPTION This module implements a tcpdump-like program, for live capture from networks. =head1 ATTRIBUTES =over 4 =item B The network interface to listen on. No default value. =item B Each time you call B method, an internal counter is updated. This counter tells you if you have not received any data since B seconds. When a timeout occure, B is set to true. =item B When B seconds has been reached, this variable is set to true, and never reset. See B if you want to reset it. =item B If you want to capture a different snaplen, set it a number. Default to 1514. =item B By default, interface is not put into promiscuous mode, set this parameter to true if you want it. =back The following are inherited attributes: =over 4 =item B Pcap filter to use. Default to no filter. =item B Stores information about the first layer type contained on read frame. This attribute is filled only after a call to B method. =item B Returns true if a call to B has been done, false otherwise or if a call to B has been done. =item B Sometimes, when frames are captured and saved to a .pcap file, timestamps sucks. That is, you send a frame, and receive the reply, but your request appear to have been sent after the reply. So, to correct that, you can use B own timestamping system. The default is 0. Set it manually to 1 if you need original .pcap frames timestamps. =back =head1 METHODS =over 4 =item B =item B (hash) Object constructor. You can pass attributes that will overwrite default ones. See B for default values. =item B When you want to start reading frames from network, call this method. =item B When you want to stop reading frames from network, call this method. =item B Returns the next captured frame; undef if none awaiting. Each time this method is called, a comparison is done to see if no frame has been captured during B number of seconds. If so, B attribute is set to 1 to reflect the pending timeout. =item B (B object) This method will store internally, sorted, the B object passed as a single parameter. B methods, implemented in various B objects will be used to efficiently retrieve (via B method) frames. Basically, it is used to make B method (from B) to retrieve quickly the reply frame for a request frame. =item B (B object) This will return an array of possible reply frames for the specified B object. For example, reply frames for a UDP probe will be all the frames which have the same source port and destination port as the request. =item B Will flush stored frames, the one which have been stored via B method. =item B Reset the internal timeout state (B attribute). =item B Tries to get packet statistics on an open descriptor. It returns a reference to a hash that has to following fields: B, B, B. =back =head1 SEE ALSO L =head1 AUTHOR Patrice EGomoRE Auffret =head1 COPYRIGHT AND LICENSE Copyright (c) 2006-2011, Patrice EGomoRE Auffret You may distribute this module under the terms of the Artistic license. See LICENSE.Artistic file in the source distribution archive. =cut