Skip to content

Instantly share code, notes, and snippets.

@ptpt52
Created June 4, 2025 01:04
Show Gist options
  • Save ptpt52/4f33b708d3d93f7c41c2c2326f92a824 to your computer and use it in GitHub Desktop.
Save ptpt52/4f33b708d3d93f7c41c2c2326f92a824 to your computer and use it in GitHub Desktop.

LVS 域名白名单内核模块设计文档

1. 背景与目标

LVS 作为高性能的四层负载均衡器,原生仅基于 IP/端口转发,不解析应用层流量,无法实现基于域名的访问控制。实际生产中有基于域名的白名单需求,需拦截非白名单域名的 HTTP/HTTPS 流量,并可在拦截时阻断连接。

本模块设计目标:

  • 支持域名白名单过滤(HTTP Host、TLS SNI)
  • 支持拦截非法域名连接并阻断后续包
  • 可选使用内核连接跟踪(conntrack)或自定义轻量状态表实现高性能
  • 以内核 Netfilter 模块形式实现,适配 LVS 前端部署

2. 需求分析

  • 协议支持:需解析 HTTP/1.x Host 字段、TLS ClientHello SNI 字段
  • 拦截策略:非白名单域名连接需拦截,并确保后续相关包均丢弃或发 RST
  • 性能要求:应尽量减少对转发性能的影响
  • 灵活性:可选择是否启用 conntrack

3. 总体设计

3.1 流程总览

  1. PREROUTING 钩子捕获新连接首包
  2. 解析首包 L7 域名信息(HTTP Host/SNI)
  3. 域名匹配白名单
    • 匹配:放行
    • 不匹配:标记连接为拦截,发 RST 或丢弃
  4. 后续包处理
    • 依赖连接状态(conntrack 或自定义 mini-state)判断是否丢弃

3.2 关键模块

  • 域名提取模块(HTTP/SNI 解析)
  • 域名白名单匹配模块
  • 状态跟踪模块(可选用 conntrack 或自实现)
  • 拦截与阻断处理模块(发 RST、丢弃包)

4. 详细设计

4.1 域名解析

  • HTTP
    • 识别 TCP SYN-ACK 完成后的首个数据包,解析 HTTP 请求头,提取 Host 字段
  • HTTPS
    • 识别 TLS ClientHello 报文,提取 SNI 字段
    • 需处理 TLS 握手分片情况,必要时缓存首包片段重组

4.2 白名单匹配

  • 内核态维护允许域名列表(支持 hash 表或 trie 提高匹配效率)
  • 动态加载/更新白名单(可通过 netlink、procfs、sysfs 等接口)

4.3 状态跟踪方案

4.3.1 基于 conntrack(方案一)

  • 依赖内核 Netfilter conntrack 子系统
  • 使用 conntrack 标记连接状态(如使用 CT MARK 或自定义状态 bit)
  • 拦截后通过 conntrack 查找后续包并丢弃

优点:实现简单,利用现成连接跟踪
缺点:conntrack 占用资源较多,影响极高并发场景性能

4.3.2 自定义轻量连接状态表(方案二)

  • 自建五元组 hash 表,仅记录需拦截的连接
  • 只针对被拦截连接维护状态,连接量极少时性能影响可忽略
  • 状态表定期清理(超时、主动关闭)
  • 后续包到达查表丢弃或发 RST

优点:性能高,占用内存和CPU极小
缺点:实现略复杂,需自己维护状态一致性

4.4 拦截与阻断

  • 对被拦截的 TCP 连接,可发 TCP RST 包断开
  • UDP 可直接丢弃数据包
  • 支持拦截日志(可选)

5. 内核模块接口设计

  • /proc/lvs_domain_whitelist/sys/kernel/lvs_domain_whitelist/
    • 支持白名单域名增删查
    • 支持运行状态与统计信息查询
  • netlink 通信接口(可选,便于用户态管理)
  • 内核参数支持启用/禁用 conntrack 模式

6. 伪代码流程

// PREROUTING 钩子
on_packet(packet):
    if not new_tcp_stream(packet):
        if is_intercepted(packet):
            drop_or_rst(packet)
        else:
            accept(packet)
        return

    domain = parse_domain_from_packet(packet)
    if domain in whitelist:
        accept(packet)
    else:
        mark_intercepted(packet)
        drop_or_rst(packet)
  • is_intercepted(packet)
    • 方案一:查 conntrack 标记
    • 方案二:查自定义 hash 状态表

7. 部署与运维建议

  • 建议在 LVS 前端部署,配合大流量环境评估性能消耗
  • 白名单维护需谨慎,避免误封
  • 定期监控模块状态表内存与命中率

8. 可选优化点

  • 支持域名通配符、正则匹配
  • 支持高性能多核并发访问状态表
  • 支持用户态远程批量管理接口

9. 小结

本内核模块设计兼顾高性能与灵活性,既可利用 conntrack 简化开发,也可通过自定义迷你状态表实现极致性能,适合 LVS 场景下的基于域名白名单的流量管控需求。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment