Post

Suricata flow update rate(ai)

Suricata flow update rate(ai)

Suricata 大象流 (Elephant Flow) 机制与配置说明

1. 概述

FlowUpdateFlowRate 是 Suricata 核心代码中用于监控流带宽使用情况的关键函数。它的主要职责是实时统计流的传输速率,并检测该流是否符合“大象流”的定义。

一旦一个流被判定为大象流(Elephant Flow),Suricata 会对其进行标记,以便进行性能优化(如停止后续的速率计算)或供管理员进行进一步的策略控制(如 Bypass)。

2. 核心函数:FlowUpdateFlowRate

该函数定义在 src/flow.c 中,主要逻辑如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static inline void FlowUpdateFlowRate(
        ThreadVars *tv, DecodeThreadVars *dtv, Flow *f, const Packet *p, int dir)
{
    // 1. 检查功能是否开启
    if (FlowRateStorageEnabled()) {
        
        // 2. 性能优化:如果已经是大象流,直接返回,不再浪费 CPU 计算速率
        if (f->flags & FLOW_IS_ELEPHANT)
            return;

        // 3. 获取流的存储区域
        FlowRateStore *frs = FlowGetStorageById(f, FlowRateGetStorageID());
        if (frs != NULL) {
            // 4. 更新当前时间窗口内的字节数
            FlowRateStoreUpdate(frs, p->ts, GET_PKT_LEN(p), dir);
            
            // 5. 检查是否超过阈值
            bool fr_exceeds = FlowRateIsExceeding(frs, dir);
            if (fr_exceeds) {
                // 6. 标记为大象流
                f->flags |= FLOW_IS_ELEPHANT;
                if (tv != NULL) {
                    StatsIncr(tv, dtv->counter_flow_elephant); // 更新统计计数器
                }
            }
        }
    }
}

3. 大象流的影响

大象流通常指在短时间内传输大量数据(高带宽、长连接)的流,如文件下载、数据备份等。

3.1 对性能的影响

  • 正面(自我优化)
    • 一旦标记为 FLOW_IS_ELEPHANT,Suricata 就会停止对该流的速率跟踪计算。这减少了对高频数据包的内存写入和计算开销。
  • 负面(潜在瓶颈)
    • 单核过载:Suricata 的架构通常将同一个流绑定到同一个 CPU 线程。一个 10Gbps 的大象流可能会导致处理该流的单个 CPU 核心占用率达到 100%,从而导致丢包,即使其他核心很空闲。
    • 检测效率低:大流量通常是加密数据或多媒体/二进制数据,对其进行全量深度包检测(DPI)不仅消耗巨大资源,而且往往没有安全价值。

3.2 应对策略

Suricata 识别大象流的主要目的就是为了减负。虽然它不会自动丢弃或忽略这些流,但它提供了标记,允许管理员:

  • Bypass(绕过):通过规则或配置,让这些被标记的大流量绕过后续的应用层检测,直接放行,从而大幅降低 CPU 负载。

4. 存储机制与配置

4.1 运行时内存存储

Suricata 使用 Flow Storage API 将速率统计信息动态挂载到内存中的 Flow 结构体上。

  • 数据结构FlowRateStore (定义于 src/util-flow-rate.h)
  • 存储内容:包含两个方向(To Server / To Client)的环形缓冲区(Ring Buffer),用于记录最近 interval 秒内的流量字节数。
  • 生命周期:随流的创建而分配,随流的销毁而释放。

4.2 配置文件存储 (suricata.yaml)

配置决定了什么样的流会被判定为大象流。默认情况下该功能通常是关闭的,需要在配置文件中显式开启。

配置路径: flow.rate-tracking

1
2
3
4
5
6
7
8
9
flow:
  memcap: 128mb
  hash-size: 65536
  prealloc: 10000
  
  # 大象流配置段
  rate-tracking:
    bytes: 1GiB    # 阈值:在区间内传输字节数超过此值即判定为大象流
    interval: 10   # 区间:时间窗口(秒)

在这个例子中,如果一个流在 10 秒内传输了超过 1GB 的数据,它就会被标记为大象流。

