我正在阅读模块Net::Pcap::Easy
的一些示例代码段,我遇到了这段代码
my $l3protlen = ord substr $raw_bytes, 14, 1;
my $l3prot = $l3protlen & 0xf0 >> 2; # the protocol part
return unless $l3prot == 4; # return unless IPv4
my $l4prot = ord substr $packet, 23, 1;
return unless $l4prot == '7';
在对原始数据包$ raw_bytes进行总十六进制转储后,我可以看到这是一个以太网帧,而不是TCP / UDP数据包。有人可以解释一下上面的代码是做什么的吗?
答案 0 :(得分:7)
为了解析框架,我查了this page。
现在进入Perl ......
my $l3protlen = ord substr $raw_bytes, 14, 1;
从$raw_bytes
中提取第15个字节(字符),并转换为其序数值(例如,字符' A'将转换为整数65(0x41),假设字符集是ASCII)。这就是Perl如何处理二进制数据,就像它是一个字符串(例如将其传递给substr
),然后让你将二进制值取回并将它们作为数字处理。 (但请记住TMTOWTDI。)
在IPv4帧中,前14个字节是MAC头(目的地和源MAC地址各6个字节,后面是2字节的Ethertype,可能是0x8000 - 你可以检查一下)。在此之后,第15个字节是以太网数据有效负载的开始:它的第一个字节包含Version(高4字节)和DWORD中的Header Length(低4字节)。
现在我觉得在这个示例代码的下一行中有一个错误,但它通常可能会被侥幸所效!
my $l3prot = $l3protlen & 0xf0 >> 2; # the protocol part
在Perl中,>>
的优先级高于&
,因此这相当于
my $l3prot = $l3protlen & (0xf0 >> 2);
或者如果您愿意
my $l3prot = $l3protlen & 0x3c;
因此,这从$l3prot
值中提取位2-5:掩码值0x3c是二进制的0011 1100。因此,例如,值0x86(二进制,1000 0110)将变为0x04(二进制0000 0100)。
实际上是一个正常的' IPv4值是0x45,即协议类型4,报头长度为5个双字。掩盖与0x3c,你得到... 4!但只有侥幸:你已经测试了长度的前2位,而不是协议类型!
这一行肯定是
my $l3prot = ($l3protlen & 0xf0) >> 4;
(注意优先级的括号和4位的移位,而不是2位)。 (我在CPAN documentation中发现了同样的错误,所以我猜它可能已经广泛传播了。)
return unless $l3prot == 4; # return unless IPv4
对于IPv4,我们希望此值为4 - 如果不是,则立即跳出该功能。 (因此上面的错误代码给出了结果,这可以将其解释为IPv4数据包,但仅限运气。)
my $l4prot = ord substr $packet, 23, 1;
现在提取第24个字节并以相同的方式转换为序数值。这是来自IP头的协议字节:
return unless $l4prot == '7';
我们希望这是7 - 如果它不立即跳出该功能。 (根据IANA,7是"基于核心的树" ...但我猜您知道您感兴趣的协议!)