• Willy Tarreau's avatar
    tcp: fix tcp_defer_accept to consider the timeout · 6d01a026
    Willy Tarreau authored
    I was trying to use TCP_DEFER_ACCEPT and noticed that if the
    client does not talk, the connection is never accepted and
    remains in SYN_RECV state until the retransmits expire, where
    it finally is deleted. This is bad when some firewall such as
    netfilter sits between the client and the server because the
    firewall sees the connection in ESTABLISHED state while the
    server will finally silently drop it without sending an RST.
    
    This behaviour contradicts the man page which says it should
    wait only for some time :
    
           TCP_DEFER_ACCEPT (since Linux 2.4)
              Allows a listener to be awakened only when data arrives
              on the socket.  Takes an integer value  (seconds), this
              can  bound  the  maximum  number  of attempts TCP will
              make to complete the connection. This option should not
              be used in code intended to be portable.
    
    Also, looking at ipv4/tcp.c, a retransmit counter is correctly
    computed :
    
            case TCP_DEFER_ACCEPT:
                    icsk->icsk_accept_queue.rskq_defer_accept = 0;
                    if (val > 0) {
                            /* Translate value in seconds to number of
                             * retransmits */
                            while (icsk->icsk_accept_queue.rskq_defer_accept < 32 &&
                                   val > ((TCP_TIMEOUT_INIT / HZ) <<
                                           icsk->icsk_accept_queue.rskq_defer_accept))
                                    icsk->icsk_accept_queue.rskq_defer_accept++;
                            icsk->icsk_accept_queue.rskq_defer_accept++;
                    }
                    break;
    
    ==> rskq_defer_accept is used as a counter of retransmits.
    
    But in tcp_minisocks.c, this counter is only checked. And in
    fact, I have found no location which updates it. So I think
    that what was intended was to decrease it in tcp_minisocks
    whenever it is checked, which the trivial patch below does.
    Signed-off-by: default avatarWilly Tarreau <w@1wt.eu>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    6d01a026
tcp_minisocks.c 22.2 KB