5. 可观测性与日志

当流被标记为大象流后,可以通过以下方式确认:

  1. EVE JSON 日志 (eve.json): 在流结束(flow event)的日志中,会包含 elephant 字段。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    {
      "event_type": "flow",
      "flow": {
        "pkts_toserver": 100000,
        "pkts_toclient": 50000,
        "bytes_toserver": 1200000000,
        "bytes_toclient": 6000000,
        "elephant": true  <-- 标识为大象流
      }
    }
    
  2. 统计日志 (stats.log): 全局计数器 flow.elephant 会记录系统启动以来检测到的大象流总数。
    1
    
    flow.elephant   | Total | 15
    
  3. 调试日志: 如果开启了 Debug 模式,src/flow.c 会打印如下日志: "Flow rate for flow %p exceeds the configured values, marking it as an elephant flow"

6. 查看流传输速率的方法

Suricata 的设计原则是高性能流处理,它在标准日志中不直接输出计算好的“速率”(如 Mbps)字段。

6.1 用户层面:通过 EVE 日志计算(最标准方式)

利用 eve.json 中的字段计算流的平均速率。

计算公式:

1
平均速率 (Mbps) = [(bytes_toserver + bytes_toclient) * 8] / (age * 1000000)

6.2 系统层面:实时监控工具(官方推荐)

如果需要实时查看瞬时速率,建议使用操作系统工具:

  • iftop: 类似 Linux top 命令,实时显示连接的带宽占用。
  • nload: 显示网卡的整体实时吞吐量。

7. FlowRateStore 机制深入探讨

7.1 FlowRateStore 是开发者专用的吗?

这个理解非常准确。在目前的 Suricata 官方代码库中,FlowRateStore 几乎完全是为了“大象流”标记功能而存在的。它是一个高度专用的模块,主要价值在于识别出消耗大量资源的流,以便进行性能优化。

它的设计特点决定了其用途的单一性:

  • “一次性”触发:一旦流被标记为 FLOW_IS_ELEPHANTFlowRateStore 就会停止对该流的更新。它是一个“超速检测器”,而不是一个持续的“速度计”。
  • 缺乏对外接口:规则关键字或 Lua API 无法直接访问 FlowRateStore 中的实时速率数据。

7.2 Filestore (文件提取) 与大象流/Bypass 的关系

这是一个非常重要的场景,因为文件提取和流量绕过(Bypass)在本质上是互斥的。

核心冲突点:

  • Filestore:需要捕获并重组完整的数据流才能成功提取文件。
  • Bypass:意味着 Suricata 引擎会放弃对流后续数据包的处理,将其直接转发。

场景分析:提取一个大文件

如果你有一条规则需要提取一个大文件(例如 5GB),这个传输过程本身很可能会因为速率过高而被标记为“大象流”。

  1. 标记:流因为速率快被标记为 FLOW_IS_ELEPHANT
  2. Bypass 触发:如果你的策略是自动 Bypass 所有大象流(例如通过 bypass 规则关键字),那么 Bypass 动作会被触发。
  3. 提取失败:一旦 Bypass 生效,Suricata 就再也看不到这个流的后续数据包了。因此,文件提取会提前中止,导致你只能得到一个被截断的不完整文件。

如何避免 Filestore 被 Bypass?

结论是:如果一个流需要进行文件提取,你必须确保它不会被 Bypass。

  • 策略优先级:Suricata 的内部逻辑通常会保证文件提取等有状态的操作优先于 Bypass。只要有活跃的文件提取事务,引擎就不会轻易地 Bypass 该流。
  • 精细化 Bypass 规则:避免使用“一刀切”的 Bypass 策略。例如,可以制定更具体的规则,如“仅对加密协议(如 TLS)的大象流启用 Bypass”,而对需要进行文件提取的应用协议(如 HTTP, SMB)则不启用。

总结: filestore 会阻止 bypass,但不会阻止流被标记为大象流。关键在于你的 Bypass 策略是否足够智能,能够识别出正在进行文件提取的流并将其排除在 Bypass 范围之外。

This post is licensed under CC BY 4.0 by the author.