Iptables -m connlimit导致内存不足

原创 一口Linux 2025-06-12 11:00

击左上方蓝色“一口Linux”,选择“设为星标

第一时间看干货文章

【干货】嵌入式驱动工程师学习路线
【干货】Linux嵌入式知识点-思维导图-免费获取
【就业】一个可以写到简历的基于Linux物联网综合项目
【就业】简历模版


图片


1. 问题描述:

Udp 高频攻击导致slab kmalloc-64 持续申请,导致内存不足。A7低版本内核无该问题,MA35/AM62在kernel6版本上也无该问题,此问题只出在A7 kernel6上。 问题环境(kernel6.6) iptables在不同环境下的版本相同

[root@evse ~]# uname -a
Linux evse 6.6.90-gf2b2a1246566 #1 SMP PREEMPT Wed Jun 4 15:06:07 CST 2025
armv7l GNU/Linux
[root@evse ~]# cat /proc/cpuinfo
processor : 0
model name : ARMv7 Processor rev 5 (v7l)
BogoMIPS : 64.00
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva
idivt vfpd32 lpae
CPU implementer : 0x41
CPU architecture: 7
CPU variant : 0x0
CPU part : 0xc07
CPU revision : 5
Hardware : Freescale i.MX6 Ultralite (Device Tree)
Revision : 0000
Serial : d9656bca271e39d4
[root@evse ~]#

2. 测试命令

删除规则与查看规则:

iptables -D INPUT 1
iptables -L INPUT --line-numbers

两条问题规则(-m connlimit ):

iptables -A INPUT -p udp -m connlimit --connlimit-above 60 --connlimit-mask 32 -m limit --limit
2/min -j LOG --log-prefix "UDP Flood Limit Exceeded: "
 
iptables -A INPUT -p udp -m connlimit --connlimit-above 60 --connlimit-mask 32 -j DROP

虚拟机对目标机使用不同间隔进行攻击:

sudo hping3 --udp -s 6666 -p 443 --flood 192.168.88.206 kmalloc-64 持续增加
sudo hping3 --udp -s 6666 -p 443 -i u2000 192.168.88.206 kmalloc-64 不持续增加
sudo hping3 --udp -s 6666 -p 443 -i u200 192.168.88.206 kmalloc-64 不持续增加
sudo hping3 --udp -s 6666 -p 443 -i u20 192.168.88.206 kmalloc-64 持续增加 ,删除规则后,kmalloc-64恢复原来较低数值。若此时不删除规则,并且停止-i u20 攻击, kmalloc-64 会一直保持原高值不变,若此时再使用-i u200 进行攻击,kmalloc-64 会在原来高值情况下慢慢减小,最终回到内存正常状态。

通过如下命令可查看有问题时,可用内存下降, kmalloc-64 会持续增加

watch -n1 cat /proc/meminfo |grep "MemFree"
watch -n1 "awk 'NR==1; NR>1 {print | \"sort -k2 -nr | head -n 11\"}' /proc/slabinfo"
watch -n1 iptables -L -vn

3. kernel4.14.98 (无问题)

此内核无该类问题,规则生效,但内存不会增长。

注意:该环境iptables两条udp规则和洪涝攻击并不会导致内存泄露,但是产品线S83中的preconf会导致空闲内存越来越少。(因固件包过老,暂不查产品线的问题)

4. kernel6.6 (有问题)

4.1 kmalloc-64 内存异常

  • 第一列: slab 缓存的名称,
  • 第二列(active_objs) :当前活跃的对象数量,
  • 第三列(num_objs) :缓存中总对象数量(包括活跃和非活跃),
  • 第四列(objsize):每个对象的大小(字节),
  • 第五列(objperslab) :每个 slab 页能存放的对象数量,
  • 第六列(pagesperslab) :每个 slab 占用的内存页数, 通常为 1。

tunables 部分可调参数(通常为 0,表示使用默认值)slabdata 部分 • 第一个值:活跃的 slab 页数量。(因每个slab占用内存物理页为1个,也可认为此值是该slab的个 数) • 第二个值:总 slab 页数量。 • 第三个值:共享 slab 页数量 总对象个数=slab组数每组对象 如 82176=128464 其中81887为当前活跃的对象

slab内存回收是以slab单个节点来回收,一个slab控制器包含多个obj,只有所有obj都非活跃状态,slab节点才会被系统回收。所有只有释放obj,后续才有slab内存回收。

当删除规则,kmalloc-64立即回到原先正常大小。或者在不删除规则的环境下,此时再降速攻击,kmalloc-64便会慢慢释放,最终变回原先大小:

4.2 优化系统参数(缩减超时时间):无效

