Perl Pcap模块无法捕获超过1500字节

时间:2014-05-24 19:59:35

标签: perl pcap

我有一个用perl制作的小型pcap监听器。每当我得到超过1500字节的东西时,它只会打印为1500.

66.0.X.X 1500

现在当我发送一个2000字节的数据包时,我得到了回复,我也尝试发送1600和10k。

无论我为pcap得到什么1500。 我怎么能解决这个问题我看了SNAPLEN但是当我把它设置得不好或者结果时,我得到了相同的结果。

我也尝试了tcpdump,我得到了奇怪的结果,因为你可以看到第一个“长度”是1500,但第二个下面的一行是5000,这就是我发送的。

tcpdump: listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes
21:59:06.142530 IP (tos 0x0, ttl 58, id 45206, offset 0, flags [+], proto UDP (17), length 1500)
    37.X.X.X.48254 > XXX.54: UDP, length 5000

我的代码:

use Net::Pcap;
use NetPacket::Ethernet;
use NetPacket::Ethernet qw(:strip);
use NetPacket::IP;
use NetPacket::IP;
use NetPacket::TCP;
use strict;

my $err;

#   Use network device passed in program arguments or if no 
#   argument is passed, determine an appropriate network 
#   device for packet sniffing using the 
#   Net::Pcap::lookupdev method

my $dev = $ARGV[0];
unless (defined $dev) {
    $dev = Net::Pcap::lookupdev(\$err);
    if (defined $err) {
        die 'Unable to determine network device for monitoring - ', $err;
    }
}

#   Look up network address information about network 
#   device using Net::Pcap::lookupnet - This also acts as a 
#   check on bogus network device arguments that may be 
#   passed to the program as an argument

my ($address, $netmask);
if (Net::Pcap::lookupnet($dev, \$address, \$netmask, \$err)) {
    die 'Unable to look up device information for ', $dev, ' - ', $err;
}

#   Create packet capture object on device

my $object;
$object = Net::Pcap::open_live($dev, 65535, 1, 0, \$err);
unless (defined $object) {
    die 'Unable to create packet capture on device ', $dev, ' - ', $err;
}

#   Compile and set packet filter for packet capture 
#   object - For the capture of TCP packets with the SYN 
#   header flag set directed at the external interface of 
#   the local host, the packet filter of '(dst IP) && (tcp
#   [13] & 2 != 0)' is used where IP is the IP address of 
#   the external interface of the machine.  For 
#   illustrative purposes, the IP address of 127.0.0.1 is 
#   used in this example.

my $filter;
Net::Pcap::compile(
    $object, 
    \$filter, 
    '(port 111)', 
    0, 
    $netmask
) && die 'Unable to compile packet capture filter';
Net::Pcap::setfilter($object, $filter) &&
    die 'Unable to set packet capture filter';

#   Set callback function and initiate packet capture loop

Net::Pcap::loop($object, -1, \&process_packet, '') ||
    die 'Unable to perform packet capture';

Net::Pcap::close($object);


    sub process_packet {
    my ($user_data, $hdr, $pkt) = @_;
    my $ip_obj = NetPacket::IP->decode(eth_strip($pkt));
        #print("$ip_obj->{src_ip} -> $ip_obj->{dest_ip} $ip_obj->{caplen}\n");
    warn "packet!\n";
    my %header = %$hdr;
    #process_packet(\%header, $pkt);
    my $len = length $pkt;
    my $fag = length $user_data;
    my $fag2 = length $hdr;
    warn "$header{len} $header{caplen} $len $fag $fag2\n"; 
}

2 个答案:

答案 0 :(得分:2)

来自"听eth1"我推断你在以太网上捕获。以太网上最大的数据包大小为1518字节(非标准" jumbo frames")除外,它是:

  • 14字节以太网标头;
  • 1500字节以太网有效载荷;
  • 最后4个字节的帧校验序列。

这意味着(除非网络使用巨型帧),您可以在以太网上发送的最大IP数据包为1500字节。

因此,如果您尝试在以太网上通过UDP-over-IPv4发送5000字节的数据,那么当添加8字节UDP标头时,这将成为5008字节的UDP数据包,并且将成为5028-添加IPv4标头时的字节或更大的IPv4数据包(IPv4标头的最小大小为20字节,如果数据包中有选项,则可以更大)。这对于以太网来说太大了,因此您机器上协议堆栈中的IP层将会#34; fragment"该数据包分成多个较小的IP数据包,并且,如果所有这些数据包到达目标机器,其IP层将重新组合成更大的IP数据包,然后将重组数据包的IP有效负载交给UDP层,因此程序接收UDP数据包将看到所有5000个字节。

你的tcpdump输出是第一个片段的输出;从IP报头中提取的分组的IP层总长度是1500(IP长度字段包括IP报头和有效载荷的长度),但UDP层长度是从UDP报头中提取的(通常适合第一个片段),是5000。

这与快照长度无关;它与IP工作方式和以太网上的最大数据包大小有关。

答案 1 :(得分:0)

根据评论的建议,我决定尝试Net::Pcap::Easy而不是Net::Pcap。如前模块的pod中所述:“ Net :: Pcap非常棒,但很难引导”。

以下代码解决了我的问题:

use strict;
use warnings;
use Net::Pcap::Easy;

# all arguments to new are optoinal
my $npe = Net::Pcap::Easy->new(
    dev              => "eth1",
    filter           => "port 111",
    packets_per_loop => 10,
    bytes_to_capture => 1024,
    timeout_in_ms    => 0, # 0ms means forever
    promiscuous      => 0, # true or false

        udp_callback => sub {
my ($npe, $ether, $ip, $udp, $header ) = @_;
       print "UDP: $ip->{src_ip}:$udp->{src_port}"
         . " -> $ip->{dest_ip}:$udp->{dest_port} $udp->{len}\n";
},

#    tcp_callback => sub {
#        my ($npe, $ether, $ip, $tcp, $header ) = @_;
#        my $xmit = localtime( $header->{tv_sec} );
# 
#        print "$xmit TCP: $ip->{src_ip}:$tcp->{src_port}"
#         . " -> $ip->{dest_ip}:$tcp->{dest_port}\n";
# 
#    },
# 
#    icmp_callback => sub {
#        my ($npe, $ether, $ip, $icmp, $header ) = @_;
#        my $xmit = localtime( $header->{tv_sec} );
# 
#        print "$xmit ICMP: $ether->{src_mac}:$ip->{src_ip}"
#         . " -> $ether->{dest_mac}:$ip->{dest_ip}\n";
#    },
);

1 while $npe->loop;