PAYATHON 2026

INetSim 无法创建 netlink socket:Protocol not supported

排障赵师傅

结论

这不是 Perl 语法错误。IPTables::IPv4::IPQueue 尝试创建旧式 IPQUEUE 通信通道时,内核拒绝了对应的 netlink 协议,并返回 EPROTONOSUPPORT,即 Protocol not supported。

最常见的原因是当前内核未提供旧式 ip_queue 功能,或者相关模块尚未加载。Perl 模块已安装,只能说明用户态代码存在,无法证明内核支持它依赖的 IPQUEUE 接口。

iptables -L 只查看 filter 表,而 INetSim 的重定向规则通常还会用到 nat 表,所以不能据此判断所有规则都为空。INetSim 在初始化 IPQUEUE 时已经失败,可能还没来得及创建规则,也可能在退出时清理了已经创建的规则。

确认 Perl 模块能否加载

运行:

perl -MIPTables::IPv4::IPQueue -e \
'print "$IPTables::IPv4::IPQueue::VERSION\n"'

能输出版本号,说明 Perl 已找到该模块。只有出现 Can't locate IPTables/IPv4/IPQueue.pm 时,才需要检查模块的安装路径和 @INC。

也可以单独运行一段与 INetSim 初始化过程类似的代码:

#!/usr/bin/perl

use strict;
use warnings;
use IPTables::IPv4::IPQueue qw(:constants);

my $ipq = IPTables::IPv4::IPQueue->new(
    copy_mode  => IPQ_COPY_PACKET,
    copy_range => 1500,
) or die IPTables::IPv4::IPQueue->errstr . "\n";

print "IPQUEUE handle created successfully\n";

将代码保存为 test-ipqueue.pl,再以 root 权限执行:

sudo perl test-ipqueue.pl

如果依然出现 Unable to create netlink socket: Protocol not supported,就可以排除 INetSim 配置问题。故障出在 IPTables::IPv4::IPQueue 与当前内核之间。

检查旧式 ip_queue 内核模块

先确认模块是否已经加载:

lsmod | grep '^ip_queue'

然后尝试手动加载:

sudo modprobe ip_queue

加载后再次运行测试脚本。

如果 modprobe 返回类似错误:

FATAL: Module ip_queue not found

说明当前运行的内核没有安装该模块,或者编译时未启用旧式 IPQUEUE 支持。可以继续检查模块信息:

modinfo ip_queue
find /lib/modules/"$(uname -r)" -type f -name 'ip_queue.ko*'

再查看当前内核的编译配置:

grep -E 'CONFIG_(NETFILTER|IP_NF_QUEUE|NETFILTER_NETLINK|NETFILTER_NETLINK_QUEUE)=' \
    "/boot/config-$(uname -r)"

与旧式 IPTables::IPv4::IPQueue 直接相关的配置是 CONFIG_IP_NF_QUEUE。常见结果如下:

CONFIG_IP_NF_QUEUE=m

这表示该功能被编译成模块,正常情况下可以通过 modprobe ip_queue 加载。

CONFIG_IP_NF_QUEUE=y

这表示该功能已经直接编译进内核,无须加载模块。

如果找不到该配置,或者结果为:

# CONFIG_IP_NF_QUEUE is not set

说明当前内核不支持这个旧接口。

CONFIG_NETFILTER_NETLINK_QUEUE 对应较新的 NFQUEUE 机制。即使存在这个配置,也不能说明旧版 IPTables::IPv4::IPQueue 可以正常工作。

用 strace 确认内核返回值

可以跟踪最小测试脚本涉及的系统调用:

sudo strace -f -e trace=socket,bind,setsockopt perl test-ipqueue.pl

如果输出中出现类似内容:

socket(AF_NETLINK, SOCK_RAW, NETLINK_FIREWALL) = -1 EPROTONOSUPPORT (Protocol not supported)

说明错误直接来自内核,无须继续修改 Perl 代码。

如果返回的是 EPERM 或 EACCES,则应检查运行用户、root 权限和相关 capability。权限不足通常不会返回 Protocol not supported。

查看 iptables 规则

命令:

sudo iptables -L

默认只列出 filter 表。检查重定向规则时,至少还要查看 nat 表:

sudo iptables -t nat -L -n -v --line-numbers

其他常用表也可以一并检查:

sudo iptables -t filter -L -n -v --line-numbers
sudo iptables -t mangle -L -n -v --line-numbers
sudo iptables -t raw -L -n -v --line-numbers

要查看更完整的规则,可以运行:

sudo iptables-save

还可以搜索 QUEUE 或 NFQUEUE 目标:

sudo iptables-save | grep -E -- '-j (QUEUE|NFQUEUE)'

如果 INetSim 在创建 IPQUEUE handle 时立即终止,可能还没有进入规则安装阶段,也可能在退出时删除了临时规则。因此,规则为空并不与当前错误冲突。

可行的修复方式

1. 模块存在时加载 ip_queue

如果 modinfo ip_queue 能找到模块,加载后重新测试:

sudo modprobe ip_queue
lsmod | grep '^ip_queue'
sudo perl test-ipqueue.pl

测试成功后再启动 INetSim。

2. 补装与当前内核匹配的模块包

部分 Ubuntu 内核会将不常用的模块放在额外的内核模块包中。具体包名取决于当前运行的内核版本,先确认版本:

uname -r

然后检查已经安装的内核包:

dpkg -l | grep -E 'linux-(image|modules)'

需要安装与 uname -r 完全匹配,并且确实包含 ip_queue.ko 的模块包。如果安装的是其他版本的内核包,不要继续用旧内核测试。安装新内核或模块后,应重新启动并再次核对:

uname -r
modinfo ip_queue

3. 使用支持旧式 IPQUEUE 的内核

如果当前内核没有 CONFIG_IP_NF_QUEUE,而所用版本的 INetSim 只能通过 IPTables::IPv4::IPQueue 工作,就需要换用启用了该配置的兼容内核。

这种方案适用于隔离的恶意软件分析实验环境。Ubuntu 12.04 和旧式 IPQUEUE 都已非常老,不宜将此类系统直接暴露在不受信任的网络中。

4. 改用兼容 NFQUEUE 的实现

NFQUEUE 是较新的 Netfilter 数据包队列机制,用户态通常通过 libnetfilter_queue 访问。它与旧式 libipq、ip_queue 和 IPTables::IPv4::IPQueue 使用的不是同一套接口。

因此,不能只把 iptables 规则中的:

-j QUEUE

改为:

-j NFQUEUE

就让原有 Perl 代码继续工作。INetSim 的重定向代码、Perl 绑定和队列处理逻辑都需要支持 NFQUEUE。是否提供这类支持,应以所用 INetSim 版本的代码和文档为准。

建议的排查顺序

按以下顺序检查,可以较快分清问题位于用户态、内核还是规则配置:

uname -r

perl -MIPTables::IPv4::IPQueue -e \
'print "$IPTables::IPv4::IPQueue::VERSION\n"'

modinfo ip_queue
sudo modprobe ip_queue

grep -E 'CONFIG_(IP_NF_QUEUE|NETFILTER_NETLINK_QUEUE)=' \
    "/boot/config-$(uname -r)"

sudo perl test-ipqueue.pl

sudo iptables-save

只要最小 Perl 测试仍返回 EPROTONOSUPPORT,就应先解决内核的 IPQUEUE 支持问题。iptables 命令可以正常执行,或者其他程序能够使用 netlink,都不能证明旧式 NETLINK_FIREWALL/IPQUEUE 通道可用。

备注:内容仅供参考。