echo 300 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
echo 1 > /proc/sys/net/netfilter/nf_conntrack_tcp_be_liberal
echo 1 > /proc/sys/net/netfilter/nf_conntrack_generic_timeout
echo 5 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout
echo 1 > /proc/sys/net/netfilter/nf_conntrack_icmp_timeout

4.3 内核调整:有效

CONFIG_HZ_1000 CONFIG_HZ=1000 ----- 在答疑Q2中详细说明原因
CONNCOUNT_GC_MAX_NODES 从8设置成64 ----- 增加单次释放节点的个数,查找资料64适合高并
发的攻击环境
if ((u32)jiffies == list->last_gc) 改成 if ((u32)jiffies == READ_ONCE(list->last_gc)) -------以保读取最新
值,

禁止编译器优化为重复读取或重排指令

单核设备应配置CONFIG_NR_CPUS=1 ,并关闭CONFIG_SMP 以匹配硬件 -----a7所有配置都应做此调整

4.4 代码追踪

iptables -A INPUT -p udp -m connlimit --connlimit-above 60 --connlimit-mask 32 -j DROP 

规则会 触发 connlimit_mt_check -> nf_conncount_init insert_tree

iptables -D INPUT 1删除上述规则,会触发connlimit_mt_destroy -> nf_conncount_destroy ->destroy_tree

使用sudo hping3 --udp -s 6666 -p 443 -i u2000000 192.168.88.206进行攻击: 因间隔为2秒,非高频攻击状态,无包被DROP, 此时无__nf_conncount_add 和conn_free 函数的 执行。

4.4.1 节点创建:

__nf_conncount_add -> kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC) (此函数便是分配slab的缓存对象)

4.4.2 节点释放:

find_or_evict 用来查找过期节点,并将其释放。


    1. 在添加节点时释放
__nf_conncount_add -> find_or_evict -> conn_free ->
kmem_cache_free(conncount_conn_cachep, conn) 

(此函数便是释放slab的缓存对象)


    1. 在其他处释放
connlimit_mt ->
nf_conncount_count ->
count_tree -> nf_conncount_gc_list -> find_or_evict
   -> insert_tree -> nf_conncount_gc_list -> find_or_evict
        - > schedule_gc_worker -> schedule_gc_worker -> schedule_work

schedule_work 触发工作队列去执行 tree_gc_worker -> nf_conncount_gc_list -> find_or_evict

connlimit_mt 主要用于限制单个 IP 的连接数

nf_conncount_count 统计当前键值对应的连接数

4.5 攻击测试

4.5.1 使用sudo hping3 --udp -s 6666 -p 443 -i u200000 192.168.88.206 进行

攻击6秒左右:

Welcome to EVSE
evse login: [ 106.484184] **[connlimit_mt_check:95]**
[ 106.488585] **[nf_conncount_init:539]**
[ 110.288686] **[insert_tree:366]**
Welcome to EVSE
evse login:
Welcome to EVSE
evse login:
Welcome to EVSE
evse login:
Welcome to EVSE
evse login: [ 132.168009] **[insert_tree:366]**
[ 132.377315] **[__nf_conncount_add:186]**
[ 132.588389] **[__nf_conncount_add:186]**
[ 132.792491] **[__nf_conncount_add:186]**
[ 132.992824] **[__nf_conncount_add:186]**
[ 133.196611] **[__nf_conncount_add:186]**
[ 133.398087] **[__nf_conncount_add:186]**
[ 133.602361] **[__nf_conncount_add:186]**
[ 133.810499] **[__nf_conncount_add:186]**
[ 134.013903] **[__nf_conncount_add:186]**
[ 134.215048] **[__nf_conncount_add:186]**
[ 134.420325] **[__nf_conncount_add:186]**
[ 134.625043] **[__nf_conncount_add:186]**
[ 134.825720] **[__nf_conncount_add:186]**
[ 135.028171] **[__nf_conncount_add:186]**
[ 135.230085] **[__nf_conncount_add:186]**
[ 135.430352] **[__nf_conncount_add:186]**
[ 135.631057] **[__nf_conncount_add:186]**
[ 135.835375] **[__nf_conncount_add:186]**
[ 136.044689] **[__nf_conncount_add:186]**
[ 136.249517] **[__nf_conncount_add:186]**
[ 136.449621] **[__nf_conncount_add:186]**
[ 136.652949] **[__nf_conncount_add:186]**

4.5.2 上一步前提下,过一段时间再使用sudo hping3 --udp -s 6666 -p 443 -i u200000 192.168.88.206 进行攻击2秒左右,从打印可看到先释放原先创建的节点:

