Skip to content

feat: gotls Upload sequence; Fix the issue where disorderly arrival c…#978

Merged
cfc4n merged 3 commits into
gojue:masterfrom
skylar2826:feature/order2
Apr 26, 2026
Merged

feat: gotls Upload sequence; Fix the issue where disorderly arrival c…#978
cfc4n merged 3 commits into
gojue:masterfrom
skylar2826:feature/order2

Conversation

@skylar2826
Copy link
Copy Markdown
Contributor

@skylar2826 skylar2826 commented Apr 7, 2026

为了解决 多 CPU perf 读取乱序 导致的 HTTP/2 字节流拼接错误。
image-20260416111550319
乱序的根本原因在于观测路径而非业务数据流:BPF 程序在每次 read() 完成时,通过 bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, ...) 将明文副本写入当前 CPU 对应的 Perf ring buffer。所谓"不同 CPU",指的是多次 hook 触发时,BPF 程序可能在不同 CPU 核心上执行,导致样本被写入各自 CPU 对应的 Perf ring buffer 中,形成多生产者(多 CPU 各自 ring)单消费者(用户态合并读取)模型;合并时无法保证全局顺序等于探针触发顺序,在 HTTP/2 二进制帧与多路复用场景下(如文件上传)表现尤为明显。

文档:
[ecapture] eBPF hook gotls 收包乱序根因分析
[eCapture] GoTLS Perf 事件有序下发
[ecapture] gotls:三种模式实现说明与上层应用职责


Open with Devin

reorder可通过配置开启,lag=10ms 测试对比:

指标 old(无 reorder) new(有 reorder)
dispatch 条数 2774 2833
相邻逆序 10(0.36%) 6(0.21%)
全局逆序对占比 3.43% 2.44%
image-20260414175528657

单元测试已通过:
image-20260413152406739

@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. fix bug fix PR labels Apr 7, 2026
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

@cfc4n
Copy link
Copy Markdown
Member

cfc4n commented Apr 7, 2026

目前这PR中,只看到内核代码增加了seq标识,但没有看到用户空间代码的排序使用。

另外,我原来的想法是,通过捕获的pcapng包+ keylog模式,做实时的网络包解密,这样,就可以规避这个问题了。 而且,目前的问题很依赖PID信息,用PID关联五元组。 很多时候无法还原准确的五元组信息。

@skylar2826
Copy link
Copy Markdown
Contributor Author

skylar2826 commented Apr 13, 2026

  1. PR已更新

  2. “目前的问题很依赖PID信息,用PID关联五元组。 很多时候无法还原准确的五元组信息”
    我理解这是openssl等的实现逻辑“先去查 PID 再在内核里反查 socket表拼五元组”;目前gotls的实现是靠”go内存布局 + 符号/偏移“直接获取的五元组信息

  3. “通过捕获的pcapng包+ keylog模式,做实时的网络包解密”
    keylog模式我理解gotls程序(如caddy)必须调用KeyLogWriter才能被hook到,而caddy默认没有开启该配置

devin-ai-integration[bot]

This comment was marked as resolved.

…auses the file content to be uninterpretable
@skylar2826
Copy link
Copy Markdown
Contributor Author

PR已更新

@cfc4n
Copy link
Copy Markdown
Member

cfc4n commented Apr 14, 2026

对于golang来说,keylog的捕获,可以HOOK writeKeyLog函数,从参数中获取。 即使KeyLogWriter没有设置,也不影响。

https://github.com/golang/go/blob/33241d7298e0c621cfc4cc9f878dba9eff2b1c3d/src/crypto/tls/common.go#L1591-L1603

func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error {
	if c.KeyLogWriter == nil {
		return nil
	}

	logLine := fmt.Appendf(nil, "%s %x %x\n", label, clientRandom, secret)

	writerMutex.Lock()
	_, err := c.KeyLogWriter.Write(logLine)
	writerMutex.Unlock()

	return err
}

