You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Linux内核Netfilter的TCP连接数限制代码优化咨询

Netfilter TCP连接数限制代码的问题与优化建议

我正在学习Linux内核中的Netfilter,想要实现TCP连接数限制功能,要求最大开放TCP连接数不超过50。我已根据理解编写了如下代码,想请教该代码是否存在问题或可优化之处?

#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/tcp.h>
#include <net/tcp.h>

#define MAX_TCP_CONNECTIONS 50
static unsigned int conn_count = 0;

static unsigned int nf_hook_func(void *priv, struct sk_buff *skb, 
                 const struct nf_hook_state *state)
{
    if (state->pf == PF_INET && skb->protocol == htons(ETH_P_IP)) {
        struct iphdr *iph = ip_hdr(skb);
        if (iph->protocol == IPPROTO_TCP) {
            struct tcphdr *tcph = tcp_hdr(skb);
            
            if (tcph->syn) {
                if (conn_count >= MAX_TCP_CONNECTIONS) {
                    printk(KERN_INFO "Dropping SYN packet. Maximum TCP connections reached.");
                    return NF_DROP;
                }
                conn_count++;
            }
            
            if (tcph->fin) {
                conn_count--;
            }
            
            printk(KERN_INFO "conn_count: %u", conn_count);
        }
    }
    
    return NF_ACCEPT;
}

static struct nf_hook_ops hook_ops = {
    .hook     = nf_hook_func,
    .pf       = PF_INET,
    .hooknum  = NF_INET_PRE_ROUTING,
    .priority = NF_IP_PRI_FIRST,
};

static int __init nf_conn_init(void) 
{
    int ret = nf_register_net_hook(&init_net, &hook_ops);
    if (ret < 0) {
        printk(KERN_ERR "Failed to register netfilter hook\n");
        return ret;
    }
    
    printk(KERN_INFO "Registered IPv4 pre-routing hook\n");
    return 0;
}

static void __exit nf_conn_exit(void) 
{
    nf_unregister_net_hook(&init_net, &hook_ops);
    printk(KERN_INFO "Unregistered IPv4 pre-routing hook\n");
}

module_init(nf_conn_init);
module_exit(nf_conn_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Netfilter TCP connection limit");

代码存在的问题

  1. 并发竞态问题:全局变量conn_count未做并发保护,内核是多CPU并行执行环境,多个CPU同时修改该变量会导致计数错误,甚至出现数据不一致。
  2. 计数逻辑不准确:
    • 仅处理SYN和FIN包,未处理RST包。TCP连接收到RST时会直接断开,若不处理会导致计数无法减少,出现计数泄漏。
    • 重复的SYN包(如客户端重传)会被重复计数,导致实际连接数未达上限但计数已超。
    • 未跟踪TCP连接的完整生命周期:仅看到SYN就增加计数,但如果客户端发完SYN后未完成三次握手,后续没有FIN/RST包,计数会一直保留,最终导致计数失真。
  3. 钩子点局限性:选择NF_INET_PRE_ROUTING仅能处理入站连接,本地发起的出站TCP连接不会经过该钩子点,无法实现全局连接数限制。
  4. 日志输出过于频繁:每个TCP包都会打印conn_count,会大量占用内核日志资源,同时影响系统性能。
  5. skb有效性未检查:直接访问ip_hdr(skb)和tcp_hdr(skb)前未检查skb是否有效、头部数据是否完整,若遇到不合法的skb会触发内核崩溃。
  6. Net Namespace不兼容:仅注册到init_net,在多Net Namespace环境下,其他命名空间的连接不会被统计和限制。

优化建议

  1. 并发安全处理:将conn_count替换为原子变量atomic_t,使用atomic_inc()、atomic_dec()、atomic_read()等原子操作保护计数,避免竞态。
  2. 完善计数逻辑:
    • 新增RST包处理逻辑,收到RST时减少计数。
    • 改用TCP连接跟踪(conntrack)机制获取真实活跃连接数,或者维护四元组(源IP/端口、目的IP/端口)哈希表,跟踪每个连接的状态,避免重复计数和泄漏。
    • 为未完成握手的SYN包设置超时,超时后自动减少计数,避免无效计数残留。
  3. 调整钩子点:若需限制全局TCP连接,可同时注册NF_INET_LOCAL_IN(入站)和NF_INET_LOCAL_OUT(出站)钩子点,覆盖所有TCP流量。
  4. 优化日志输出:仅在关键事件(如达到连接上限、计数异常变化)时打印日志,或使用pr_debug()替代printk(),默认不输出,通过动态调试开关启用。
  5. 添加skb有效性检查:在访问IP/TCP头部前,使用skb_is_good()、skb_ip_may_pull()等函数确保skb数据完整、可访问。
  6. 支持Net Namespace:使用nf_register_hook()或基于per-net数据结构实现,让模块在所有Net Namespace中生效。

内容的提问来源于stack exchange,提问作者goodman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 17:13:18