[ 246.340577] **[conn_free:92]**
[ 246.343988] **[conn_free:92]**
[ 246.347228] **[conn_free:92]**
[ 246.350448] **[conn_free:92]**
[ 246.353663] **[conn_free:92]**
[ 246.356968] **[conn_free:92]**
[ 246.360190] **[conn_free:92]**
[ 246.363408] **[conn_free:92]**
[ 246.366622] **[conn_free:92]**
[ 246.369831] **[__nf_conncount_add:186]**
[ 246.544568] **[conn_free:92]**
[ 246.547849] **[conn_free:92]**
[ 246.551030] **[conn_free:92]**
[ 246.554201] **[conn_free:92]**
[ 246.557367] **[conn_free:92]**
[ 246.560535] **[conn_free:92]**
[ 246.563701] **[conn_free:92]**
[ 246.566866] **[conn_free:92]**
[ 246.570031] **[conn_free:92]**
[ 246.573193] **[__nf_conncount_add:186]**
[ 246.749883] **[conn_free:92]**
[ 246.753196] **[conn_free:92]**
[ 246.756645] **[conn_free:92]**
[ 246.759876] **[conn_free:92]**
[ 246.763095] **[conn_free:92]**
[ 246.766407] **[__nf_conncount_add:186]**
[ 246.961836] **[__nf_conncount_add:186]**
[ 247.162273] **[__nf_conncount_add:186]**
[ 247.362697] **[__nf_conncount_add:186]**
[ 247.563052] **[__nf_conncount_add:186]**

4.5.3 断电重启后,使用sudo hping3 --udp -s 6666 -p 443 -i u200000 192.168.88.206 进行攻击30秒左右

可以看到先连续创建前60个(200ms一帧,12秒正好60个),期间没有conn_free,这是因为之前**-- connlimit-above 60** 参数的原因,可以看到后期每增加一个节点,便会释放一个节点。内核的nf_conncount 模块会优先释放最早创建的连接 (FIFO策略)。

Welcome to EVSE
evse login: [ 6588.953200] **[connlimit_mt_check:95]**
[ 6588.964224] **[nf_conncount_init:539]**
Welcome to EVSE
evse login: [ 6623.889501] **[insert_tree:366]**
[ 6624.092922] **[__nf_conncount_add:186]**
[ 6624.293990] **[__nf_conncount_add:186]**
[ 6624.496559] **[__nf_conncount_add:186]**
[ 6624.704156] **[__nf_conncount_add:186]**
[ 6624.905262] **[__nf_conncount_add:186]**
[ 6625.117401] **[__nf_conncount_add:186]**
[ 6625.332664] **[__nf_conncount_add:186]**
[ 6625.534785] **[__nf_conncount_add:186]**
[ 6625.735500] **[__nf_conncount_add:186]**
[ 6625.936776] **[__nf_conncount_add:186]**
[ 6626.142550] **[__nf_conncount_add:186]**
[ 6626.464095] **[__nf_conncount_add:186]**
[ 6626.672264] **[__nf_conncount_add:186]**
[ 6626.876006] **[__nf_conncount_add:186]**
[ 6627.080153] **[__nf_conncount_add:186]**
[ 6627.280599] **[__nf_conncount_add:186]**
[ 6627.485330] **[__nf_conncount_add:186]**
[ 6627.688502] **[__nf_conncount_add:186]**
[ 6627.890940] **[__nf_conncount_add:186]**
[ 6628.093806] **[__nf_conncount_add:186]**
[ 6628.313874] **[__nf_conncount_add:186]**
[ 6628.515991] **[__nf_conncount_add:186]**
[ 6628.720403] **[__nf_conncount_add:186]**
[ 6628.924391] **[__nf_conncount_add:186]**
[ 6629.126770] **[__nf_conncount_add:186]**
[ 6629.330207] **[__nf_conncount_add:186]**
[ 6629.533838] **[__nf_conncount_add:186]**
[ 6629.734090] **[__nf_conncount_add:186]**
[ 6629.934281] **[__nf_conncount_add:186]**
[ 6630.135378] **[__nf_conncount_add:186]**
[ 6630.335804] **[__nf_conncount_add:186]**
[ 6630.537249] **[__nf_conncount_add:186]**
[ 6630.740110] **[__nf_conncount_add:186]**
[ 6630.942853] **[__nf_conncount_add:186]**
[ 6631.143030] **[__nf_conncount_add:186]**
[ 6631.346782] **[__nf_conncount_add:186]**
[ 6631.547754] **[__nf_conncount_add:186]**
[ 6631.747852] **[__nf_conncount_add:186]**
[ 6631.948470] **[__nf_conncount_add:186]**
[ 6632.152779] **[__nf_conncount_add:186]**
[ 6632.364964] **[__nf_conncount_add:186]**
[ 6632.576077] **[__nf_conncount_add:186]**
[ 6632.796017] **[__nf_conncount_add:186]**
[ 6632.997078] **[__nf_conncount_add:186]**
[ 6633.203338] **[__nf_conncount_add:186]**
[ 6633.406403] **[__nf_conncount_add:186]**
[ 6633.607636] **[__nf_conncount_add:186]**
[ 6633.812599] **[__nf_conncount_add:186]**
[ 6634.024786] **[__nf_conncount_add:186]**
[ 6634.225224] **[__nf_conncount_add:186]**
[ 6634.427251] **[__nf_conncount_add:186]**
[ 6634.642583] **[__nf_conncount_add:186]**
[ 6634.842924] **[__nf_conncount_add:186]**
[ 6635.042996] **[__nf_conncount_add:186]**
[ 6635.243920] **[__nf_conncount_add:186]**
[ 6635.461265] **[__nf_conncount_add:186]**
[ 6635.670469] **[__nf_conncount_add:186]**
[ 6635.871427] **[__nf_conncount_add:186]**
[ 6636.079939] **[__nf_conncount_add:186]**
[ 6636.280148] **[__nf_conncount_add:186]**
[ 6636.481285] **[conn_free:92]**
[ 6636.484515] **[__nf_conncount_add:186]**
[ 6636.682712] **[conn_free:92]**
[ 6636.686019] **[__nf_conncount_add:186]**
[ 6636.883322] **[conn_free:92]**
[ 6636.886627] **[__nf_conncount_add:186]**
[ 6637.093071] **[conn_free:92]**
[ 6637.096471] **[__nf_conncount_add:186]**
[ 6637.308856] **[conn_free:92]**
[ 6637.312146] **[__nf_conncount_add:186]**
[ 6637.509549] **[conn_free:92]**
[ 6637.512862] **[__nf_conncount_add:186]**
[ 6637.715686] **[conn_free:92]**
[ 6637.718980] **[__nf_conncount_add:186]**
[ 6637.918133] **[conn_free:92]**
[ 6637.921462] **[__nf_conncount_add:186]**
[ 6638.122847] **[conn_free:92]**
[ 6638.126249] **[__nf_conncount_add:186]**
[ 6638.346137] **[conn_free:92]**
 
