Linux 使用perl确定IPv4数据包的源端口

Linux 使用perl确定IPv4数据包的源端口,linux,perl,ip,tun,Linux,Perl,Ip,Tun,我有一个从TunTap接口读取和处理IPv4数据包的perl脚本。稍微简化一下,它看起来是这样的: #!/usr/bin/perl use warnings; use strict; use Common; use Linux::TunTap; use NetPacket::IP; use IO::Socket; $|++; ###### Predecs ##### my $tun; my %config = Loadconfig(); $tun = Linux::TunTap->ne

我有一个从TunTap接口读取和处理IPv4数据包的perl脚本。稍微简化一下,它看起来是这样的:

#!/usr/bin/perl
use warnings;
use strict;
use Common;
use Linux::TunTap;
use NetPacket::IP;
use IO::Socket;
$|++;

###### Predecs #####
my $tun;
my %config = Loadconfig();

$tun = Linux::TunTap->new(NAME => $config{'localtun_name'})
or die "Couldn't connect to Interface $config{localtun_name}\n";
print "Interface up: " . $tun->{interface} . "\n";

while (my $rawdata = $tun->get_raw()) {
        $rawdata =~ s/^....//; # Strip the TunTap header
        my $packet = NetPacket::IP->decode($rawdata);
        print "$packet->{id} $packet->{src_ip} -> $packet->{dest_ip} $packet->{proto} $packet->{len}\n";
        # Do some processing here
}

出于路由原因,我需要知道数据的源端口。我还没有找到一种使用
NetPacket::IP
实现这一点的方法,所以有没有其他方法来确定这一点?由于调试原因,我目前仅使用
NetPacket::IP
,因此我没有真正设置该模块,特别是如果其他模块允许我提取序列号、大小、源IP、,和目标IP。

NetPacket::IP
只处理没有端口概念的IP数据包。端口仅在TCP/UDP(或您在IP上分层的任何端口)层起作用,因此您需要例如
NetPacket::TCP
来获取此信息。您可能需要查看$packet->{proto}来决定要将哪个模块(TCP或UDP)用于第4层解析

如果您确定不需要更高级别的
NetPacket
模块所需要的额外报头字段,那么您可以利用TCP和UDP的源端口都位于报头的前16位这一事实,因此您可以说

# Untested, so I'm not sure about the case returned in
# $packet->{proto}
if($packet->{proto} eq 'tcp' or $packet->{proto} eq 'udp') {
    $port = unpack('n', $packet->{data});
    ...
}

编辑:顺便说一句,如果需要的话,使用substr()代替regexp替换应该会更快。

干杯,今晚将测试这是否符合我的需要,并重新评估将整个项目在模型中向下移动一层好的,尝试一下。我现在能够从其他模块中提取src_端口(
NetPacket::TCP
NetPacket::UDP
)。至于代码片段,
$packet->{proto}
返回一个协议号(TCP为6),因此这里只有一个轻微的更改,但是,
解包('n',$packet->{data})的结果
与我通过
$tcppacket->{'src_port'}
得到的不同。解包功能有没有可能被错误使用?在不应该有源端口的ICMP数据包上进行测试时,
unpack()
-line yelds 2048您分别从
unpack()
$tcppacket->{src_port}
中得到了什么?如果你看一下
NetPacket::TCP::decode()
,你会发现它们完全是这样做的,只是有更多的字段:
($self->{src_port},$self->{dest_port},$self->{seqnum},$self->{acknum},$tmp,$self->{winsize},$self cksum},$self cksum},$self->{cksum},$self
您从ICMP数据包中获取虚假值的原因很简单,因为您正在解码与TCP/UDP中的端口号位于同一位置的类型和代码字段。在使用telnet连接进行测试时,
unpack()
方法给出45696,而
$packet->{src_port}
给出17680。然而,在剥离前7个字节时,我正在对
Linux::TunTap
提供的原始数据使用
unpack()
,而
$packet->{src_port}
正在使用
NetPacket::TCP
方法从所述原始数据创建的
NetPacket::TCP
对象。也许我说的不对?不,那不可能是对的。为什么是7字节?IPv4标头的长度介于20到60字节之间,具体取决于选项。您可以使用tcpdump或wireshark检查哪个端口值是正确的。