为了解析帧,我查了this page。
现在到 Perl...
my $l3protlen = ord substr $raw_bytes, 14, 1;
从$raw_bytes 中提取第 15 个字节(字符),并转换为其序数值(例如,假设字符集为 ASCII,字符“A”将转换为整数 65 (0x41))。这就是 Perl 处理二进制数据的方式,就像它是一个字符串一样(例如,将它传递给substr),然后让您将二进制值取回并将它们作为数字处理。 (但请记住TMTOWTDI。)
在 IPv4 帧中,前 14 个字节是 MAC 标头(目标和源 MAC 地址各 6 个字节,随后是 2 个字节的 Ethertype,可能是 0x8000 - 你可以检查一下)。在这之后,第 15 个字节是以太网数据负载的开始:第一个字节包含版本(高 4 字节)和以 DWORD 为单位的标头长度(低 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 是“基于核心的树”......但我想你知道你对哪些协议感兴趣!)