[ 6638.349367] **[__nf_conncount_add:186]**
[ 6638.562855] **[conn_free:92]**
[ 6638.566084] **[__nf_conncount_add:186]**

4.5.4 若使用sudo hping3 --udp -s 6666 -p 443 -i u20 192.168.88.206 进行高频攻击

我们可以看到创建节点速度要明显快于释放。Kernel 6.6对连接跟踪模块进行了重构,新增了更严格的连接状态检查机制,导致处理每个连接需要更多CPU周期。

创建快是因为仅需分配内存,而释放需完成哈希表操作、状态清理等耗时步骤。

[10060.558838] **[__nf_conncount_add:186]**
[10060.558854] **[__nf_conncount_add:186]**
[10060.558873] **[__nf_conncount_add:186]**
[10060.558889] **[__nf_conncount_add:186]**
[10060.558907] **[__nf_conncount_add:186]**
[10060.559033] **[__nf_conncount_add:186]**
[10060.559058] **[__nf_conncount_add:186]**
[10060.559081] **[__nf_conncount_add:186]**
[10060.559098] **[__nf_conncount_add:186]**
[10060.559116] **[__nf_conncount_add:186]**
[10060.559134] **[__nf_conncount_add:186]**
[10060.559152] **[__nf_conncount_add:186]**
[10060.559170] **[__nf_conncount_add:186]**
[10060.559294] **[__nf_conncount_add:186]**
[10060.559318] **[__nf_conncount_add:186]**
[10060.559342] **[__nf_conncount_add:186]**
[10060.559360] **[__nf_conncount_add:186]**
[10060.559380] **[__nf_conncount_add:186]**
[10060.559399] **[__nf_conncount_add:186]**
[10060.559417] **[__nf_conncount_add:186]**
[10060.559436] **[__nf_conncount_add:186]**
[10060.559562] **[__nf_conncount_add:186]**
[10060.559587] **[__nf_conncount_add:186]**
[10060.559607] **[__nf_conncount_add:186]**
[10060.559624] **[__nf_conncount_add:186]**
[10060.559642] **[__nf_conncount_add:186]**
[10060.559660] **[__nf_conncount_add:186]**
[10060.559678] **[__nf_conncount_add:186]**
[10060.559696] **[__nf_conncount_add:186]**
[10060.559833] **[__nf_conncount_add:186]**
[10060.559861] **[__nf_conncount_add:186]**
[10060.559880] **[__nf_conncount_add:186]**
[10060.559899] **[__nf_conncount_add:186]**
[10060.559918] **[__nf_conncount_add:186]**
[10060.559936] **[__nf_conncount_add:186]**
[10060.559954] **[__nf_conncount_add:186]**
[10060.559972] **[__nf_conncount_add:186]**
[10060.560100] **[__nf_conncount_add:186]**
[10060.560125] **[__nf_conncount_add:186]**
[10060.560147] **[__nf_conncount_add:186]**
[10060.560164] **[__nf_conncount_add:186]**
[10060.560182] **[__nf_conncount_add:186]**
[10060.560201] **[__nf_conncount_add:186]**
[10060.560219] **[__nf_conncount_add:186]**
[10060.560239] **[__nf_conncount_add:186]**
[10060.560371] **[__nf_conncount_add:186]**
[10060.560394] **[__nf_conncount_add:186]**
[10060.560413] **[__nf_conncount_add:186]**
[10060.560429] **[__nf_conncount_add:186]**
[10060.560445] **[__nf_conncount_add:186]**
[10060.560482] **[__nf_conncount_add:186]**
[10060.560500] **[__nf_conncount_add:186]**
[10060.560518] **[__nf_conncount_add:186]**
[10060.560646] **[__nf_conncount_add:186]**
[10060.560671] **[__nf_conncount_add:186]**
[10060.560688] **[__nf_conncount_add:186]**
[10060.560705] **[__nf_conncount_add:186]**
[10060.560842] **[conn_free:92]**
[10060.560870] **[conn_free:92]**
[10060.560883] **[conn_free:92]**
[10060.560895] **[conn_free:92]**
[10060.560906] **[conn_free:92]**
[10060.560917] **[conn_free:92]**
[10060.560929] **[conn_free:92]**
[10060.560940] **[conn_free:92]**
[10060.560952] **[conn_free:92]**
[10060.560961] **[__nf_conncount_add:186]**
[10060.560982] **[__nf_conncount_add:186]**
[10060.561001] **[__nf_conncount_add:186]**
[10060.561018] **[__nf_conncount_add:186]**
[10060.561171] **[__nf_conncount_add:186]**
[10060.561201] **[__nf_conncount_add:186]**
[10060.561222] **[__nf_conncount_add:186]**
[10060.561240] **[__nf_conncount_add:186]**
[10060.561257] **[__nf_conncount_add:186]**
[10060.561274] **[__nf_conncount_add:186]**
[10060.561290] **[__nf_conncount_add:186]**
[10060.561307] **[__nf_conncount_add:186]**
[10060.561439] **[__nf_conncount_add:186]**
 
