Para fechamento: o problema foi um erro estúpido no meu código (no cliente).
O cliente, neste caso, usa soquetes não-bloqueadores, então a chamada connect()
retornará imediatamente enquanto o kernel espera pelo pacote SYN, ACK do servidor. Infelizmente, o código do cliente era muito impaciente: se a conexão não fosse estabelecida após algumas centenas de milissegundos, o cliente chamaria close()
no soquete.
Em alguns casos raros, os pacotes SYN e ACK do servidor seriam atrasados por várias centenas de milissegundos no caminho pela rede. Quando a resposta atrasada finalmente chegava ao host do cliente, o kernel veria que o soquete já estava fechado e trataria a resposta SYN, ACK como pertencente a um soquete inválido. É por isso que ele responderia com um pacote RST ao servidor.
Então, sim, é possível que o código do aplicativo (usando API de soquete estilo BSD normal no Linux) cause este pacote RST: usando um soquete não bloqueador e fechando a conexão enquanto o handshake de três vias ainda está em andamento.