@skylar2826
Copy link
Copy Markdown
Contributor Author

  1. 更新了顶部的总览内容,补充了乱序的根因
  2. 我理解现在更新的gotls text明文代码不会影响到pcapng模式、keylog模式的处理,彼此独立
image-20260416152756215 3. 对比了 pcapng 模式和 keylog 模式后,认为这两种方案需要“读取 keylog + 按 TCP/TLS 解密”才能得到明文,二次开发成本较高。因此,gotls 的明文模式更适合我的场景,可以直接使用 ecapture 工具,无需额外开发

@skylar2826
Copy link
Copy Markdown
Contributor Author

额外:handler推荐内置Write(GetData())输出原始二进制数据,方便组包

@skylar2826
Copy link
Copy Markdown
Contributor Author

skylar2826 commented Apr 16, 2026

在commit1中使用了更高准确度的方案;但平衡收益后,在commit2中仅保留了monoNs字段,移除cpu、seq排序

image

自测已通过:
image-20260416184555277

@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Apr 16, 2026
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels Apr 16, 2026
@cfc4n
Copy link
Copy Markdown
Member

cfc4n commented Apr 21, 2026

请查收一下邮件,😃

Copy link
Copy Markdown
Member

@cfc4n cfc4n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

改动量有点大,周末我详细看下。

楼主思维活跃,逻辑清晰,Linux内核、go底层经验丰富,强。

Comment thread internal/probe/base/base_probe.go
@skylar2826
Copy link
Copy Markdown
Contributor Author

以下问题虽与本PR无直接关联,但在 review 过程中被提及,比较关心:

“通过捕获的pcapng包+ keylog模式,做实时的网络包解密”:
性能问题会不会导致丢包严重,期望能提供几种模式下压力测试的相关数据

“目前的问题很依赖PID信息,用PID关联五元组。 很多时候无法还原准确的五元组信息”:
在使用openssl时,我们也遇到无法关联上的表现,能展开讲讲或者有资料可以看到具体是什么原因导致无法准确关联并获取五元组信息吗

@cfc4n
Copy link
Copy Markdown
Member

cfc4n commented Apr 24, 2026

性能问题: #829 未解决,你提到的 ringbuf 应该会有很大改善。不过,依旧面临低版本内核的兼容问题。
PID无法获取或五元组关联不了的问题,我让GitHub Copilot 在 项目中搜了一下:

以下是 gojue/ecapture 项目 OpenSSL 模块中关于五元组无法关联PID 获取不了的相关 Issues 汇总,按问题类型分类整理:


一、五元组为 0.0.0.0:0 / [::]:0 的问题

#981(Closed)— --pid 过滤时输出 PID 为 0 的日志

  • 现象:使用 ecapture tls --pid 3284221 时,输出中频繁出现 PID:0, Comm:, TID:0, FD:0, Tuple: [::]:0->[::]:0,且捕获到了非指定 PID 的进程数据。
  • 原因分析--pid 过滤在 text 模式下存在竞态或过滤逻辑缺陷,connect 事件与 SSL 数据事件的 PID 关联不准确。
  • 状态:已关闭(wontfix + improve 标签)

#908(Open)— IP 信息全为 0.0.0.0

  • 现象:在内核 4.19.90(Kylin V10)+ Apache httpd 场景下,Src:0.0.0.0:0, Dest:0.0.0.0:0,数据能抓到但 IP 全为空。
  • 原因:内核 < 5.2 时,GlobalVar(全局变量)被禁用,kretprobe_connect 等钩子依赖的内核版本特性不可用,五元组无法从连接跟踪表中获取。
  • 状态:Open(仍未解决)

#739(Closed)— HTTP/2 包的 tuple 有时为 0.0.0.0:0-0.0.0.0:0

  • 现象:同一会话中,部分包出现 tuple=[TUPLE_NOT_FOUND],最终 UUID 中显示 0.0.0.0:0-0.0.0.0:0
  • 根本原因DestroyConn(连接销毁事件)在 eBPF perf buffer 中先于后续 SSL 数据事件被用户态消费,导致查 connMap 时连接已被删除 → TUPLE_NOT_FOUND
  • 状态:已关闭(已修复)