[10060.561463] **[__nf_conncount_add:186]**
[10060.561480] **[__nf_conncount_add:186]**
[10060.561497] **[__nf_conncount_add:186]**
[10060.561513] **[__nf_conncount_add:186]**
[10060.561531] **[__nf_conncount_add:186]**
[10060.561547] **[__nf_conncount_add:186]**
[10060.561563] **[__nf_conncount_add:186]**
[10060.561688] **[__nf_conncount_add:186]**
[10060 561712] **[ f t dd:186]**

5 答疑

Q1: 从下面的代码可以看到slab描述符的名称应为nf_conncount_tuple,为何在proc/slabinfo中没有?而出现增长的slab名称确是malloc-64?

conncount_conn_cachep = kmem_cache_create("nf_conncount_tuple",
sizeof(struct nf_conncount_tuple),
00NULL);

slab描述符nf_conncount_tuple未在/proc/slabinfo显示,因为对象尺寸与通用缓存匹配且未强制独 立分配,内核会复用 malloc-64 缓存,所以在高频攻击下是malloc-64持续增加。

Q2: 为何Udp 高频攻击导致slab kmalloc-64 持续申请,导致内存不足?

高频攻击,有一个新连接便生成一个节点(add_new_node),就会申请一个slab对象(kmem_cache_alloc) 。 其中find_or_evict函数是用来释放无效过期节点,注意if ((u32)jiffies == READ_ONCE(list->last_gc))的判断逻辑,A7原CONFIG_HZ=100,也就是一个jiffies的单位就是10ms,当在这10ms时间内,这个函数直接到add_new_node出申请对象,而调过了释放无效过期的逻辑。当高频下(比如u20),10ms内就有500个节点要连续申请。

在下一个10ms才会到find_or_evict的释放逻辑,这样内存申请过于密集。

find_or_evict的释放逻辑还有注意点,每次它只释放9个节点,当释放完9个后,find_or_evict函数就返回。

这样就可知道高频攻击下,因节点在短时间创建过多节点,而一次释放最多9个,随着时间的积累,内存会逐渐被kmalloc-64所消耗。

所以kernel6需做如下调整:CONFIG_HZ_1000 CONFIG_HZ=1000 CONNCOUNT_GC_MAX_NODES从8设置成64(64值适合高并发环境)。 (后期其他平台用非rt内核kernel6,也需关注此处)

