Sullo sfondo, per molto tempo abbiamo avuto problemi con il nostro firewall che a volte mantengono le richieste HTTP sospese parzialmente caricate fino al timeout di TCP.
Dopo aver tracciato il traffico sul firewall, ho notato che si verifica solo in determinate condizioni di temporizzazione, ad esempio quando il server web ha inviato l'intera risposta prima che il client abbia inviato il suo secondo ACK sul payload. [SYN, SYN / ACK, ACK] è stato scambiato, RICHIESTA è stata inviata e ACK 'e il primo pacchetto RESPONSE è stato ricevuto e ACK', quindi il server web invia il resto del corpo della risposta in un colpo (8 pacchetti incluso l'ultimo FIN, PSH) e prima che il client abbia ACKato qualcuno di questi, il Firewall RIFIUTA con un RST verso il server web e mantiene il client sospeso in modo infinito.
Ecco l'intera traccia diarshark con pacchetti da entrambi i lati del firewall. 192.168.126.161 è l'indirizzo IP NAT'et privato del client. 172.16.1.2 è l'IP del server web (non mostra l'IP pubblico reale) e 10.1.1.1 è l'IP esterno del firewall (non mostra l'IP pubblico reale)
2105 0.086275 192.168.126.161 172.16.1.2 TCP 37854 > http [SYN] Seq=0 Win=5840 Len=0 MSS=1460 SACK_PERM=1 TSV=89375083 TSER=0
2106 0.000066 10.1.1.1 172.16.1.2 TCP 37854 > http [SYN] Seq=0 Win=5840 Len=0 MSS=1460 SACK_PERM=1 TSV=89375083 TSER=0
2107 0.002643 172.16.1.2 10.1.1.1 TCP http > 37854 [SYN, ACK] Seq=0 Ack=1 Win=32768 Len=0 MSS=1460
2108 0.007705 172.16.1.2 192.168.126.161 TCP http > 37854 [SYN, ACK] Seq=0 Ack=1 Win=32768 Len=0 MSS=1460
2109 0.006301 192.168.126.161 172.16.1.2 TCP 37854 > http [ACK] Seq=1 Ack=1 Win=5840 Len=0
2110 0.000025 10.1.1.1 172.16.1.2 TCP 37854 > http [ACK] Seq=1 Ack=1 Win=5840 Len=0
2111 0.000007 192.168.126.161 172.16.1.2 HTTP GET /test/style.css HTTP/1.1
2112 0.000015 10.1.1.1 172.16.1.2 HTTP GET /test/style.css HTTP/1.1
2113 0.001536 172.16.1.2 10.1.1.1 TCP http > 37854 [ACK] Seq=1 Ack=111 Win=32658 Len=0
2114 0.000014 172.16.1.2 192.168.126.161 TCP http > 37854 [ACK] Seq=1 Ack=111 Win=32658 Len=0
2115 0.002274 172.16.1.2 10.1.1.1 HTTP HTTP/1.1 200 OK (text/css)
2116 0.000025 172.16.1.2 192.168.126.161 HTTP HTTP/1.1 200 OK (text/css)
2117 0.005689 192.168.126.161 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=1461 Win=8760 Len=0
2118 0.000024 10.1.1.1 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=1461 Win=8760 Len=0
2119 0.001536 172.16.1.2 10.1.1.1 HTTP Continuation or non-HTTP traffic
2120 0.000026 172.16.1.2 192.168.126.161 HTTP Continuation or non-HTTP traffic
2121 0.000007 172.16.1.2 10.1.1.1 HTTP Continuation or non-HTTP traffic
2122 0.000023 172.16.1.2 192.168.126.161 HTTP Continuation or non-HTTP traffic
2123 0.000313 172.16.1.2 10.1.1.1 HTTP Continuation or non-HTTP traffic
2124 0.000030 172.16.1.2 192.168.126.161 HTTP Continuation or non-HTTP traffic
2125 0.000007 172.16.1.2 10.1.1.1 HTTP Continuation or non-HTTP traffic
2126 0.000023 172.16.1.2 192.168.126.161 HTTP Continuation or non-HTTP traffic
2127 0.000009 172.16.1.2 10.1.1.1 HTTP Continuation or non-HTTP traffic
2128 0.000023 172.16.1.2 192.168.126.161 HTTP Continuation or non-HTTP traffic
2129 0.001108 172.16.1.2 10.1.1.1 HTTP Continuation or non-HTTP traffic
2130 0.000035 172.16.1.2 192.168.126.161 HTTP Continuation or non-HTTP traffic
2131 0.000008 172.16.1.2 10.1.1.1 HTTP Continuation or non-HTTP traffic
2132 0.000022 172.16.1.2 192.168.126.161 HTTP Continuation or non-HTTP traffic
2133 0.000007 172.16.1.2 10.1.1.1 HTTP Continuation or non-HTTP traffic
REJECT-->
2134 0.000089 10.1.1.1 172.16.1.2 TCP 37854 > http [RST] Seq=111 Win=0 Len=0
CLIENT FIRST ACK-->
2135 0.002421 192.168.126.161 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=2921 Win=11680 Len=0
2136 0.000033 10.1.1.1 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=2921 Win=11680 Len=0
2137 0.000007 192.168.126.161 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=4381 Win=14600 Len=0
2138 0.000014 10.1.1.1 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=4381 Win=14600 Len=0
2139 0.000008 192.168.126.161 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=5841 Win=17520 Len=0
2140 0.000014 10.1.1.1 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=5841 Win=17520 Len=0
2141 0.000007 192.168.126.161 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=7301 Win=20440 Len=0
2142 0.000013 10.1.1.1 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=7301 Win=20440 Len=0
2143 0.000007 192.168.126.161 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=8761 Win=23360 Len=0
2144 0.000015 10.1.1.1 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=8761 Win=23360 Len=0
2145 0.000007 192.168.126.161 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=10221 Win=26280 Len=0
2146 0.000013 10.1.1.1 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=10221 Win=26280 Len=0
2147 0.001059 192.168.126.161 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=11681 Win=29200 Len=0
2148 0.000018 10.1.1.1 172.16.1.2 TCP 37854 > http [ACK] Seq=111 Ack=11681 Win=29200 Len=0
Sto scavando e registrando l'attraversamento dei pacchetti secondo questo grafico e sembra che l'ultimo pacchetto in arrivo 2133 abbia superato raw-PREROUTING, conntrack, mangle-PREROUTING ma poi sia perso. Non ho regole REJECT nel mio iptables, registro tutte le regole DROP e nessuna mostra dove si perde il pacchetto 2133.
Mi piacerebbe usare il target TRACE sul filtro in entrata, ma purtroppo Ubuntu 8.04 non viene fornito con il supporto per il target TRACE.
Quindi credo che si applichino alcune regole interne di routing / conntrack / mangling implicite che per qualche ragione ripristina la connessione. Forse il traffico innesca una certa protezione DOS, ma non ho idea di dove configurarlo / analizzarlo. La cosa più frustrante è che un pacchetto viene rifiutato e nulla viene registrato ...
Anche la richiesta di questo file funziona al 100% dagli host Windows, ma non riesce su alcuni host Linux e il 99,9% di tutte le richieste arriva, ma a volte la tempistica dei pacchetti attiva questo comportamento nel nostro firewall.
EDIT Ok, ora ho aggiunto tonnellate di logging in iptables e sembra che succeda quanto segue (ancora non so perché!)
Per i pacchetti che attraversano con successo il firewall, vengono presi i seguenti passaggi, riferimenti tabella / passo da qui
Table 3-3 step
2 raw-pre
conntrack
3 mangle-pre
4 [nat-pre]
5 routing-decision -> destination forward
6 mangle-fwd
7 filter-fwd
8 mangle-post
9 [nat-post]
Il pacchetto 2133 che viene rifiutato attraversa questi passaggi:
Table 3-1 steps for the incoming FIN,ACK packet 2133
2 raw-pre
conntrack
3 mangle-pre
4 [nat-pre]
5 routing-decision -> destination local
6 mangle-input
7 filter-input
8 local process emits RST -> webserver
Table 3-2 steps for the outgoing RST packet 2134 in response to 2133
1 raw-out
2 routing decision
conntrack
3 mangle-out
reroute-check
4 [nat-out]
5 filter-out
6 mangle-post
7 nat-post
La cosa strana è che la decisione di routing per il pacchetto 2133 nel passaggio 5 ora è diversa dalla decisione di routing per gli altri pacchetti. Quando si analizzano richieste che funzionano, ad es. Non si blocca, anche l'ultimo FIN viene instradato correttamente. Sembra un bug nel kernel o che la decisione di instradamento sia in qualche modo piena di stato.
MODIFICARE
Una cosa che potrebbe causare questi problemi è il fatto seguente, il traffico viene instradato tra il firewall e la LAN locale, quindi la LAN client non è direttamente collegata al firewall tramite L2.
+---------------------------+ +------------------+ +------------------------+
| | | Router | ( Lab network ) | |
( Internet ) -- + eth1 eth0 +-------+ +-- ( ) -+ Client 192.168.126.161 |
| 10.1.1.1 192.168.60.254 | | | ( 192.168.126.0/24 ) | |
+---------------------------+ +------------------+ +------------------------+
In questa immagine, 10.1.1.1 rappresenta l'indirizzo IP esterno del firewall, tutti gli altri indirizzi sono gli indirizzi IP reali utilizzati.
Ecco la tabella di routing sul firewall:
Destination Gateway Genmask Flags Metric Ref Use Iface
10.1.1.0 0.0.0.0 255.255.255.240 U 0 0 0 eth1
192.168.126.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
192.168.60.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
0.0.0.0 10.1.1.15 0.0.0.0 UG 0 0 0 eth1
Si noti che 10.1.1.0 e gw 10.1.1.15 predefiniti sono composti, il resto è esattamente lo stesso usato. Ho dovuto aggiungere manualmente il percorso 192.168.126.0/24 per raggiungere la rete del laboratorio da eth0 (192.168.60.254).
Ecco alcuni log estesi sull'attraversamento dei pacchetti per l'ultimo pacchetto 2133 che viene rifiutato a causa del routing verso l'host locale (ad esempio il firewall).
[16406874.374588] raw pre IN=eth1 OUT= MAC=00:02:b3:b9:ff:b5:00:90:1a:10:06:88:08:00 SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=13739 DF PROTO=TCP SPT=80 DPT=53497 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0
[16406874.374625] mangle pre IN=eth1 OUT= MAC=00:02:b3:b9:ff:b5:00:90:1a:10:06:88:08:00 SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=13739 DF PROTO=TCP SPT=80 DPT=53497 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0
[16406874.374667] mangle in IN=eth1 OUT= MAC=00:02:b3:b9:ff:b5:00:90:1a:10:06:88:08:00 SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=13739 DF PROTO=TCP SPT=80 DPT=53497 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0
[16406874.374699] filter in IN=eth1 OUT= MAC=00:02:b3:b9:ff:b5:00:90:1a:10:06:88:08:00 SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=13739 DF PROTO=TCP SPT=80 DPT=53497 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0
[16406874.374780] mangle out IN= OUT=eth1 SRC=10.1.1.1 DST=172.16.1.2 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=53497 DPT=80 WINDOW=0 RES=0x00 RST URGP=0
[16406874.374807] mangle post IN= OUT=eth1 SRC=10.1.1.1 DST=172.16.1.2 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=53497 DPT=80 WINDOW=0 RES=0x00 RST URGP=0
[16406874.378813] mangle pre IN=eth0 OUT= MAC=00:02:b3:b9:ff:b4:00:90:1a:10:0c:dd:08:00 SRC=192.168.126.161 DST=172.16.1.2 LEN=40 TOS=0x00 PREC=0x00 TTL=63 ID=35424 DF PROTO=TCP SPT=53497 DPT=80 WINDOW=11680 RES=0x00 ACK URGP=0
[16406874.378863] mangle fwd IN=eth0 OUT=eth1 SRC=192.168.126.161 DST=172.16.1.2 LEN=40 TOS=0x00 PREC=0x00 TTL=62 ID=35424 DF PROTO=TCP SPT=53497 DPT=80 WINDOW=11680 RES=0x00 ACK URGP=0
Ancora una volta, il nostro IP esterno fw è stato sostituito con 10.1.1.1 e l'ip del webserver esterno alla rete NAT è sostituito con 172.16.1.2
EDIT Ultime notizie!
Ok, l'ultimo tentativo è stato di DROP il pacchetto RST, molto interessante, ho aggiunto una regola iptables che ha eliminato tutti i pacchetti RST destinati al server web da cui abbiamo problemi a richiedere i file. E poi ha funzionato, ad esempio l'ultimo pacchetto FIN, ACK, PSH 2133 nel registro sopra è stato eliminato, ma poiché l'RST viene eliminato, il server web ha il tempo di ottenere tutta la formica dell'ACK, quindi decide di ritrasmettere l'ultimo pacchetto, il pacchetto 2133 ancora una volta, e ora passa attraverso il firewall dal momento che il modulo di contrack ha visto il ritorno di ACK dal client e consente l'ultimo pacchetto ACK, FIN con il payload finale.
Quindi è sicuramente un problema di temporizzazione / finestra, questo particolare file, con la tempistica degli ACK dal client, innesca qualcosa in conntrack che rifiuta il pacchetto finale dal server web.
Finora, cercare su Google e leggere i documenti del kernel non rivela nulla che possa causare questo comportamento, il prossimo passo sarà leggere il codice sorgente del kernel per il modulo routing / conntrack.
PROBLEMA RISOLTO
Bene, almeno ora sappiamo esattamente cosa succede e abbiamo una soluzione alternativa che risolve il problema.
Sergey ha sottolineato la preziosa regola di corrispondenza INVALID -m state --state che ha aiutato molto nel debug, ora mi rendo conto che un'installazione di iptables senza una regola esplicita per i pacchetti INVALID non è completa, quindi a volte sembra accadere un comportamento strano.
Quando si abilita la registrazione nel modulo conntrack per ciò che causa il pacchetto non valido, cosa succede è abbastanza ovvio e avevo il mio sospetto al riguardo.
[16659529.322465] nf_ct_tcp: SEQ is over the upper bound (over the window of the receiver) IN= OUT= SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=40874 DF PROTO=TCP SPT=80 DPT=55498 SEQ=658735108 ACK=1194081763 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0
Ancora una volta, 172.16.1.2 è il server web esterno (che si comporta in modo errato) e 10.1.1.1 è l'indirizzo esterno del firewall.
Il server web invia più dati sul filo di quanto il client abbia pubblicizzato nella finestra di ricezione (conntrack è pieno di stato e lo verifica), sembra che sia quando arriva il pacchetto FIN che conntrack salta fuori dal momento che la finestra di ricezione è effettivamente superata molto in precedenza.
Credo che potrebbe essere causato da un offloading TCP errato nella scheda di rete sul server web. Quando ho iniziato ad analizzare questo, ho catturato il server web e secondo le tracce tcpdump / WireShark i jumbo frame sono stati scritti dallo strato TCP nel kernel che è stato quindi segmentato in frame più piccoli con MTU = 1500 dalla scheda di rete. Quindi, ovviamente, questo deve essere risolto nel server web poiché non è corretto il comportamento TCP per inviare più dati di quanti il destinatario abbia le pubblicità nella sua finestra di ricezione.
Sia Polynomial che Sergey hanno fornito un prezioso contributo, ma Sergey mi ha indicato l'esatto comportamento del modulo conntrack / NAT per quanto riguarda l'attraversamento di pacchetti.