@Otokaze
2018-10-06T17:43:48.000000Z
字数 1250
阅读 903
笔记
Linux 中有两种透明代理方式(只讨论 TCP 和 UDP):REDIRECT、TPROXY。
IP_TRANSPARENT
选项。REDIRECT 方式注定只能透明代理 TCP,因为 UDP 在经过 DNAT 之后,无法使用 SO_ORIGINAL_DST
套接字选项来获取原始的目的地址和目的端口。目前的解决办法是,通过 TPROXY 来代理 UDP,使用此方法代理 UDP 时,需要先为监听套接字设置 IP_RECVORIGDSTADDR
选项,然后在收到 UDP 包之后(使用 recvmsg()
而不是 recvfrom()
),获取原始目的地址信息,进行透明代理。
解释一下 IP_TRANSPARENT
选项的作用,它的作用有两个:
所以要使用 TPROXY 进行透明代理,IP_TRANSPARENT
套接字选项是必不可少的。
REDIRECT TCP 透明代理思路
SO_ORIGINAL_DST
socket 选项获取原始目的地址信息。TPROXY TCP 透明代理思路
IP_TRANSPARENT
选项,然后再绑定要监听地址。getsockname()
获取目的地址(即 self-side 地址)。TPROXY UDP 透明代理思路
IP_TRANSPARENT
、IP_RECVORIGDSTADDR
选项,绑定要监听地址。recvmsg()
接收 UDP 包,获取原始地址信息,然后发送该 UDP 数据给目的主机。IP_TRANSPARENT
选项,bind 原始地址再发给客户端。但是,如果按照上面的 TPROXY UDP 实现思路,那么它将只能用于透明代理 request-response 类型的 UDP 上层协议,如 DNS,但是类似 QUIC 这样的非 request-response 类型的 UDP 上层协议会出现问题,因为端口号变了,导致它们依靠端口号来识别用户的策略失效,即 QUIC 协议无法正常工作。
解决方法:在代理程序内部维护一个 hash table,手动维护一个状态信息,防止端口变化。