static int __nf_conncount_add(struct net *net,
struct nf_conncount_list *list,
const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_zone *zone)
{
 const struct nf_conntrack_tuple_hash *found;
 struct nf_conncount_tuple *conn, *conn_n;
 struct nf_conn *found_ct;
 unsigned int collect = 0;
 if ((u32)jiffies == READ_ONCE(list->last_gc))
  goto add_new_node;
  /* check the saved connections */
  list_for_each_entry_safe(conn, conn_n, &list->head, node) {
   if (collect > CONNCOUNT_GC_MAX_NODES)
    break;
   found = find_or_evict(net, list, conn);
   if (IS_ERR(found)) {
    /* Not found, but might be about to be confirmed */
    if (PTR_ERR(found) == -EAGAIN) {
     if (nf_ct_tuple_equal(&conn->tuple, tuple) &&
     nf_ct_zone_id(&conn->zone, conn->zone.dir)
     ==
     nf_ct_zone_id(zone, zone->dir))
    return 0/* already exists */
   } else {
    collect++;
   }
  continue;
  }
  found_ct = nf_ct_tuplehash_to_ctrack(found);
  
  if (nf_ct_tuple_equal(&conn->tuple, tuple) &&
  nf_ct_zone_equal(found_ct, zone, zone->dir)) {
   /*
   * We should not see tuples twice unless someone hooks
   * this into a table without "-p tcp --syn".
   *
   * Attempt to avoid a re-add in this case.
   */

   nf_ct_put(found_ct);
   return 0;
  } else if (already_closed(found_ct)) {
   /*
   
   * we do not care about connections which are
   * closed already -> ditch it
   */

   nf_ct_put(found_ct);
   conn_free(list, conn);
   collect++;
   continue;
  }
  nf_ct_put(found_ct);
 }
 add_new_node:
 if (WARN_ON_ONCE(list->count > INT_MAX))
  return -EOVERFLOW;
 conn = kmem_cache_alloc(conncount_conn_cachep, GFP_ATOMIC);
 if (conn == NULL)
  return -ENOMEM;
 conn->tuple = *tuple;
 conn->zone = *zone;
 conn->cpu = raw_smp_processor_id();
 conn->jiffies32 = (u32)jiffies;
 list_add_tail(&conn->node, &list->head);
 list->count++;
 list->last_gc = (u32)jiffies;
 return 0;
}

Q3:删除规则后,kmalloc-64恢复原来较低数值?

iptables -D INPUT 1删除规则,会触发connlimit_mt_destroy -> nf_conncount_destroy ->destroy_tree -> kmem_cache_free ,便会把所用的slab对象全部释放,所以kmalloc-64恢复原来较低 数值。

Q4:若此时不删除规则,暂停攻击, kmalloc-64 会一直保持原高值不变?

find_or_evict函数是用来释放无效过期节点,虽然find_or_evict除了在我们介绍的 __nf_conncount_add函数里被调用,还会在其他几个函数中被调用。

但是通过日志追踪,实际find_or_evict只在__nf_conncount_add中执行。那么只有新节点过来,才会进入find_or_evict函数来释放内存,所以暂停攻击,kmalloc-64 就会一直保持原高值不变。

Q5:若此时再使用低频进行攻击, kmalloc-64 会在原来高值情况下慢慢减小,最终回到内存正常状态?

当低频攻击时,__nf_conncount_add的在10ms内直接add_new_node就会少,同时find_or_evict函数一次最多可以释放9个对象。这样释放节点数快于新节点的创建,所以kmalloc-64 会在原来高值情况下慢慢减小,最终会回到内存正常状态。

Q6:find_or_evict会在多个函数被调用,为何实际只在__nf_conncount_add中执行?如果其他函数也会调用,这样释放节点就加快了,也可以避免该问题。

之前过分析的代码:

connlimit_mt ->
nf_conncount_count ->
count_tree -> nf_conncount_gc_list -> find_or_evict
 -> insert_tree -> nf_conncount_gc_list -> find_or_evict
  - > schedule_gc_worker -> schedule_gc_worker -> schedule_work

schedule_work 触发工作队列去执行tree_gc_worker -> nf_conncount_gc_list -> find_or_evict

首先对Q4的补充: connlimit_mt 和 __nf_conncount_add 均包含节点释放逻辑,但两者的触发条件均依赖数据包的主动进入。 当高频攻击停止且无新数据包进入时,由于缺乏触发条件,已分配的 kmalloc-64 内存(存储连接计数节点)将无法释放,导致内存占用维持高位。

static unsigned int
count_tree(struct net *net,

struct nf_conncount_data *data,
const u32 *key,
const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_zone *zone)

