Net-Inspect
view release on metacpan or search on metacpan
lib/Net/Inspect/L3/IP.pm view on Meta::CPAN
############################################################################
# RawIP
# reassembles fragmented IP packets
############################################################################
use strict;
use warnings;
package Net::Inspect::L3::IP;
use base 'Net::Inspect::Flow';
use fields qw(frag frag_timeout);
use Net::Inspect::Debug;
use Socket;
my $inet6_ntop;
BEGIN {
$inet6_ntop = eval {
Socket->VERSION(1.95);
Socket::inet_ntop( AF_INET6(),"\x0"x16)
&& sub { Socket::inet_ntop(AF_INET6(),shift) };
} || eval {
require Socket6;
Socket6::inet_ntop( Socket6::AF_INET6(),"\x0"x16)
&& sub { Socket6::inet_ntop(Socket6::AF_INET6(),shift) };
};
*pktin6 = $inet6_ntop ? \&_pktin6 : \&_pktin6_unsupported;
}
# field frag: hash indexed by {ip.id,saddr,daddr} with values
# [ $pos, \@fragments, $expire ]
# $pos - up to which position defragmentation is done
# @fragments - list of fragments [final,offset,data]
# final: true if this is the last fragment
# $expire - if no more fragments are received after $expire the
# packet gets discarded
sub new {
my ($class,$flow,%args) = @_;
if ( ref($flow) eq 'ARRAY' ) {
my $f = Net::Inspect::Flow->new_any('pktin');
$f->attach($_) for @$flow;
$flow = $f;
}
my $self = $class->SUPER::new($flow);
$self->{frag} = {};
$self->{frag_timeout} = $args{timeout} || 60;
return $self;
};
############################################################################
# process single raw packet, call ip-version specific function
############################################################################
sub pktin {
my Net::Inspect::L3::IP $self = shift;
my ($data,$time) = @_;
# check IP version
my $ver = unpack('C',$data) >> 4;
if ($ver == 4) {
$self->pktin4($data,$time);
return 1;
} elsif ($ver == 6) {
$self->pktin6($data,$time);
return 0;
} else {
trace("bad IP version $ver");
return 0;
}
}
############################################################################
# defragment ipv4 raw packets
############################################################################
sub pktin4 {
my Net::Inspect::L3::IP $self = shift;
my ($data,$time) = @_;
# parse IPv4 header
my ($vi,$qos,$len,$id,$ffo,$ttl,$proto,$chksum,$saddr,$daddr) =
unpack('CCnnnCCna4a4',$data);
# get payload
my $ihl = $vi & 0xf;
if ( $ihl<5 ) {
lib/Net/Inspect/L3/IP.pm view on Meta::CPAN
debug("forward %d bytes assembled from %d fragments",
length($fragments->[1][0][2]),$fragments->[0]);
return $self->{upper_flow}->pktin( $fragments->[1][0][2], {
time => $time,
saddr => $saddr,
daddr => $daddr,
proto => $proto,
id => $id,
ttl => $ttl,
qos => $qos,
fragments => $fragments->[0],
});
}
# set time for last fragment and expire old fragments
$fragments->[2] = $time + $self->{frag_timeout};
my $fdb = $self->{frag};
my @k = keys %$fdb;
if ( @k > 1 ) {
for (@k) {
$fdb->{$_}[2] >= $time and next;
delete $fdb->{$_} # expired
}
}
}
############################################################################
# IPv6 packets - fragmentation currently not supported
############################################################################
sub _pktin6 {
my Net::Inspect::L3::IP $self = shift;
my ($data,$time) = @_;
# parse and strip IPv6 header
my ($vtf,$len,$nextheader,$ttl,$saddr,$daddr) = unpack('NnCCa16a16',
substr($data,0,40,''));
if ($len > length($data)) {
trace("short packet len=".length($data)."/$len");
return;
} elsif ( $len < length($data)) {
substr($data,$len) = '';
}
my $tclass = ( $vtf & 0x0ff00000 ) >> 20;
my $flowlabel = $vtf & 0xfffff;
my $proto;
while ( $nextheader != 59 ) {
return if $data eq '';
if ($nextheader == 6 || $nextheader == 17 || $nextheader == 58) {
$proto = $nextheader;
last;
}
($nextheader,$len) = unpack("CC",$data);
substr($data,0,$len+8,''); # skip extension header
}
return $self->{upper_flow}->pktin( $data, {
time => $time,
saddr => $inet6_ntop->($saddr),
daddr => $inet6_ntop->($daddr),
proto => $proto,
ttl => $ttl,
qos => $tclass,
flowlabel => $flowlabel,
ver => 6,
});
}
sub _pktin6_unsupported {
trace("IPv6 unsupported, need to install recent Socket or Socket6 module");
}
1;
__END__
=head1 NAME
Net::Inspect::L3::IP - get raw IP packets, reassemble fragments
=head1 SYNOPSIS
my $raw = Net::Inspect::L3::IP->new($tcp);
$raw->pktin($data,$timestamp);
=head1 DESCRIPTION
Gets Raw-IP packets via C<pktin> hook, extracts meta-data, reassembles
fragmented packets and calls C<pktin> hook on attached flows, once for
each full packet.
Provides the hooks required by C<Net::Inspect::L2::Pcap>.
Usually C<Net::Inspect::L4::TCP> or similar are used as upper flow.
Constructor:
=over 4
=item new(%args)
The only used argument is %args is C<timeout>, which specifies when timeout in
seconds, after which the next fragment of a packet must be received.
Defaults to 60.
=back
Hooks provided:
=over 4
=item pktin($data,$timestamp)
=back
Hooks called:
=over 4
( run in 0.742 second using v1.01-cache-2.11-cpan-df04353d9ac )