Perché il nostro firewall (Ubuntu 8.04) rifiuta il pacchetto finale (FIN, ACK, PSH) con un RST


20

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.


Hai delle dichiarazioni REJECT nella tua configurazione di iptables? In tal caso, vedere se è possibile utilizzare la registrazione per capire quale sia la regola.
Ladadadada,

No, nessuna regola di rifiuto sembra che il REJECT avvenga al di fuori di iptablesm durante la decisione di routing
Ernelli,

È possibile che il firewall non supporti le finestre scorrevoli? Come si confronta una cattura da un client funzionante con questa?
joeqwerty,

Quando funziona, a parte il fatto che tutti i pacchetti vengono inoltrati correttamente al client e non vengono restituiti pacchetti RST, il client invia gli ACK prima del FIN finale dal server. Ho esaminato un dump da un file di grandi dimensioni (300k) e quindi non ci sono problemi. Funziona anche una traccia da un piccolo file, il pacchetto finale con FIN viene inoltrato. Potete per favore approfondire "Il firewall non supporta le finestre scorrevoli"
Ernelli

È possibile espandere la connessione tra il router e il client di laboratorio? Hai / 24 netmask sui 60 e 126, quindi non è chiaro come i client di laboratorio sono in grado di inviare traffico? La loro maschera di rete non è un / 24? Sta succedendo una specie di arp proxy? Esiste un alias su eth0: 1 per il 126.0 / 24?
polinomio,

Risposte:


9

Una situazione simile è descritta su http://www.spinics.net/lists/netfilter/msg51408.html : alcuni pacchetti che avrebbero dovuto essere elaborati da NAT in qualche modo sono stati contrassegnati come INVALID anziché ESTABLISHED e sono passati alla catena INPUT. Dovresti aggiungere alcune regole -m state --state INVALIDper verificarlo, e la risposta su http://www.spinics.net/lists/netfilter/msg51409.html suggerisce che tale pacchetto INVALID dovrebbe sempre essere DROPped, perché NAT non viene eseguito correttamente su di essi , pertanto gli indirizzi in essi contenuti potrebbero essere errati.

Se i pacchetti problematici sono contrassegnati come INVALID, l'aggiunta iptables -I INPUT -m state --state INVALID -j DROPprobabilmente risolverà il problema (il pacchetto interrotto non arriverà al processo locale e non causerà la risposta RST, quindi TCP si ripristinerà dal pacchetto perso dopo un timeout). Quindi puoi provare a eseguire il debug del problema ulteriormente, come descritto in http://www.spinics.net/lists/netfilter/msg51411.html :

echo 255 >/proc/sys/net/netfilter/nf_conntrack_log_invalid

(In quel caso particolare il problema è stato causato da un hardware di rete rotto lungo il percorso, probabilmente combinato con un po 'di rottura offload checksum TCP.)


4

Ho visto questo comportamento su altri tipi di firewall e il comportamento era così identico che ho pensato di buttarlo lì.

Il problema che avevo era che il firewall stava NAT nello stesso spazio delle porte effimere sulla scatola. Ciò provocherebbe questo comportamento esatto se i due si scontrassero perché il kernel ora supponeva che la connessione fosse pensata per il computer locale. A tal fine ci sono un paio di cose che puoi controllare. Innanzitutto stai specificando la configurazione della porta in uscita in iptables (usando --to-port)? Oppure hai modificato l'intervallo di porte effimere sulla macchina:

$ cat /proc/sys/net/ipv4/ip_local_port_range

Per diagnosticare puoi impostare la tua acquisizione e vedere se vedi altre richieste usando lo stesso ip fw esterno, porta combo entro 3 * MSL prima dell'RST (~ 180s credo).

Anche se non sono sicuro che sia la risposta, se mi trovassi in questa situazione, lo escluderei prima e poi guarderei un altro paio di cose.

È facile da riprodurre? È possibile acquisire più diagnostica dalla casella del firewall e vedere che si verifica il problema? Vorrei provare a catturare:

$ netstat -anp
$ cat /proc/net/ip_conntrack

circa ogni secondo mentre provi a riprodurre e vedere se c'è qualcosa che si lega localmente alla porta e come appariva la tabella mascherata durante il problema.

Se si esegue il firewall dell'output RST, l'eventuale ACK dal client interno provoca il corretto collegamento?

Ultima cosa, vedi tutti i registri? Hai già controllato dmesg? Hai impostato *. * Sulla casella del firewall nella configurazione di syslog su un file per assicurarti?

Fammi sapere cosa trovi! Apprezzo molto la quantità di informazioni fornite nella domanda, grazie.


Grazie per il tuo impegno, posso riprodurre l'errore al 100%, tutte le richieste attraverso il firewall funzionano tranne pochissime. Coloro che non lavorano sembrano colpire un preciso problema di dimensioni / tempistica. Posso aggiungere più tracce di Wireshark per richieste sempre più grandi tra lo stesso client / server Web attraverso il firewall che funziona, ma la traccia sopra è quella che si blocca. Ho aggiunto nuove informazioni sopra che potrebbero programmare una luce sul problema.
Ernelli,

/ proc / sys / net / ipv4 / ip_local_port_range è impostato su [32768 61000] netstat non mostra alcuna porta associata localmente. ip_conntrack mostra la connessione come stabilita, ad esempio ritiene che sia ancora aperta poiché l'ultimo FIN non è stato inoltrato al client. Lo stato è pacchetti = 10 byte = 12084 [ASSICURATO] mark = 0 secmark = 0 use = 1
ernelli
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.