我有一个用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";
}
答案 0 :(得分:2)
来自"听eth1"我推断你在以太网上捕获。以太网上最大的数据包大小为1518字节(非标准" jumbo frames")除外,它是:
这意味着(除非网络使用巨型帧),您可以在以太网上发送的最大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;