Linux有没有一种方法来记录发送TCP RST数据包的原因?

5
在运行内核4.11.8-1.el6.elrepo.x86_64时,想知道TCP堆栈发送某些RST数据包的原因,即是否有类似BSD中的net.inet.tcp.log_debug=1的Linux对应项?以下是需要查找原因的其中一种情况:握手中最终到达的ACK后立即发送了RST。可以看到SYN丢失多次,并且在超过1秒后仍未到达最后一个ACK。但仍不清楚为什么会发送RST。禁用syn cookie也没有帮助。
15:27:41.166799 IP CLIENT.16537 > SERVER.80: Flags [S], seq 1397492268, win 29200, options [mss 1440,sackOK,TS val 1230199 ecr 0,nop,wscale 6], length 0
15:27:41.166820 IP SERVER.80 > CLIENT.16537: Flags [S.], seq 1773519351, ack 1397492269, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 9], length 0
15:27:42.069572 IP CLIENT.16537 > SERVER.80: Flags [S], seq 1397492268, win 29200, options [mss 1460,sackOK,TS val 1230299 ecr 0,nop,wscale 6], length 0
15:27:42.069590 IP SERVER.80 > CLIENT.16537: Flags [S.], seq 1773519351, ack 1397492269, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 9], length 0
15:27:43.123141 IP SERVER.80 > CLIENT.16537: Flags [S.], seq 1773519351, ack 1397492269, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 9], length 0
15:27:44.067228 IP CLIENT.16537 > SERVER.80: Flags [S], seq 1397492268, win 29200, options [mss 1460,sackOK,TS val 1230499 ecr 0,nop,wscale
 6], length 0
15:27:44.067240 IP SERVER.80 > CLIENT.16537: Flags [S.], seq 1773519351, ack 1397492269, win 29200, options [mss 1460,nop,nop,sackOK,nop,wscale 9], length 0
15:27:46.547072 IP CLIENT.16537 > SERVER.80: Flags [.], ack 1, win 457, length 0
15:27:46.547094 IP SERVER.80 > CLIENT.16537: Flags [R], seq 1773519352, win 0, length 0
15:27:46.548177 IP CLIENT.16537 > SERVER.80: Flags [.], ack 1, win 457, options [nop,nop,sack 1 {0:1}], length 0
15:27:46.548186 IP SERVER.80 > ClIENT.16537: Flags [R], seq 1773519352, win 0, length 0

感谢您的帮助。

1
虽然这不是问题的答案,但在这种特定情况下,客户端在“15:27:46.547072”发送了错误的“ack 1”,可能导致了RST的发送(正确应该是“ack 1773519352”)。 - user3151902
谢谢,但握手后的ACK编号为1只是tcpdump为了易读性而进行的调整。 - Utoah
您可以使用 iptables -I OUTPUT -p tcp -m tcp --tcp-flags SYN,ACK,FIN,RST RST -j LOG 来跟踪它们,然后查看 /var/log/kern.log - F. Hauri - Give Up GitHub
1个回答

3

这种精确的功能是不可用的,可以通过查看对tcp_send_active_reset的调用代码来看到。在像这样的代码中:

int tcp_disconnect(struct sock *sk, int flags)
{
    ...
    int old_state = sk->sk_state;

    if (old_state != TCP_CLOSE)
        tcp_set_state(sk, TCP_CLOSE);

    if ...
    } else if (tcp_need_reset(old_state) ||
           (tp->snd_nxt != tp->write_seq &&
            (1 << old_state) & (TCPF_CLOSING | TCPF_LAST_ACK))) {
        /* The last check adjusts for discrepancy of Linux wrt. RFC
         * states
         */
        tcp_send_active_reset(sk, gfp_any());

显示的多个原因中,导致RST未提供给任何调试宏并且未提供给tcp_send_active_reset的原因不明。Linux 4.15添加了tracepoints,包括tcp:tcp_send_reset,如这篇博客文章所述。对于许多重置,可以从函数和tracepoints的动态探测中汇总状态,以相同的方式检查并推断其选择的原因。这是一个复杂的问题,因为在我举例的重置可能产生的情况下,在具有tcp:tcp_send_reset探针的函数之前套接字已经改变了状态,因此必须在调用tcp_disconnect()tcp_set_state()时结合动态探针检查sk->sk_state以获得old_state,以及在tcp_send_active_reset的tracepoint上探测以确认将重置发送到特定套接字上。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接