开发指南
本文档为向 eCapture 项目贡献代码的开发者提供全面指导。内容涵盖构建系统、开发工作流、测试流程和发布过程。有关实现新捕获模块的信息,请参阅 添加新模块。有关 eBPF 程序开发的详细信息,请参阅 eBPF 程序开发。
开发环境设置
前置条件
eCapture 开发需要以下工具和库:
| 组件 | 最低版本 | 用途 |
|---|---|---|
| Go | 1.24 | 用户空间程序编译 |
| Clang | 9+ (推荐 14) | eBPF 程序编译 |
| LLVM | 9+ (推荐 14) | eBPF 字节码生成 |
| Linux Kernel | 4.18+ | eBPF 支持 |
| libelf-dev | - | ELF 文件解析 |
| Linux headers | - | 内核结构定义 |
环境初始化脚本
项目在 builder/init_env.sh:1-106 提供了自动化环境设置脚本。该脚本执行以下操作:
- 检测 Ubuntu 版本并选择适当的 Clang 版本 (builder/init_env.sh:16-39)
- 通过 apt-get 安装所需的软件包 (builder/init_env.sh:72-74)
- 配置交叉编译工具链 (builder/init_env.sh:43-61)
- 为 eBPF 编译准备 Linux 内核源码 (builder/init_env.sh:81-89)
- 下载并安装 Go (builder/init_env.sh:94-97)
架构检测: 脚本会自动检测主机架构并配置交叉编译:
- 在 x86_64 上:设置 aarch64 交叉编译 (builder/init_env.sh:48-52)
- 在 aarch64 上:设置 x86_64 交叉编译 (builder/init_env.sh:53-58)
手动执行:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/gojue/ecapture/master/builder/init_env.sh)"构建系统架构
Makefile 结构
构建系统由三个主要文件组成:
构建系统组件:
Makefile:主构建编排 (Makefile:1-245)variables.mk:环境检测和变量定义functions.mk:可重用的构建函数 (functions.mk:1-76)builder/Makefile.release:发布打包和分发 (builder/Makefile.release:1-151)
来源:Makefile:1-11、functions.mk:1-76、builder/Makefile.release:1-10
构建目标概览
| 目标 | 用途 | 包含的字节码 |
|---|---|---|
all | 完整构建(CO-RE 和 non-CO-RE) | 两者都包含 |
nocore | 仅构建 non-CO-RE | 仅 non-CO-RE |
ebpf | 编译 CO-RE eBPF 字节码 | CO-RE |
ebpf_noncore | 编译 non-CO-RE eBPF 字节码 | non-CO-RE |
assets | 生成 Go 嵌入式字节码 | 两者都包含 |
build | 编译 Go 二进制文件 | - |
clean | 删除构建产物 | - |
test-race | 运行带竞态检测器的单元测试 | - |
e2e | 运行端到端测试 | - |
来源:Makefile:4-14、Makefile:106-245
构建流程
完整构建流水线
来源:Makefile:6-11、Makefile:133-201
CO-RE 与 Non-CO-RE 编译
CO-RE(一次编译,到处运行):
clang -D__TARGET_ARCH_x86 \
-target bpfel \
-c kern/openssl.c \
-o user/bytecode/openssl_kern_core.o \
-g -fno-ident- 生成与内核无关的字节码 (Makefile:122-127)
- 需要支持 BTF(BPF 类型格式)的内核
- 使用
bpftool btf dump生成的vmlinux.h(Makefile:130-131) - 文件大小更小,可跨内核版本移植
Non-CO-RE(特定内核):
clang -I /usr/src/linux-source/arch/x86/include \
-c kern/openssl.c -o - | \
llc -march=bpf -filetype=obj \
-o user/bytecode/openssl_kern_noncore.o- 需要目标内核的内核头文件 (Makefile:144-159)
- 可在不支持 BTF 的旧内核上工作
- 针对特定内核,不同内核版本需要重新构建
- 由于包含内核结构定义,文件大小更大
构建变量:
KERN_SRC_PATH:内核源码路径 (Makefile:147-154)KERN_BUILD_PATH:内核构建路径 (Makefile:148-152)LINUX_ARCH:目标架构(x86、arm64)(Makefile:122)
资源嵌入流程
构建系统使用 go-bindata 将所有 eBPF 字节码文件嵌入到 Go 二进制文件中:
- 编译 eBPF 程序:在
user/bytecode/中生成*.o文件 - 生成 Go 代码:
go-bindata读取所有.o文件 (Makefile:164) - 创建资源包:生成
assets/ebpf_probe.go(Makefile:164) - 嵌入到二进制文件:Go 构建包含嵌入的资源
这种方法消除了在二进制文件旁分发单独字节码文件的需要。
构建 eCapture
标准构建(本地架构)
完整构建,包含 CO-RE 和 non-CO-RE:
make clean
make env # 显示构建环境
make all # 构建所有内容仅 non-CO-RE(用于旧内核):
make clean
make nocorenocore 目标适用于以下情况:
- 目标系统缺少 BTF 支持
- 部署到特定内核版本
- 通过排除 CO-RE 字节码来减少二进制大小
交叉编译
在 x86_64 上为 ARM64 构建:
make clean
CROSS_ARCH=arm64 make env
CROSS_ARCH=arm64 make all在 ARM64 上为 x86_64 构建:
make clean
CROSS_ARCH=amd64 make env
CROSS_ARCH=amd64 make all交叉编译要求:
- 已安装交叉编译工具链 (.github/workflows/go-c-cpp.yml:19)
- 对于 ARM64:
gcc-aarch64-linux-gnu - 对于 x86_64:
gcc-x86-64-linux-gnu
- 对于 ARM64:
- 已准备目标架构的内核头文件 (.github/workflows/go-c-cpp.yml:31)
libpcap 交叉编译: 构建系统自动为交叉编译配置 libpcap:
CC=aarch64-linux-gnu-gcc AR=aarch64-linux-gnu-ar \
./configure --host=aarch64-linux-gnu来源:Makefile:56-65、Makefile:176-184、.github/workflows/go-c-cpp.yml:56-65
Android 构建
为 Android 构建(ARM64):
make clean
CROSS_ARCH=arm64 make env
ANDROID=1 CROSS_ARCH=arm64 make nocoreAndroid 特定注意事项:
- Android 构建仅使用 non-CO-RE (.github/workflows/go-c-cpp.yml:61-65)
- 特殊处理 BoringSSL 版本(Android 12-16)
- ARM 架构的网络字节序调整
来源:Makefile:95、.github/workflows/go-c-cpp.yml:61-65
构建环境变量
| 变量 | 说明 | 示例 |
|---|---|---|
CROSS_ARCH | 目标架构 | arm64、amd64 |
ANDROID | Android 构建标志 | 1(启用) |
DEBUG | 调试构建标志 | 1(启用调试符号) |
SNAPSHOT_VERSION | 覆盖版本字符串 | v0.8.0 |
环境显示:
make env此命令显示所有构建变量,包括:
- 主机架构检测
- 内核版本
- 编译器版本
- 目标架构设置
- 版本信息
测试
单元测试
运行单元测试:
go test -v ./...使用竞态检测器运行:
make test-race竞态检测器构建 (Makefile:216-224):
- 启用
CGO_ENABLED=1以实现 C 集成 - 与 libpcap 静态链接
- 使用竞态检测器识别数据竞争
端到端测试
项目为每个主要模块提供 E2E 测试脚本:
运行特定 E2E 测试:
make e2e-tls # 测试 TLS/SSL 捕获
make e2e-gnutls # 测试 GnuTLS 捕获
make e2e-gotls # 测试 Go TLS 捕获运行所有 E2E 测试:
make e2eCI/CD 流水线
GitHub Actions 工作流架构
来源:.github/workflows/go-c-cpp.yml:1-128、.github/workflows/release.yml:1-129
CI 构建矩阵
CI 系统构建并测试多种配置:
| 架构 | 本地构建 | 交叉编译 | Android |
|---|---|---|---|
| x86_64 | ✓ CO-RE + non-CO-RE | ✓ arm64 目标 | ✓ arm64 |
| arm64 | ✓ CO-RE + non-CO-RE | ✓ amd64 目标 | ✓ amd64 |
CI 构建步骤:
设置环境 (.github/workflows/go-c-cpp.yml:16-33):
- 安装 Go 1.24.6
- 安装 Clang 14、LLVM 工具
- 提取并准备 Linux 内核源码
本地 CO-RE 构建 (.github/workflows/go-c-cpp.yml:38-44):
bashmake clean make env DEBUG=1 make -j8代码质量检查 (.github/workflows/go-c-cpp.yml:45-50):
- 对 Go 代码运行
golangci-lint - 版本:v2.1
- 对 Go 代码运行
Non-CO-RE 构建 (.github/workflows/go-c-cpp.yml:51-55):
bashmake clean make nocore交叉编译 (.github/workflows/go-c-cpp.yml:56-65):
bashCROSS_ARCH=arm64 make env CROSS_ARCH=arm64 make -j8 ANDROID=1 CROSS_ARCH=arm64 make nocore -j8测试执行 (.github/workflows/go-c-cpp.yml:66-67):
bashgo test -v -race ./...
来源:.github/workflows/go-c-cpp.yml:9-127
编译器版本管理
CI 系统确保一致的编译器版本:
Clang/LLVM 设置:
for tool in "clang" "llc" "llvm-strip"
do
sudo rm -f /usr/bin/$tool
sudo ln -s /usr/bin/$tool-14 /usr/bin/$tool
done这会创建符号链接以强制使用 Clang 14 (.github/workflows/go-c-cpp.yml:20-24)。
内核源码准备:
cd /usr/src
source_file=$(find . -maxdepth 1 -name "*linux-source*.tar.bz2")
sudo tar -xf $source_file
cd $source_dir
sudo make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- prepare V=0为交叉编译准备内核头文件 (.github/workflows/go-c-cpp.yml:25-32)。
来源:.github/workflows/go-c-cpp.yml:16-33
发布流程
发布工作流
来源:.github/workflows/release.yml:1-129、builder/Makefile.release:1-151
发布目标
创建快照(开发构建):
make -f builder/Makefile.release snapshot创建发布(特定版本):
SNAPSHOT_VERSION=v0.8.0 make -f builder/Makefile.release release发布到 GitHub:
SNAPSHOT_VERSION=v0.8.0 make -f builder/Makefile.release publishrelease 目标编排 (builder/Makefile.release:10):
snapshot:构建 Linux 产物build_deb:创建 DEB 包snapshot_android:构建 Android 产物
来源:builder/Makefile.release:10-151
打包格式
TAR.GZ 归档文件
归档内容:
ecapture二进制文件LICENSECHANGELOG.mdREADME.md和README_CN.md
命名约定:
ecapture-{VERSION}-{OS}-{ARCH}[-nocore].tar.gz示例:
ecapture-v0.8.0-linux-amd64.tar.gz(CO-RE + non-CO-RE)ecapture-v0.8.0-android-arm64-nocore.tar.gz(仅 non-CO-RE)
归档创建 (builder/Makefile.release:62-76):
$(CMD_MKDIR) -p $(TAR_DIR)
$(CMD_CP) LICENSE $(TAR_DIR)/LICENSE
$(CMD_CP) bin/ecapture $(TAR_DIR)/ecapture
$(CMD_TAR) -czf $(OUT_ARCHIVE) $(TAR_DIR)来源:builder/Makefile.release:62-76、functions.mk:62-76
DEB 包
包结构:
ecapture-v0.8.0-amd64.deb
├── DEBIAN/
│ └── control
└── usr/
└── local/
└── bin/
└── ecapture控制文件字段 (builder/Makefile.release:143-149):
- Package: ecapture
- Version: 从 git 标签提取
- Architecture: amd64 或 arm64
- Maintainer: CFC4N cfc4ncs@gmail.com
- Description: capture SSL/TLS text content without CA cert by eBPF
构建过程:
make -f builder/Makefile.release deb使用 dpkg-deb --build 创建 DEB 包 (builder/Makefile.release:151)。
来源:builder/Makefile.release:132-151
Docker 镜像
多架构构建:
docker buildx build \
--platform linux/amd64,linux/arm64 \
--build-arg VERSION=v0.8.0 \
-t ecapture:v0.8.0 \
-t ecapture:latest \
--push .Dockerfile 阶段 (builder/Dockerfile:1-39):
构建器阶段:Ubuntu 22.04 基础镜像
- 安装编译器(Clang 14、Go 1.24.6)
- 使用
make all构建 eCapture
运行时阶段:Alpine Linux
- 仅复制
ecapture二进制文件 - 设置 ENTRYPOINT 为
/ecapture
- 仅复制
镜像标签:
{username}/ecapture:v{VERSION}(特定版本){username}/ecapture:latest(最新发布)
来源:.github/workflows/release.yml:101-129、builder/Dockerfile:1-39
发布说明生成
发布工作流自动生成发布说明:
获取前一个标签 (.github/workflows/release.yml:63-67):
bashPREVIOUS=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")通过 GitHub API 生成说明 (.github/workflows/release.yml:68-80):
bashgh api --method POST \ /repos/$REPO/releases/generate-notes \ -f tag_name=$TAG \ -f previous_tag_name=$PREVIOUS_TAG创建发布 (builder/Makefile.release:124):
bashgh release create $(VERSION) $$FILES \ --title "eCapture $(VERSION)" \ --notes-file $(RELEASE_NOTES)
来源:.github/workflows/release.yml:63-87、builder/Makefile.release:114-124
开发工作流总结
典型开发周期
设置环境:
bash/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/gojue/ecapture/master/builder/init_env.sh)"克隆并构建:
bashgit clone https://github.com/gojue/ecapture.git cd ecapture make env # 验证环境 make all # 构建所有内容进行修改:
- 在
kern/中修改 eBPF 程序 - 在
cli/、user/或其他包中修改 Go 代码
- 在
测试:
bashmake clean make all go test -v ./... make e2e # 如果测试模块格式化代码:
bashmake format # 使用 clang-format 格式化 C 代码提交并推送:
bashgit add . git commit -m "Your change description" git push origin your-branch创建 Pull Request:
- CI 自动在 x86_64 和 arm64 上运行
- 测试本地和交叉编译构建
- 使用 golangci-lint 检查代码质量
关键构建命令参考
| 命令 | 用途 | 使用场景 |
|---|---|---|
make env | 显示构建环境 | 验证配置 |
make all | 完整构建(CO-RE + non-CO-RE) | 开发 |
make nocore | 仅 non-CO-RE 构建 | 旧内核 |
make clean | 删除构建产物 | 清理重建 |
make test-race | 使用竞态检测器运行测试 | 查找并发问题 |
make e2e | 运行 E2E 测试 | 集成测试 |
make format | 格式化 C 代码 | 代码风格 |
CROSS_ARCH=arm64 make | 为 ARM64 交叉编译 | ARM 目标 |
ANDROID=1 make nocore | 为 Android 构建 | 移动部署 |