基于 eBPF 和 Go 实现透明代理
本文介绍了如何利用 eBPF 的能力,并通过 Go 和 ebpf-go 包实现高性能透明代理。原文:Transparent Proxy Implementation using eBPF and Go
透明代理(transparent proxy),也称为内联代理(inline proxy),可以拦截并重定向客户端请求,而无需修改请求或对客户端进行配置。透明代理对用户来说是不可见的,意味着用户不会察觉到它的存在,也无需调整网络设置。这项技术对于网络管理、安全策略执行、流量监控和优化来说至关重要。透明代理能够执行一系列功能,包括内容过滤、缓存加速、流量控制和负载均衡等。实现透明代理的常用技术包括 TPROXY、NAT 等。
本文将展示如何利用 eBPF 实现透明代理,具体来说就是结合 Go 语言以及 ebpf-go 包来实现。

⚠️注意:关于 eBPF,本文不会涉及太多细节,如果对这个话题不太熟悉,可以查看其他文章。
Security Evaluation: eBPF vs. WebAssembly
eBPF-Powered Load Balancing for SO_REUSEPORT
eBPF 在透明代理中的应用
扩展的伯克利数据包过滤器(eBPF,Extended Berkeley Packet Filter)是一种强大工具,可用于实现透明代理,能够在 Linux 内核中运行沙盒程序。这种能力使其能够进行高性能数据包处理和实时流操作,避免在用户空间和内核空间之间进行上下文切换所带来的开销。
用 eBPF 实现透明代理涉及三个 eBPF 程序,每个程序负责网络拦截和转发的不同功能:
连接建立时的地址替换:第一个 eBPF 程序
cgroup/connect4
附加到connect
系统调用。当客户端尝试连接目标服务器时,此程序拦截连接尝试,将目标 IP 地址和端口替换为本地透明代理的地址和端口 —— 这种重定向对客户端来说是完全透明的。同时,原目标地址和端口被存储在map_socks
eBPF 映射中,以便其他 eBPF 程序稍后引用此信息。连接建立后的源地址记录:第二个 eBPF 程序
sockops
在代理与目标服务器成功建立连接后执行。其主要功能是记录连接的源地址和端口。此信息会更新map_socks
eBPF 映射中的相应条目。此外,源端口和套接字的 cookie(唯一标识符)被映射到map_ports
eBPF 映射中,确保所有必要的连接详情可供其他 eBPF 程序使用。此步骤对于维护网络连接状态至关重要。基于原始目标信息的转发:第三个 eBPF 程序
cgroup/getsockopt
在 Pipy 代理使用getsockopt
调用查询原始目标信息时被触发。该程序通过源端口从map_ports
中获取原始套接字的 cookie,然后访问存储在map_socks
中的原始目标信息。利用这些信息,与原始目标服务器建立连接,并转发客户端请求。从而确保流量在经过代理处理后能透明的重定向到其预期的目的地。
这三个程序都链接到特定的 cgroup,在我们的例子中是根 cgroup,但也可以是其他任何 cgroup。从而确保只有当该组内的进程执行指定系统调用(syscalls)时,才会被激活。目前,我们的配置仅代理 TCP IPv4 连接,但也可以适应其他协议。
下图展示了整个设置,每种颜色代表一个不同阶段,按以下顺序执行:
红色 -> 绿色 -> 紫色 -> 粉色

这就是理论上需要的全部内容,接下来我们看一下代码。
💡提示:代码里添加了一些有用的注释帮助读者理解
用户空间代码
内核空间代码
如果想尝试一下,这是 GitHub 仓库链接:GitHub - dorkamotorka/transparent-proxy-ebpf
性能评估
下面是基本性能测试,以评估该 eBPF 项目对主机服务器的影响,特别关注在拦截流量时的延迟和 CPU 负载情况。测试内容包括测量 10,000 次请求的平均延迟。

研究结果表明,eBPF 程序平均会带来约 1 毫秒固定开销。此外,每个钩子引入的平均 CPU 负载情况如下:套接字操作为 0.4%,cgroup/connect4
为 0.1%,cgroup/getsockopt
为 0.09%。基本上没什么影响。
研究结果表明,尽管 eBPF 程序会带来额外延迟和 CPU 负载,但其带来的流量拦截优势却足以弥补这些不足。
⚠️ 注意:此实现的灵感来源于 Pipy,通过使用 ebpf-go 添加了用户空间实现,从而扩展其功能。此外,还对内核空间代码进行了少量修改,并添加了多处注释以增强可读性。
结论
总之,基于 eBPF 实现透明代理为网络拦截和转发提供了强大的解决方案。通过利用 eBPF 的能力,例如高性能数据包处理和在 Linux 内核中进行实时流量操作,透明代理能够高效管理各种用途的网络流量,包括安全执行、流量监控和优化。示例展示了 eBPF 与 Go 的集成,展示了不同 eBPF 程序如何无缝协作以实现透明代理功能。这种方法不仅确保了最小的开销,还为扩展代理功能以支持除 TCP IPv4 连接之外的其他协议提供了灵活性。
你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。为了方便大家以后能第一时间看到文章,请朋友们关注公众号"DeepNoMind",并设个星标吧,如果能一键三连(转发、点赞、在看),则能给我带来更多的支持和动力,激励我持续写下去,和大家共同成长进步!
版权声明: 本文为 InfoQ 作者【俞凡】的原创文章。
原文链接:【http://xie.infoq.cn/article/d2a5b039af6ac180e38908978】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论