我编写了一个程序来使用RTM_GETADDR
for family查询 Linux rtnetlink(7) 接口AF_INET
。解析响应我意识到响应的最大部分似乎是IFA_UNSPEC
长度为 88 字节的类型记录(其他部分的长度通常小于 8 字节)。
调试示例输出(仅针对一个接口):
DB<3> r
index 1, family 2, prefixlen 8
flags permanent
host
# len 8, type 1
address 127.0.0.1
# len 8, type 2
local 127.0.0.1
# len 7, type 3
label lo
# len 8, type 8
flags permanent
# len 20, type 6
cacheinfo: prefered forever, valid forever, cstamp 2.31, tstamp 2.31
# len 88, type 0
RT_Netlink::handle_response(lib/RT_Netlink.pm:361):
“len 88, type 0”是IFA_UNSPEC
响应中的一大块。
所以我想知道:那些未指定的块是什么,为什么它们会在响应中发送?
这是手册页所说的:
Attributes
rta_type value type description
─────────────────────────────────────────────────────────────
IFA_UNSPEC - unspecified.
IFA_ADDRESS raw protocol address interface address
IFA_LOCAL raw protocol address local address
IFA_LABEL asciiz string name of the interface
IFA_BROADCAST raw protocol address broadcast address.
IFA_ANYCAST raw protocol address anycast address
IFA_CACHEINFO struct ifa_cacheinfo Address information.
我想我发现了问题:
问题出在响应的解析器中(仿照https://github.com/Yourens/rtnetlinkexample/blob/master/if_show.c中的 C 源代码,因为原始手册页很难理解事情是如何工作的):
我收到的响应消息有以下长度:76、88、88、88
解析器处理的第一条消息是 324 字节,但消息长度实际上只有 52 字节。所以解析器在当前消息结束后以某种方式解析,将下一条消息检测为 type
IFA_UNSPEC
。具体来说,解析的第一条消息有 3 倍 88 字节
IFA_UNSPEC
,而第二条消息有 2 倍 88 字节IFA_UNSPEC
,第三条消息有 1倍 88 字节IFA_UNSPEC
,最后一条消息最终没有IFA_UNSPEC
。当我在调用 IFA_RTA() 之前将 NLMSG_DATA() 的结果截断为 IFA_PAYLOAD() 时,这些
IFA_UNSPEC
属性神奇地消失了。我同意一切听起来都很抽象,没有提出很多问题中没有的代码。
解析响应的基本 Perl 代码是(原始的 C 结构以二进制数据的形式存在,由相应的
__U_
* 例程解包。可能该部分引入了错误,因为示例 C 代码只是在 Perl 中使用子字符串时推进了一个指针):最终的解决方法是将相应的行替换为:
最后,这里有一些调试输出的总结,显示了修复前后的差异:
不幸的是,修复似乎吞噬了类型 6(缓存信息)数据;也许还有更多的错误。
更新:
我找到了解决方案(我认为),改变:
至
IFA_PAYLOAD
似乎是 的长度,IFA_RTA
而不是 的NLMSG_DATA
。整个网络链接“数据包”结构是一个(记录不充分的)谜,甚至可能是“痛苦”。