{
 struct rb_root *root;
 struct rb_node *parent;
 struct nf_conncount_rb *rbconn;
 unsigned int hash;
 printk("**[%s:%d]** \n", __func__, __LINE__);
 hash = jhash2(key, data->keylen, conncount_rnd) % CONNCOUNT_SLOTS;
 root = &data->root[hash];
 parent = rcu_dereference_raw(root->rb_node);
 while (parent) {
  int diff;
  rbconn = rb_entry(parent, struct nf_conncount_rb, node);
  diff = key_diff(key, rbconn->key, data->keylen);
  if (diff < 0) {
   parent = rcu_dereference_raw(parent->rb_left);
  } else if (diff > 0) {
   parent = rcu_dereference_raw(parent->rb_right);
  } else {
   int ret;
   printk("**[%s:%d]** \n", __func__, __LINE__);
   if (!tuple) {
    printk("**[%s:%d]** \n", __func__, __LINE__);
    nf_conncount_gc_list(net, &rbconn->list);
    return rbconn->list.count;
   }
   spin_lock_bh(&rbconn->list.list_lock);
   /* Node might be about to be free'd.
   * We need to defer to insert_tree() in this case.
   */

   if (rbconn->list.count == 0) {
    spin_unlock_bh(&rbconn->list.list_lock);
    break;
   }
   /* same source network -> be counted! */
   ret = __nf_conncount_add(net, &rbconn->list, tuple,
   zone);
   spin_unlock_bh(&rbconn->list.list_lock);
   if (ret)
    return 0/* hotdrop */
   else
    return rbconn->list.count;
   }
 }
 printk("**[%s:%d]** \n", __func__, __LINE__);
 if (!tuple)
  return 0;
 printk("**[%s:%d]** \n", __func__, __LINE__);
 return insert_tree(net, data, root, hash, key, tuple, zone);
}

count_tree 为何没进入上述释放节点的逻辑:


    1. 因调用时始终传入有效的 tuple 参数,跳过了直接调用 nf_conncount_gc_list 的路径。

    1. 进入__nf_conncount_add逻辑后,直接返回,不再进入 insert_tree 函数调用,后续的释放节点都走不到。

end



一口Linux 


关注,回复【1024】海量Linux资料赠送


精彩文章合集

文章推荐

【专辑】ARM
【专辑】粉丝问答
【专辑】所有原创
专辑linux入门
专辑计算机网络
专辑Linux驱动
【干货】嵌入式驱动工程师学习路线
【干货】Linux嵌入式所有知识点-思维导图

