📄 icmpv4.pm
字号:
## $Id: ICMPv4.pm,v 1.3.2.4 2006/06/04 13:36:37 gomor Exp $#package Net::Packet::ICMPv4;use strict;use warnings;use Carp;require Net::Packet::Layer4;our @ISA = qw(Net::Packet::Layer4);use Net::Packet::Utils qw(getRandom16bitsInt getRandom32bitsInt inetChecksum inetAton inetNtoa);use Net::Packet::Consts qw(:icmpv4 :layer);require Net::Packet::IPv4;require Net::Packet::Frame;our @AS = qw( type code checksum identifier sequenceNumber originateTimestamp receiveTimestamp transmitTimestamp addressMask gateway unused error data);__PACKAGE__->cgBuildIndices;__PACKAGE__->cgBuildAccessorsScalar(\@AS);no strict 'vars';sub new { my $self = shift->SUPER::new( type => NP_ICMPv4_TYPE_ECHO_REQUEST, code => NP_ICMPv4_CODE_ZERO, checksum => 0, identifier => getRandom16bitsInt(), sequenceNumber => getRandom16bitsInt(), originateTimestamp => time(), receiveTimestamp => 0, transmitTimestamp => 0, addressMask => 0, gateway => "127.0.0.1", unused => 0, data => "", @_, ); unless ($self->[$__raw]) { #燭his line handles the packing of ICMPv4 Destination unreach IPv4 Frame my $error = $self->[$__error]; $self->[$__data] = $error->raw if $error; } $self;}sub getKey { 'ICMP' }sub getKeyReverse { 'ICMP' }sub recv { my $self = shift; my ($frame) = @_; my $env = $frame->env; for ($env->dump->frames) { next unless $_->timestamp ge $frame->timestamp; if ($frame->l3) { if ($_->isIcmpv4 && $_->l3->src eq $frame->l3->dst) { if ($self->[$__type] == NP_ICMPv4_TYPE_ECHO_REQUEST && $_->l4->type == NP_ICMPv4_TYPE_ECHO_REPLY) { return $_; } elsif ($self->[$__type] == NP_ICMPv4_TYPE_TIMESTAMP_REQUEST && $_->l4->type == NP_ICMPv4_TYPE_TIMESTAMP_REPLY) { return $_; } elsif ($self->[$__type] == NP_ICMPv4_TYPE_INFORMATION_REQUEST && $_->l4->type == NP_ICMPv4_TYPE_INFORMATION_REPLY) { return $_; } elsif ($self->[$__type] == NP_ICMPv4_TYPE_ADDRESS_MASK_REQUEST && $_->l4->type == NP_ICMPv4_TYPE_ADDRESS_MASK_REPLY) { return $_; } } } # DescL4 recv, warning, it may receive a packet targetted at another #爃ost, since no L3 headers is kept at D4 for packet matching else { if ($self->[$__type] == NP_ICMPv4_TYPE_ECHO_REQUEST && $_->l4->type == NP_ICMPv4_TYPE_ECHO_REPLY) { return $_; } elsif ($self->[$__type] == NP_ICMPv4_TYPE_TIMESTAMP_REQUEST && $_->l4->type == NP_ICMPv4_TYPE_TIMESTAMP_REPLY) { return $_; } elsif ($self->[$__type] == NP_ICMPv4_TYPE_INFORMATION_REQUEST && $_->l4->type == NP_ICMPv4_TYPE_INFORMATION_REPLY) { return $_; } elsif ($self->[$__type] == NP_ICMPv4_TYPE_ADDRESS_MASK_REQUEST && $_->l4->type == NP_ICMPv4_TYPE_ADDRESS_MASK_REPLY) { return $_; } } } undef;}my $packTypes = { NP_ICMPv4_TYPE_ECHO_REQUEST() => \&_packEcho, NP_ICMPv4_TYPE_ECHO_REPLY() => \&_packEcho, NP_ICMPv4_TYPE_TIMESTAMP_REQUEST() => \&_packTimestamp, NP_ICMPv4_TYPE_TIMESTAMP_REPLY() => \&_packTimestamp, NP_ICMPv4_TYPE_INFORMATION_REQUEST() => \&_packInformation, NP_ICMPv4_TYPE_INFORMATION_REPLY() => \&_packInformation, NP_ICMPv4_TYPE_ADDRESS_MASK_REQUEST() => \&_packAddressMask, NP_ICMPv4_TYPE_ADDRESS_MASK_REPLY() => \&_packAddressMask, NP_ICMPv4_TYPE_DESTINATION_UNREACHABLE() => \&_packDestUnreach, NP_ICMPv4_TYPE_REDIRECT() => \&_packRedirect, NP_ICMPv4_TYPE_TIME_EXCEEDED() => \&_packTimeExceed,};my $unpackTypes = { NP_ICMPv4_TYPE_ECHO_REQUEST() => \&_unpackEcho, NP_ICMPv4_TYPE_ECHO_REPLY() => \&_unpackEcho, NP_ICMPv4_TYPE_TIMESTAMP_REQUEST() => \&_unpackTimestamp, NP_ICMPv4_TYPE_TIMESTAMP_REPLY() => \&_unpackTimestamp, NP_ICMPv4_TYPE_INFORMATION_REQUEST() => \&_unpackInformation, NP_ICMPv4_TYPE_INFORMATION_REPLY() => \&_unpackInformation, NP_ICMPv4_TYPE_ADDRESS_MASK_REQUEST() => \&_unpackAddressMask, NP_ICMPv4_TYPE_ADDRESS_MASK_REPLY() => \&_unpackAddressMask, NP_ICMPv4_TYPE_DESTINATION_UNREACHABLE() => \&_unpackDestUnreach, NP_ICMPv4_TYPE_REDIRECT() => \&_unpackRedirect, NP_ICMPv4_TYPE_TIME_EXCEEDED() => \&_unpackTimeExceed,};sub getDataLength { my $self = shift; my $data = $self->[$__data]; $data ? length($data) : 0;}sub getLength { my $self = shift; my $dataLength = $self->getDataLength; my $hdrLengths = { NP_ICMPv4_TYPE_ECHO_REQUEST() => 8 + $dataLength, NP_ICMPv4_TYPE_ECHO_REPLY() => 8 + $dataLength, NP_ICMPv4_TYPE_TIMESTAMP_REQUEST() => 20 + $dataLength, NP_ICMPv4_TYPE_TIMESTAMP_REPLY() => 20 + $dataLength, NP_ICMPv4_TYPE_INFORMATION_REQUEST() => 8 + $dataLength, NP_ICMPv4_TYPE_INFORMATION_REPLY() => 8 + $dataLength, NP_ICMPv4_TYPE_ADDRESS_MASK_REQUEST() => 12 + $dataLength, NP_ICMPv4_TYPE_ADDRESS_MASK_REPLY() => 12 + $dataLength, NP_ICMPv4_TYPE_DESTINATION_UNREACHABLE() => 8 + $dataLength, NP_ICMPv4_TYPE_REDIRECT() => 8 + $dataLength, NP_ICMPv4_TYPE_TIME_EXCEEDED() => 8 + $dataLength, }; $hdrLengths->{$self->[$__type]} || 0;}sub _handleType { my $self = shift; my ($format, $fields, $values) = @_; if (@$values) { return($self->SUPER::pack($format, @$values) || undef); } else { my @elts = $self->SUPER::unpack($format, $self->[$__payload]) or return undef; my $n = 0; return { map { $_ => $elts[$n++] } @$fields }; }}sub _packEcho { my $self = shift; $self->_handleType( 'nn', [], [ $self->[$__identifier], $self->[$__sequenceNumber] ] );}sub _unpackEcho { shift->_handleType('nn a*', [ qw(identifier sequenceNumber data) ], []);}sub _packTimestamp { my $self = shift; $self->_handleType('nnNNN', [], [ $self->[$__identifier], $self->[$__sequenceNumber], $self->[$__originateTimestamp], $self->[$__receiveTimestamp], $self->[$__transmitTimestamp] ], );}sub _unpackTimestamp { shift->_handleType( 'nnNNN a*', [ qw(identifier sequenceNumber originateTimestamp receiveTimestamp transmitTimestamp data) ], [], );}#營t has same fields as ICMP echosub _packInformation { shift->_packEcho }sub _unpackInformation { shift->_unpackEcho }sub _packAddressMask { my $self = shift; $self->_handleType('nnN', [], [ $self->[$__identifier], $self->[$__sequenceNumber], $self->[$__addressMask] ], );}sub _unpackAddressMask { shift->_handleType( 'nnN a*', [ qw(identifier sequenceNumber addressMask data) ], [], );}#燩ad ICMP error returned to achieve IP length (from IP request),#燼nd put it as a Frame into error instance datasub _dataToFrame { my $data = shift; my $ip = Net::Packet::IPv4->new(raw => $data); $data .= "\x00" x $ip->length; Net::Packet::Frame->new(raw => $data) or return undef;}sub _packDestUnreach { my $self = shift; $self->_handleType( 'N', [], [ $self->[$__unused] ], );}sub _unpackDestUnreach { my $href = shift->_handleType( 'N a*', [ qw(unused data) ], [], ); $href->{error} = _dataToFrame($href->{data}) if $href->{data}; $href;}sub _packRedirect { my $self = shift; $self->_handleType( 'a4', [], [ inetAton($self->[$__gateway]) ], );}sub _unpackRedirect { my $href = shift->_handleType( 'a4 a*', [ qw(gateway data) ], [], ); $href->{gateway} = inetNtoa($href->{gateway}); $href->{error} = _dataToFrame($href->{data}) if $href->{data}; $href;}sub _packTimeExceed { my $self = shift; $self->_handleType( 'N', [], [ $self->unused ], );}sub _unpackTimeExceed { my $href = shift->_handleType( 'N a*', [ qw(unused data) ], [], ); $href->{error} = _dataToFrame($href->{data}) if $href->{data}; $href;}sub _decodeError { my $self = shift; carp("@{[(caller(0))[3]]}: unknown ICMPv4: ". "type: @{[$self->type]}, code: @{[$self->code]}\n"); undef;}sub pack { my $self = shift; $self->[$__raw] = $self->SUPER::pack('CCn', $self->[$__type], $self->[$__code], $self->[$__checksum], ) or return undef; my $sub = $packTypes->{$self->[$__type]} || \&_decodeError; my $raw = $self->$sub or return undef; if (my $data = $self->[$__data]) { $raw .= $self->SUPER::pack('a*', $data) or return undef; } $self->[$__raw] = $self->[$__raw].$raw; 1;}sub unpack { my $self = shift; my ($type, $code, $checksum, $payload) = $self->SUPER::unpack('CCS a*', $self->[$__raw]) or return undef;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -