查看文档目录

四层转发:把客户端 IP 传给源站

四层转发“回源携带客户端 IP”的三个选项怎么选,TOA 选项的格式与限制,在源站安装 TOA 接收端,以及怎么验证源站拿到了客户端地址。

三个选项

四层转发编辑页的“回源携带客户端 IP”有三个选项,只能选一个,都只用于 TCP。

选项源站需要做什么说明
关闭无源站看到的是节点地址
PROXY protocol v1源站程序支持 PROXY protocol(如 nginx listen ... proxy_protocol、HAProxy accept-proxy)改应用配置,不改内核;IPv4、IPv6 客户端都能传
TOA源站安装 TOA 接收端(内核模块或 eBPF 版)应用不用改,通过 getpeername() 拿到客户端地址;只传 IPv4

TOA 怎么工作

节点在发往源站的 TCP 连接上,从三次握手的 ACK 开始,在最先几个数据段里加一个 TCP 选项:kind 254、长度 8,内容是客户端端口(2 字节)和 IPv4 地址(4 字节),网络字节序。源站确认收到数据后,节点就不再加这个选项。源站的 TOA 接收端读到它,让这条连接的 getpeername() 返回客户端地址。

限制:

  • 只传 IPv4 客户端。IPv6 客户端的连接照常转发,但不带 TOA,源站看到节点地址;需要 IPv6 客户端地址时改用 PROXY protocol。
  • 源站没装接收端时,内核忽略这个选项,连接不受影响,只是拿不到客户端地址。
  • 节点需要 Linux 5.10 及以上内核。
  • 节点到源站之间如果有会剥掉未知 TCP 选项的设备(部分防火墙、负载均衡),TOA 会丢失。

在源站安装接收端

我们不分发源站模块。常用的开源实现如下,使用前请按各仓库的说明和许可证自行确认:

实现地址备注
华为云 ELB TOAhttps://github.com/huaweicloud/elb-toa内核模块
Huawei TCP_option_addresshttps://github.com/Huawei/TCP_option_address内核模块,较老,新内核可能编译不过
阿里云 CDN TOAhttps://github.com/aliyun/alibabacloud-cdn-tool-toa内核模块与 eBPF 版(eBPF 版要求 5.10 以上内核和 cgroup v2)

内核模块一般需要与运行内核一致的头文件,例如 Debian/Ubuntu 的 linux-headers-$(uname -r)、RHEL/Rocky 的 kernel-devel-$(uname -r),再按仓库说明编译并 insmod。

验证

  1. 在四层转发里选择“TOA”并发布。
  2. 从一台客户端连接转发端口,看源站应用日志里记录的对端地址,应为客户端的公网地址。
  3. 不要用 ss -tn 或 netstat 判断:内核模块版接收端只改 getpeername() 的返回值,不改内核连接表,这两个命令看到的仍是节点地址。
  4. 没生效时在源站抓包:tcpdump -nn -v -i <网卡> 'tcp port <源站端口>',握手 ACK 的选项里应能看到 kind 254(tcpdump 显示为 exp- 开头)。抓得到但应用里仍是节点地址,说明接收端没装好;抓不到,检查节点内核版本和中间设备。

常见问题

装了 TOA,应用日志里还是节点地址

先抓包确认选项到了源站。到了,再确认接收端已加载、应用读的是 getpeername() 而不是自己解析别的头。

客户端是 IPv6

TOA 不传 IPv6 客户端,改用 PROXY protocol v1。