Eu quebrei o cliente que precisava atender e não posso alterá-lo ou afetá-lo de nenhuma maneira. Eu coloquei o mesmo software no windows e no linux. O Windows está funcionando, o Linux não é. Depois de analisar, descobri que esse é o problema do TCP Handshaking. Aqui está um dump simplificado:
Servidor do Windows:
SYN(seq=X,ack=0)--->
<---SYN,ACK(seq=Y,ack=X+1)
SYN(seq=X,ack=0)---> (TCP Retransmission)
SYN(seq=X,ack=0)---> (TCP Retransmission)
<---SYN,ACK(seq=Y,ack=X+1) (TCP Retransmission)
SYN(seq=X,ack=0)---> (TCP Retransmission)
<---SYN,ACK(seq=Y,ack=X+1) (TCP Retransmission)
SYN(seq=X,ack=0)---> (TCP Retransmission)
<---RST(seq=Y+1,ack=X+1)
SYN(seq=Z,ack=0)--->
<---SYN,ACK(seq=V,ack=Z+1)
ACK(seq=Z+1,ack=V+1)--->
<---PSH,ACK(seq=V+1,ack=Z+1)
.......WORKING.........
Servidor Linux:
SYN(seq=X,ack=0)--->
<---SYN,ACK(seq=Y,ack=X+1)
SYN(seq=X,ack=0)---> (TCP Retransmission)
<---SYN,ACK(seq=Y,ack=X+1) (TCP Retransmission)
<---SYN,ACK(seq=Y,ack=X+1) (TCP Retransmission)
SYN(seq=X,ack=0)---> (TCP Retransmission)
<---SYN,ACK(seq=Y,ack=X+1) (TCP Retransmission)
<---SYN,ACK(seq=Y,ack=X+1) (TCP Retransmission)
SYN(seq=X,ack=0)---> (TCP Retransmission)
<---SYN,ACK(seq=Y,ack=X+1) (TCP Retransmission)
<---SYN,ACK(seq=Y,ack=X+1) (TCP Retransmission)
SYN(seq=X,ack=0)---> (TCP Retransmission)
<---SYN,ACK(seq=Y,ack=X+1) (TCP Retransmission)
<---SYN,ACK(seq=Y,ack=X+1) (TCP Retransmission)
SYN(seq=Z,ack=0)--->
<---SYN,ACK(seq=V,ack=Z+1)
SYN(seq=Z,ack=0)---> (TCP Retransmission)
<---SYN,ACK(seq=V,ack=Z+1) (TCP Retransmission)
<---SYN,ACK(seq=V,ack=Z+1) (TCP Retransmission)
SYN(seq=Z,ack=0)---> (TCP Retransmission)
<---SYN,ACK(seq=V,ack=Z+1) (TCP Retransmission)
<---SYN,ACK(seq=V,ack=Z+1) (TCP Retransmission)
SYN(seq=Z,ack=0)---> (TCP Retransmission)
<---SYN,ACK(seq=V,ack=Z+1) (TCP Retransmission)
<---SYN,ACK(seq=V,ack=Z+1) (TCP Retransmission)
SYN(seq=Z,ack=0)---> (TCP Retransmission)
<---SYN,ACK(seq=V,ack=Z+1) (TCP Retransmission)
<---SYN,ACK(seq=V,ack=Z+1) (TCP Retransmission)
......ENDLESS LOOP.......
Note que o TCP Retransmission não é causado por timeouts de rede ou algo assim, eu acredito que este cliente quebrado simplesmente ignore, solte-os.
A chave para fazer esse handshake funcionar é enviar um pacote com apenas o sinalizador RST (RST, ACK não funciona). O Windows está fazendo isso ingenuamente, como fazer isso funcionar no linux?
Existe alguma opção / configuração do kernel do Linux para conseguir isso?
Existe algum sinalizador / opção de soquete (como SO_LINGER)?
Talvez alguma outra maneira de fazer isso funcionar no Linux?
Minha solução atual é colocar essas regras nftables:
nft 'add rule input input tcp dport > 1024 tcp flags & (fin | syn | rst | psh | ack | urg) == syn limit rate over 5/minute burst 3 packets ip protocol tcp reject with tcp reset'
nft 'add rule input output tcp sport > 1024 tcp flags & (fin | syn | rst | psh | ack | urg) == rst | ack tcp flags set rst'
Primeiro, tenta descobrir essa retransmissão de SYN e responder com a reinicialização tcp (RST, ACK). Segundo um swap que RST, ACK em RST. ..mas esta solução alternativa está suja e pode afetar outra transmissão também: - (
Tags nftables tcp socket linux-kernel