一口Linux 写点代码,写点人生!
评论
  •   几个月前,一个老旧的大风扇的散风圈(俺不知其专业名称)的开关按钮不起作用,就是锁不住了,散风圈也就不转了。今天,有空,就拿到工作台,开始拆解分析故障原因,能修好更好。  看看,用的时间够长了吧!皮肤都变颜色了。看标签,合格品2005年的。  底部四个螺丝固定,很容易拆开了。  看到掉下一个标签圆纸片,拿起来看看,是那个横向摇头的电机的。  找到那个按钮开关位置  应该是开关内部的有缺陷了。把它拆下来,一看就是正规合格品。  拿出我日积月累的分类藏宝盒,呵呵,找到一款螺丝孔位正好合适的。   
    自做自受 2025-07-10 11:16 290浏览
  • 提要:采用LOXIM的微孔雾化专用芯片LX8201,能突破压电陶瓷驱动电压超标(24伏)的技术难题,满足全球市场对喷雾玩具的电压安规认证要求。玩具行业尤其是喷雾玩具行业内人士都知道,喷雾玩具的压电陶瓷驱动电压超标(常需60-100V)与强制安规标准(中国,日本,欧美,都一样)对玩具电压的限制(≤24V)存在根本性冲突,如果采用“多层压电堆叠(MPA)技术“(比如日本TDK公司),成本将增加至现有微孔雾化片的10倍以上,这个矛盾一直没有得到好的解决。喷雾玩具在国内热销(淘宝/抖音),能卖的原因,无
    Loximonline 2025-07-08 10:55 256浏览
  • 在全球广泛倡导绿色低碳与可持续发展的时代浪潮中,新能源汽车作为实现节能减排的重要载体之一,正受到各国政府与企业的加速培育。在此背景下,为提升新能源汽车的市场渗透率,我国已率先进入充电基础设施建设的加速期,从私人专用充电桩到社区公用充电桩,从高速路网补能节点到城市公用充电桩,汽车补能网络正在急速膨胀中。图源:摄图网(已授权)据中国充电联盟(EVCIPA)最新统计数据显示,截止2025年5月份,我国充电基础设施累计数量为1440万台,同比上升45.1%。其中,在2025年1月~5月期间,我国充电基础
    华普微HOPERF 2025-07-09 16:13 257浏览
  • 据知名市场研究机构Counterpoint Research发布的数据概览,2025年第二季度,中国智能手机销量预计将迎来小幅回暖,增长率约为1%。在这场销量微增的背后,华为与苹果两大品牌成为了推动市场前行的核心力量。其中华为手机的表现最为亮眼,数据显示,华为在中国市场的智能手机销量份额实现了12%的同比增长,这一成绩不仅使其成为了当季增长最快的品牌,更助力华为重新夺回销量榜首的位置。相比之下,vivo的表现就有些尴尬了。虽然还是位列第二,但vivo在第二季度的智能手机销量份额同比下降了9%,下
    用户1742991715177 2025-07-09 08:19 207浏览
  • 在数字化、自动化高速发展的今天,光电耦合器正以一种低调却不可或缺的方式,悄然改变着我们的生活。它不仅是电子电路中的“安全卫士”,更是连接信号世界的“桥梁”,凭借出色的电气隔离能力,为各类设备提供稳定可靠的信号传输保障。电气隔离——让系统更安全在工业控制系统中,安全始终是重中之重。光电耦合器通过光信号进行电气隔离,能够有效防止高压电流侵入低压控制电路。例如,在智能电网系统中,它广泛应用于电表与通信模块之间,确保数据传输的安全性,防止电网高压对低压设备造成冲击。在电动汽车的电池管理系统(BMS)中,
    腾恩科技-彭工 2025-07-05 13:56 444浏览
  •   去年底,整理旧物,扔的扔了,留的留了,这不,十四个几十年前留下来的工业级小型排风扇,下图左上角处,又拿出来,下决心把它们再利用发挥余热。  呵呵,这回不是拆而是装了。怎么装呢?组装、固定、机架、接线,简单,也不简单,原则是一切都用手头现有废旧材料,争取做到一个不买!DIY,废物利用,如今时髦的话,以旧换新!摆上台面,找来木条,策划怎么做?  比一比,看一看,觉得合适,按尺寸锯开木条。  咋走线?想到了,在有限空间内弯转,从一个螺丝孔穿出来,整体拼凑整齐。   咋固定风扇呢?找来木片条,锯断,
    自做自受 2025-07-06 21:37 514浏览
  • 本文主要针对分立方案高速输出电路,由于MOS管、稳压管、PCB布局布线都存在一些寄生电容,这些寄生电容都会影响高速输出电路的占空比,所以本文对这些寄生电容的影响进行简单说明。测试工况:电压:24V,负载类型:阻性负载2K,输出频率:200Khz,要求占空比45%~55%;电路拓扑如下图所示:图1寄生电容分布情况:如下图所示,MOS管寄生电容为Cgd、Cgs、Cds,稳压管寄生电容为Cd;图2而MOS管手册常见的参数如下图所示为Ciss、Coss、Crss(为啥是这些参数,而不改成Cgs、Cgd、
    用户1751282873645 2025-07-08 23:58 181浏览
  • 曾经靠“砍一刀”撕裂传统电商格局的拼多多,如今疲态尽显。数据显示,拼多多今年第一季度实现营收957亿元,同比增长10%,市场预估1016亿元,相比预期低了近60亿元;经营利润为161亿元,相比去年同期下降38%;归属于普通股股东的净利润为147亿元,同比下降47%。与此同时,拼多多市值也坐上了“过山车”。去年市值一度突破 2180 亿美元,力压国内电商巨头阿里,今年(7月1日收盘)市值仅余 1497.59 亿美元,已不足阿里(市值2718.63亿美元)一半
    用户1742991715177 2025-07-05 14:24 410浏览
  • 什么是LoRaWAN? LoRaWAN技术及应用LoRaWAN(Long Range Wide Area Network)是一种低功耗、长距离、广域网络通信协议,特别设计用于连接物联网(IoT)设备。LoRaWAN采用无线通信技术,能够覆盖数十公里的范围,提供长时间的电池寿命,适用于智能城市、农业、工业自动化、环境监测,与健康医疗等领域应用。来源: LoRa Alliance一探究竟:LoRaWAN物联网应用优势营运商采用 LoRaWAN 具有多方面的优势,除了长距离覆盖范围及低功耗的特点外,还
    百佳泰测试实验室 2025-07-10 14:51 263浏览
  • 在物联网无线通信领域,随着行业应用场景的不断拓宽,同一频段下的设备通信需求正呈指数级增长,然而这一增长趋势却与频谱资源的有限性形成了鲜明对立,信道拥挤、信号串扰与非线性失真等不良现象所造成的“通信压力”正在持续放大。从智能家居的设备互联到工业物联网的实时控制,从智慧楼宇的广域组网到智慧城市的海量数据传输,有限的频谱资源不仅需要满足不断增长的设备通信需求,还需要适配不同场景对速率、时延与可靠性等差异化要求。在此背景下,如何在有限的频谱资源中实现更为稳定的无线通信质量,已成为物联网行业发展路径中的核
    华普微HOPERF 2025-07-07 16:13 544浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