Pourquoi notre pare-feu (Ubuntu 8.04) rejette le paquet final (FIN, ACK, PSH) avec un RST


20

Contexte, pendant longtemps, nous avons eu des problèmes avec notre pare-feu qui maintiennent parfois les requêtes HTTP suspendues partiellement chargées jusqu'à ce que TCP expire.

Après avoir tracé le trafic sur le pare-feu, j'ai remarqué qu'il ne se produit que dans certaines conditions de synchronisation, par exemple lorsque le serveur Web a envoyé la réponse entière avant que le client ait envoyé son deuxième ACK sur la charge utile. [SYN, SYN / ACK, ACK] a été échangé, REQUEST a été envoyé et ACK'ed et le premier paquet RESPONSE a été reçu et ACK'ed, puis le serveur Web envoie le reste du corps de la réponse en une seule fois (8 paquets y compris le dernier FIN, PSH) et avant que le client ait ACKé l'un de ceux-ci, le pare-feu REJETTE avec un RST vers le serveur Web et maintient le client suspendu infini.

Voici l'intégralité de la trace wireShark avec des paquets des deux côtés du pare-feu. 192.168.126.161 est l'adresse IP NAT'et privée du client. 172.16.1.2 est l'IP du serveur Web (ne montrant pas l'IP publique réelle) et 10.1.1.1 est l'IP externe du pare-feu (ne montrant pas l'IP publique réelle)

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

J'ai creusé et consigné la traversée de paquets selon ce tableau et il semble que le dernier paquet entrant 2133 ait dépassé raw-PREROUTING, conntrack, mangle-PREROUTING mais est ensuite perdu. Je n'ai pas de règles REJECT dans mes iptables, j'enregistre toutes les règles DROP et aucune d'entre elles ne montre où le paquet 2133 est perdu.

J'aimerais utiliser la cible TRACE sur le filtre entrant, mais malheureusement ubuntu 8.04 n'est pas livré avec le support de la cible TRACE.

Je crois donc que certaines règles de routage / conntrack / mangling implicites internes s'appliquent qui, pour une raison quelconque, réinitialise la connexion. Peut-être que le trafic déclenche une protection DOS, mais je ne sais pas où configurer / analyser cela. Le plus frustrant est qu'un paquet est rejeté et que rien n'est enregistré ...

La demande de ce fichier fonctionne également à 100% à partir des hôtes Windows, mais elle échoue sur certains hôtes Linux et 99,9% de toutes les demandes passent mais parfois le timing des paquets déclenche ce comportement dans notre pare-feu.

EDIT Ok, maintenant j'ai ajouté des tonnes de connexion à iptables et il semble que ce qui suit se produit (je ne sais toujours pas pourquoi!)

Pour les paquets traversant avec succès le pare-feu, les étapes suivantes sont suivies, les références de table / étape d' ici

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]

Le paquet 2133 qui est rejeté passe par ces étapes:

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

Ce qui est étrange, c'est que la décision de routage pour le paquet 2133 à l'étape 5 est maintenant différente de la décision de routage pour les autres paquets. Lors de l'analyse de requêtes qui fonctionnent, par exemple ne se bloquent pas, même le dernier FIN est correctement routé. Il semble que ce soit un bogue dans le noyau ou que la décision de routage soit en quelque sorte avec état.

MODIFIER

Une chose qui pourrait provoquer ces problèmes est le fait suivant, le trafic est acheminé entre le pare-feu et le LAN local, de sorte que le LAN client n'est pas directement connecté au pare-feu via 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 )  |                        |
                +---------------------------+       +------------------+                         +------------------------+

Dans cette image, 10.1.1.1 représente l'adresse IP externe du pare-feu, toutes les autres adresses sont les vraies adresses IP utilisées.

Voici la table de routage sur le pare-feu:

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

Notez que 10.1.1.0 et gw 10.1.1.15 par défaut sont constitués, le reste est exactement le même que celui utilisé. J'ai dû ajouter manuellement la route 192.168.126.0/24 pour atteindre le réseau de laboratoire à partir de eth0 (192.168.60.254).

Voici quelques journaux détaillés sur la traversée de paquets pour le dernier paquet 2133 qui est rejeté en raison de son routage vers l'hôte local (par exemple le pare-feu).

[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 

Encore une fois, notre IP externe fw a été remplacée par 10.1.1.1 et l'IP du serveur Web en dehors du réseau NAT est remplacée par 172.16.1.2

EDIT Breaking News!

Ok, le dernier essai a été de SUPPRIMER le paquet RST, très très intéressant, j'ai ajouté une règle iptables qui a supprimé tous les paquets RST destinés au serveur Web sur lequel nous avons des problèmes pour demander des fichiers. Et ensuite, cela a fonctionné, par exemple, le dernier paquet FIN, ACK, PSH 2133 dans le journal ci-dessus est supprimé, mais comme le RST est supprimé, le serveur Web a le temps d'obtenir toutes les fourmis de l'ACK, puis décide de retransmettre le dernier paquet, le paquet 2133 à nouveau, et maintenant, il passe par le pare-feu puisque le module de contrack a maintenant vu les ACK revenir du client et autorise le dernier paquet ACK, FIN avec la charge utile finale.

C'est donc définitivement un problème de timing / fenêtre, ce fichier particulier, avec le timing des ACK du client, déclenche quelque chose dans conntrack qui rejette le paquet final du serveur web.

Jusqu'à présent, la recherche sur Google et la lecture des documents du noyau ne révèlent rien qui puisse provoquer ce comportement, la prochaine étape sera de lire le code source du noyau pour le module de routage / conntrack.

PROBLÈME RÉSOLU

Eh bien, au moins maintenant, nous savons exactement ce qui se passe et nous avons une solution de contournement qui résout le problème.

Sergey a souligné la très précieuse règle de correspondance état -m - état INVALID qui a beaucoup aidé dans le débogage.Je me rends maintenant compte qu'une configuration iptables sans règle explicite pour les paquets INVALID n'est pas complète, donc un comportement étrange semble parfois se produire.

Lorsque vous activez la connexion dans le module conntrack pour ce qui cause le paquet invalide, ce qui se passe est assez évident et j'ai eu mes soupçons à ce sujet.

[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 

Encore une fois, 172.16.1.2 est le serveur Web externe (qui se comporte incorrectement) et 10.1.1.1 est l'adresse externe du pare-feu.

Le serveur Web envoie plus de données sur le câble que le client n'en a annoncé dans la fenêtre de réception (conntrack est plein d'état et le vérifie), il semble que ce soit lorsque le paquet FIN arrive que conntrack échoue car la fenêtre de réception est dépassée plus tôt.

Je pense que cela pourrait être dû à un déchargement TCP incorrect dans la carte réseau du serveur Web. Lorsque j'ai commencé à analyser cela, j'ai pris des captures sur le serveur Web et selon les traces tcpdump / wireShark, des trames jumbo ont été écrites par la couche TCP dans le noyau qui a ensuite été segmentée en plus petites trames avec MTU = 1500 par la carte réseau. Donc, évidemment, cela doit être résolu dans le serveur Web car ce n'est pas le comportement TCP correct d'envoyer plus de données que le récepteur n'a de publicités dans sa fenêtre de réception.

Polynôme et Sergey ont tous deux fourni des informations précieuses, mais Sergey m'a signalé le comportement exact du module conntrack / NAT en ce qui concerne la traversée de paquets.


Avez-vous des instructions REJECT dans votre configuration iptables? Si tel est le cas, voyez si vous pouvez utiliser la journalisation pour déterminer de quelle règle il s'agit.
Ladadadada

Non, pas de règles de rejet, il semble que le REJET se produise en dehors d'iptablesm, cela se produit pendant la décision de routage
ernelli

Est-il possible que le pare-feu ne prenne pas en charge les fenêtres coulissantes? Comment une capture à partir d'un client fonctionnel se compare-t-elle à celle-ci?
joeqwerty

Quand cela fonctionne, à part tous les paquets transmis correctement au client et aucun paquet RST retourné, le client envoie des ACK avant la FIN finale du serveur. J'ai examiné un vidage à partir d'un gros fichier (300k) et puis il n'y a aucun problème. Une trace d'un petit fichier fonctionne également, le paquet final avec FIN est transmis. Pouvez-vous s'il vous plaît élaborer sur "le pare-feu ne prend pas en charge les fenêtres coulissantes"
ernelli

Pouvez-vous développer la connexion entre le routeur et le client de laboratoire? Vous avez / 24 netmasks sur les 60 et 126, donc on ne sait pas comment les clients du laboratoire peuvent envoyer du trafic? Leur masque de réseau n'est-il pas un / 24? Y a-t-il une sorte d'arp proxy? Existe-t-il un alias sur eth0: 1 pour le 126.0 / 24?
polynôme

Réponses:


9

Une situation similaire est décrite sur http://www.spinics.net/lists/netfilter/msg51408.html : certains paquets qui auraient dû être traités par NAT ont en quelque sorte été marqués comme INVALIDES au lieu d'ESTABLISHED et sont allés à la chaîne INPUT. Vous devez ajouter quelques règles avec -m state --state INVALIDpour vérifier cela, et la réponse à http://www.spinics.net/lists/netfilter/msg51409.html suggère qu'un tel paquet INVALID devrait toujours être DROPped, car NAT n'est pas exécuté correctement sur eux , par conséquent, les adresses qui s'y trouvent peuvent être erronées.

Si vos paquets problématiques sont vraiment marqués comme INVALIDES, l'ajout résoudra iptables -I INPUT -m state --state INVALID -j DROPprobablement le problème (le paquet cassé n'atteindra pas le processus local et ne provoquera pas la réponse RST, puis TCP récupérera du paquet perdu après un délai d'expiration). Ensuite, vous pouvez essayer de déboguer davantage le problème, comme décrit dans http://www.spinics.net/lists/netfilter/msg51411.html :

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

(Dans ce cas particulier, le problème a été causé par un matériel réseau cassé le long du chemin, probablement combiné à une rupture de déchargement de la somme de contrôle TCP.)


4

J'ai vu ce comportement sur d'autres types de pare-feu et le comportement était tellement identique que j'ai pensé que je le mettrais dehors.

Le problème que j'avais était que le pare-feu était NAT dans le même espace que les ports éphémères de la boîte. Cela provoquerait ce comportement exact si les deux entraient en collision car le noyau supposait maintenant que la connexion était destinée à la machine locale. À cette fin, vous pouvez vérifier quelques éléments. Commencez-vous par spécifier la configuration du port sortant dans iptables (en utilisant --to-ports)? Ou avez-vous modifié la plage de ports éphémères sur la machine:

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

Pour diagnostiquer, vous pouvez configurer votre capture et voir si vous voyez d'autres demandes en utilisant la même ip fw externe, combo de port dans un délai de 3 * MSL avant le RST (~ 180s je pense).

Bien que je ne sois pas sûr que ce soit la réponse, si j'étais dans cette situation, j'exclurais cela en premier, puis j'examinerais quelques autres choses.

Est-ce facile à reproduire? Est-il possible de capturer plus de diagnostics à partir du pare-feu et de voir le problème se produire? J'essaierais de capturer:

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

chaque seconde environ en essayant de se reproduire et de voir s'il y a quelque chose qui se lie localement au port et à quoi ressemblait la table de mascarade pendant le problème.

Si vous pare-feu le RST sortant, l'éventuel ACK du client interne entraîne-t-il la réussite de la connexion?

Dernière chose, voyez-vous tous les journaux? Avez-vous déjà vérifié dmesg? Avez-vous installé *. * Sur la boîte de pare-feu dans la configuration syslog dans un fichier pour vous en assurer?

Faites-moi savoir ce que vous trouvez! J'apprécie vraiment la quantité d'informations que vous avez fournies dans la question, merci.


Merci pour vos efforts, je peux reproduire l'erreur à 100%, toutes les demandes via le pare-feu fonctionnent sauf très peu. Ceux qui ne travaillent pas semblent rencontrer un problème de taille / calendrier précis. Je peux ajouter plusieurs traces Wireshark pour des demandes plus grandes / plus petites entre le même client / serveur Web via le pare-feu qui fonctionne, mais la trace ci-dessus est celle qui reste bloquée. J'ai ajouté de nouvelles informations ci-dessus qui pourraient programmer une lumière sur le problème.
ernelli

/ proc / sys / net / ipv4 / ip_local_port_range est défini sur [32768 61000] netstat n'affiche aucun port lié localement. ip_conntrack affiche la connexion comme établie, par exemple, elle croit qu'elle est toujours ouverte puisque le dernier FIN n'a pas été transmis au client. Le statut est paquets = 10 octets = 12084 [ASSURÉ] mark = 0 secmark = 0 use = 1
ernelli
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.