如何设置TCP套接字选项,在握手阶段发送ACK/RST?(HAProxy探测场景)
HAProxy用户态探测机制的实现思路
你观察到的是HAProxy的半连接式健康探测流程,对应的报文交互如下:
Client -> [SYN] -> Server Client <- [ACK/SYN] <- Server Client -> [ACK/RST] -> Server
这种探测逻辑完全在用户态实现,无需修改内核网络栈,核心依赖以下套接字技巧:
使用原始套接字(Raw Socket)
原始套接字允许用户态程序直接构造和发送IP层及以下的报文。HAProxy会手动构造符合TCP规范的SYN包,指定目标端口、序列号等字段,通过原始套接字发送给后端服务器。同时,它会监听网卡上的IP报文,过滤出目标为自身探测端口的SYN+ACK响应。自定义报文解析与响应处理
收到服务器返回的SYN+ACK后,HAProxy不会让内核自动完成三次握手(否则会建立完整连接,浪费资源),而是手动构造ACK+RST包发送给服务器,直接终止连接流程。这一步同样通过原始套接字实现,避免内核介入连接管理。套接字选项辅助
为了让原始套接字能正确接收和处理报文,会设置必要的套接字选项:- 设置
IP_HDRINCL选项,允许用户态程序自行构造IP头部,而非由内核生成; - 绑定到特定网卡或端口,配合BPF过滤规则,只接收与探测相关的报文,减少无用数据处理;
- 使用非阻塞模式(
O_NONBLOCK),避免探测逻辑阻塞主线程。
- 设置
绕过内核TCP连接跟踪
由于所有报文都由用户态构造和处理,内核的TCP连接跟踪模块不会将这些探测报文识别为有效连接,也就不会生成对应的连接条目,避免了内核资源的占用。
内容的提问来源于stack exchange,提问作者Junhui Zhu
相关产品推荐
相关产品推荐