#774(Closed)— Android 14 se.Tuple 未实现,所有包均为 0.0.0.0:0

  • 现象:Android 14 BoringSSL 场景下,UUID 中 Tuple 部分恒为 0.0.0.0:0-0.0.0.0:0,无法将 Request 和 Response 关联到真实连接。
  • 原因:Android BoringSSL 的 se.Tuple 部分在当时版本中尚未实现(代码注释明确标注)。
  • 状态:已关闭

二、FD 获取为 0 导致五元组无法关联

#933(Closed)— process_SSL_bio 函数获取 fd 为 0

  • 现象:eBPF trace 日志显示 process_SSL_bio: fd=0, ssl_st_fd no entry for ssl=0x...bio_num=0x0,最终五元组无法关联。
  • 原因:curl 通过 SSL_set0_rbio 设置自定义 BIO 时,BIO num 字段中没有写入 socket fd,导致 ecapture 读取到 fd=0。
  • 状态:已关闭

#822(Closed)— curl 8.12 调用 OpenSSL 3.4.1 时无法抓到 fd

  • 现象:Ubuntu 25.04 的 curl 8.12 + OpenSSL 3.4.1,fd 值始终为 0,无法建立五元组。
  • 原因:curl 8.12 使用了 BIO_meth_set_read / BIO_meth_set_write 自定义 BIO 方法,且调用 SSL_set0_rbio不将 socket fd 写入 bio->num,ecapture 原有的 bio->num 读取路径完全失效。
  • 状态:已关闭(wontfix,需新方案)

三、IPv6 五元组获取缺失

#724(Closed)— -m text 模式无法获取 IPv6 五元组

  • 现象:IPv6 连接的五元组信息无法出现在 UUID 中,IPv6 包被静默丢弃。
  • 原因:eBPF 内核代码 kretprobe_connect 中硬编码了 if (address_family != AF_INET) return 0;仅处理 IPv4,IPv6(AF_INET6)直接跳过不处理。
  • 状态:已关闭(标记 todo,已有后续 PR 跟进)

四、五元组功能缺失 / 需求演进

#4(Closed,2022)— 需要将 SSL 明文信息关联到 IP 五元组

#682(Closed)— text 模式下五元组信息不完整(仅含服务端 IP)

  • 现象:v0.8.9 的 UUID 中仅显示服务端 IP(如 39.156.66.10:443),缺少客户端 IP/端口,本地服务端连接显示 0.0.0.0
  • 原因:五元组功能当时尚不完善,仅 connect 方向有四元组,accept 方向缺失。
  • 状态:已关闭(后续版本修复)

#871(Closed)— keylog 模式下能否同时获取五元组

  • 问题-m keylog 仅输出 CLIENT_RANDOM,无法同时获取连接的五元组信息,难以关联到具体流量。
  • 状态:已关闭

总结

问题类型 代表 Issue 根本原因
连接销毁竞态 → tuple 为 0 #739 DestroyConn 事件先于数据事件被消费,connMap 已清除
内核 <5.2 不支持 GlobalVar #908 内核版本过低,kretprobe/GlobalVar 不可用
BIO 自定义导致 fd=0 #822, #933 应用自定义 BIO,bio->num 中不写入 socket fd
IPv6 不支持 #724 eBPF hook 只处理 AF_INET,跳过 AF_INET6
Android BoringSSL Tuple 未实现 #774 Android BoringSSL 路径的 Tuple 字段当时未实现
--pid 过滤不准确 #981 connect 事件与 SSL 数据事件 PID 关联竞态

Comment thread internal/probe/gotls/gotls_perf_reader.go
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Apr 26, 2026
@cfc4n cfc4n merged commit fe109ef into gojue:master Apr 26, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix bug fix PR lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants