如何设置TCP套接字选项让它在握手时发送ACK/RST?

问题描述 投票:0回答:3

我注意到HAProxy的探测机制是这样的:

Client -> [SYN]     -> Server
Client <- [ACK/SYN] <- Server
Client -> [ACK/RST] -> Server

浏览HAProxy的源代码后,我认为他们并没有修改网络堆栈行为并在用户模式下实现这一点。所以我想这是套接字选项的一个技巧。你能给我一些提示吗?

c linux networking tcp operating-system
3个回答
1
投票

我使用 TCP Fast Open 复制了所描述的行为。当使用

connect()
时,TCP客户端(您标记为服务器)将等待SYN-ACK并回复ACK。

这是我的例子:

#include <unistd.h>
#include <arpa/inet.h>
    
int main() {
        int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

        struct sockaddr_in sai;
        sai.sin_family = AF_INET;
        sai.sin_port = htons(1234);
        sai.sin_addr.s_addr = inet_addr("127.0.0.1");

        struct linger sl;
        sl.l_onoff = 1;         /* non-zero value enables linger option in kernel */
        sl.l_linger = 0;        /* timeout interval in seconds */
        setsockopt(sock, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl));

        int ret = sendto(sock, NULL, 0, MSG_FASTOPEN | MSG_MORE, &sai, sizeof(sai));
        if(ret == -1) {
                //Probing or TFO failed
                //If TFO failed, try connect()
        }
        close(sock);
}

0
投票

这实际上是一个非常合理的问题,如何为了进行健康检查而这样做。而且如何做到这一点并不明显。

我不知道如何使用正常的套接字操作获取Syn、Syn-Ack、Ack-Rst;我能想到的最接近的是打开连接,然后立即以 SO_LINGER 间隔 0 关闭它。

但是即使你可以复制它,仍然存在一个问题,即用户空间应用程序想要快速获知 Syn-Ack 是否到达(正常的 TCP 连接如果没有回复就会重传 Syn,并最终放弃)与您想要获得健康检查答案的速度相比,需要花费相当长的时间)。由于所有这些都是在内核 TCP 实现中处理的,因此我认为没有任何方法可以快速知道 Syn-Ack 已到达。这让我相信这不是通过正常的套接字操作来完成的。

我要做的是在用户空间应用程序中构造一个 Syn 数据包并使用原始套接字发送它。使用 Iptables/netfilter 将 Syn-Ack 回复发送到用户空间。如果 Syn-Ack 及时到达,您的健康检查就会通过。当它到达时,内核 TCP 堆栈也会看到它(除非您使用 Iptables/netfilter 阻止它)并立即回复重置(因为它不知道连接)。


0
投票

这应该由默认选项“nolinger”控制,这将设置套接字选项SO_LINGER。当套接字关闭时检查它。你可以在内核源文件“net/ipv4/tcp.c”的“__tcp_close”中找到这样的信息

© www.soinside.com 2019 - 2024. All rights reserved.