Simulation de problèmes de réseau sous Linux

Bonjour à tous, je m'appelle Sasha, je dirige les tests backend chez FunCorp. Comme beaucoup d’autres, nous avons mis en place une architecture orientée services. D'une part, cela simplifie le travail, car Il est plus facile de tester chaque service séparément, mais d'un autre côté, il est nécessaire de tester l'interaction des services entre eux, ce qui se produit souvent sur le réseau.

Dans cet article, je parlerai de deux utilitaires qui peuvent être utilisés pour vérifier des scénarios de base décrivant le fonctionnement d'une application en présence de problèmes de réseau.

Simulation de problèmes de réseau sous Linux

Simulation de problèmes de réseau

En règle générale, les logiciels sont testés sur des serveurs de test dotés d'une bonne connexion Internet. Dans des environnements de production difficiles, les choses peuvent ne pas être aussi fluides, vous devez donc parfois tester des programmes dans de mauvaises conditions de connexion. Sous Linux, l'utilitaire vous aidera à simuler de telles conditions tc.

tc(abbr. du contrôle de la circulation) vous permet de configurer la transmission des paquets réseau dans le système. Cet utilitaire a de grandes capacités, vous pouvez en savoir plus à leur sujet ici. Ici, je n'en considérerai que quelques-uns : nous nous intéressons à la planification du trafic, pour laquelle nous utilisons disque q, et comme nous devons émuler un réseau instable, nous utiliserons un qdisc sans classe réseau.

Lançons un serveur d'écho sur le serveur (j'ai utilisé nmap-ncat):

ncat -l 127.0.0.1 12345 -k -c 'xargs -n1 -i echo "Response: {}"'

Afin d'afficher en détail tous les horodatages à chaque étape de l'interaction entre le client et le serveur, j'ai écrit un simple script Python qui envoie une requête Teste à notre serveur d'écho.

Code source du client

#!/bin/python

import socket
import time

HOST = '127.0.0.1'
PORT = 12345
BUFFER_SIZE = 1024
MESSAGE = "Testn"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
t1 = time.time()
print "[time before connection: %.5f]" % t1
s.connect((HOST, PORT))
print "[time after connection, before sending: %.5f]" % time.time()
s.send(MESSAGE)
print "[time after sending, before receiving: %.5f]" % time.time()
data = s.recv(BUFFER_SIZE)
print "[time after receiving, before closing: %.5f]" % time.time()
s.close()
t2 = time.time()
print "[time after closing: %.5f]" % t2
print "[total duration: %.5f]" % (t2 - t1)

print data

Lançons-le et regardons le trafic sur l'interface lo et port 12345 :

[user@host ~]# python client.py
[time before connection: 1578652979.44837]
[time after connection, before sending: 1578652979.44889]
[time after sending, before receiving: 1578652979.44894]
[time after receiving, before closing: 1578652979.45922]
[time after closing: 1578652979.45928]
[total duration: 0.01091]
Response: Test

Décharge de trafic

[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
10:42:59.448601 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flags [S], seq 3383332866, win 43690, options [mss 65495,sackOK,TS val 606325685 ecr 0,nop,wscale 7], length 0
10:42:59.448612 IP 127.0.0.1.12345 > 127.0.0.1.54054: Flags [S.], seq 2584700178, ack 3383332867, win 43690, options [mss 65495,sackOK,TS val 606325685 ecr 606325685,nop,wscale 7], length 0
10:42:59.448622 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 606325685 ecr 606325685], length 0
10:42:59.448923 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 606325685 ecr 606325685], length 5
10:42:59.448930 IP 127.0.0.1.12345 > 127.0.0.1.54054: Flags [.], ack 6, win 342, options [nop,nop,TS val 606325685 ecr 606325685], length 0
10:42:59.459118 IP 127.0.0.1.12345 > 127.0.0.1.54054: Flags [P.], seq 1:15, ack 6, win 342, options [nop,nop,TS val 606325696 ecr 606325685], length 14
10:42:59.459213 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flags [.], ack 15, win 342, options [nop,nop,TS val 606325696 ecr 606325696], length 0
10:42:59.459268 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flags [F.], seq 6, ack 15, win 342, options [nop,nop,TS val 606325696 ecr 606325696], length 0
10:42:59.460184 IP 127.0.0.1.12345 > 127.0.0.1.54054: Flags [F.], seq 15, ack 7, win 342, options [nop,nop,TS val 606325697 ecr 606325696], length 0
10:42:59.460196 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flags [.], ack 16, win 342, options [nop,nop,TS val 606325697 ecr 606325697], length 0

Tout est standard : une poignée de main à trois, PSH/ACK et ACK en réponse deux fois - c'est l'échange de requête et de réponse entre le client et le serveur, et FIN/ACK et ACK deux fois - complétant la connexion.

Retard de paquet

Fixons maintenant le délai à 500 millisecondes :

tc qdisc add dev lo root netem delay 500ms

Nous lançons le client et constatons que le script s'exécute désormais pendant 2 secondes :

[user@host ~]# ./client.py
[time before connection: 1578662612.71044]
[time after connection, before sending: 1578662613.71059]
[time after sending, before receiving: 1578662613.71065]
[time after receiving, before closing: 1578662614.72011]
[time after closing: 1578662614.72019]
[total duration: 2.00974]
Response: Test

Qu'y a-t-il dans le trafic ? Regardons:

Décharge de trafic

13:23:33.210520 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flags [S], seq 1720950927, win 43690, options [mss 65495,sackOK,TS val 615958947 ecr 0,nop,wscale 7], length 0
13:23:33.710554 IP 127.0.0.1.12345 > 127.0.0.1.58694: Flags [S.], seq 1801168125, ack 1720950928, win 43690, options [mss 65495,sackOK,TS val 615959447 ecr 615958947,nop,wscale 7], length 0
13:23:34.210590 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 615959947 ecr 615959447], length 0
13:23:34.210657 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 615959947 ecr 615959447], length 5
13:23:34.710680 IP 127.0.0.1.12345 > 127.0.0.1.58694: Flags [.], ack 6, win 342, options [nop,nop,TS val 615960447 ecr 615959947], length 0
13:23:34.719371 IP 127.0.0.1.12345 > 127.0.0.1.58694: Flags [P.], seq 1:15, ack 6, win 342, options [nop,nop,TS val 615960456 ecr 615959947], length 14
13:23:35.220106 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flags [.], ack 15, win 342, options [nop,nop,TS val 615960957 ecr 615960456], length 0
13:23:35.220188 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flags [F.], seq 6, ack 15, win 342, options [nop,nop,TS val 615960957 ecr 615960456], length 0
13:23:35.720994 IP 127.0.0.1.12345 > 127.0.0.1.58694: Flags [F.], seq 15, ack 7, win 342, options [nop,nop,TS val 615961457 ecr 615960957], length 0
13:23:36.221025 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flags [.], ack 16, win 342, options [nop,nop,TS val 615961957 ecr 615961457], length 0

Vous pouvez voir que le décalage attendu d'une demi-seconde est apparu dans l'interaction entre le client et le serveur. Le système se comporte de manière bien plus intéressante si le décalage est plus important : le noyau commence à renvoyer certains paquets TCP. Modifions le délai à 1 seconde et regardons le trafic (je n'afficherai pas la sortie du client, il y a les 4 secondes attendues dans la durée totale) :

tc qdisc change dev lo root netem delay 1s

Décharge de trafic

13:29:07.709981 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [S], seq 283338334, win 43690, options [mss 65495,sackOK,TS val 616292946 ecr 0,nop,wscale 7], length 0
13:29:08.710018 IP 127.0.0.1.12345 > 127.0.0.1.39306: Flags [S.], seq 3514208179, ack 283338335, win 43690, options [mss 65495,sackOK,TS val 616293946 ecr 616292946,nop,wscale 7], length 0
13:29:08.711094 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [S], seq 283338334, win 43690, options [mss 65495,sackOK,TS val 616293948 ecr 0,nop,wscale 7], length 0
13:29:09.710048 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 616294946 ecr 616293946], length 0
13:29:09.710152 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 616294947 ecr 616293946], length 5
13:29:09.711120 IP 127.0.0.1.12345 > 127.0.0.1.39306: Flags [S.], seq 3514208179, ack 283338335, win 43690, options [mss 65495,sackOK,TS val 616294948 ecr 616292946,nop,wscale 7], length 0
13:29:10.710173 IP 127.0.0.1.12345 > 127.0.0.1.39306: Flags [.], ack 6, win 342, options [nop,nop,TS val 616295947 ecr 616294947], length 0
13:29:10.711140 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 616295948 ecr 616293946], length 0
13:29:10.714782 IP 127.0.0.1.12345 > 127.0.0.1.39306: Flags [P.], seq 1:15, ack 6, win 342, options [nop,nop,TS val 616295951 ecr 616294947], length 14
13:29:11.714819 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [.], ack 15, win 342, options [nop,nop,TS val 616296951 ecr 616295951], length 0
13:29:11.714893 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [F.], seq 6, ack 15, win 342, options [nop,nop,TS val 616296951 ecr 616295951], length 0
13:29:12.715562 IP 127.0.0.1.12345 > 127.0.0.1.39306: Flags [F.], seq 15, ack 7, win 342, options [nop,nop,TS val 616297952 ecr 616296951], length 0
13:29:13.715596 IP 127.0.0.1.39306 > 127.0.0.1.12345: Flags [.], ack 16, win 342, options [nop,nop,TS val 616298952 ecr 616297952], length 0

On peut voir que le client a envoyé deux fois un paquet SYN et que le serveur a envoyé deux fois un SYN/ACK.

En plus d'une valeur constante, le délai peut être défini sur un écart, une fonction de distribution et une corrélation (avec la valeur du paquet précédent). Cela se fait comme suit:

tc qdisc change dev lo root netem delay 500ms 400ms 50 distribution normal

Ici nous avons fixé le délai entre 100 et 900 millisecondes, les valeurs seront sélectionnées selon une distribution normale et il y aura une corrélation de 50% avec la valeur du délai du paquet précédent.

Vous avez peut-être remarqué que dans la première commande que j'ai utilisée ajouteret ensuite Change. La signification de ces commandes est évidente, j'ajouterai donc simplement qu'il y a plus de la, qui peut être utilisé pour supprimer la configuration.

Perte de paquets

Essayons maintenant de faire une perte de paquets. Comme le montre la documentation, cela peut être fait de trois manières : perdre des paquets de manière aléatoire avec une certaine probabilité, utiliser une chaîne de Markov de 2, 3 ou 4 états pour calculer la perte de paquets, ou utiliser le modèle d'Elliott-Gilbert. Dans l'article, je considérerai la première méthode (la plus simple et la plus évidente), et vous pourrez en lire d'autres ici.

Faisons la perte de 50% des paquets avec une corrélation de 25% :

tc qdisc add dev lo root netem loss 50% 25%

Malheureusement, tcpdump ne pourra pas nous montrer clairement la perte de paquets, nous supposerons seulement que cela fonctionne réellement. Et la durée d'exécution accrue et instable du script nous aidera à le vérifier. client.py (peut être complété instantanément, ou peut-être en 20 secondes), ainsi qu'un nombre accru de paquets retransmis :

[user@host ~]# netstat -s | grep retransmited; sleep 10; netstat -s | grep retransmited
    17147 segments retransmited
    17185 segments retransmited

Ajouter du bruit aux paquets

En plus de la perte de paquets, vous pouvez simuler des dommages aux paquets : du bruit apparaîtra à une position aléatoire du paquet. Faisons des dommages aux paquets avec une probabilité de 50 % et sans corrélation :

tc qdisc change dev lo root netem corrupt 50%

On lance le script client (rien d'intéressant là-bas, mais cela a pris 2 secondes), regardons le trafic :

Décharge de trafic

[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
10:20:54.812434 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [S], seq 2023663770, win 43690, options [mss 65495,sackOK,TS val 1037001049 ecr 0,nop,wscale 7], length 0
10:20:54.812449 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flags [S.], seq 2104268044, ack 2023663771, win 43690, options [mss 65495,sackOK,TS val 1037001049 ecr 1037001049,nop,wscale 7], length 0
10:20:54.812458 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 1037001049 ecr 1037001049], length 0
10:20:54.812509 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1037001049 ecr 1037001049], length 5
10:20:55.013093 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1037001250 ecr 1037001049], length 5
10:20:55.013122 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flags [.], ack 6, win 342, options [nop,nop,TS val 1037001250 ecr 1037001250], length 0
10:20:55.014681 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flags [P.], seq 1:15, ack 6, win 342, options [nop,nop,TS val 1037001251 ecr 1037001250], length 14
10:20:55.014745 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [.], ack 15, win 340, options [nop,nop,TS val 1037001251 ecr 1037001251], length 0
10:20:55.014823 IP 127.0.0.1.43666 > 127.0.0.5.12345: Flags [F.], seq 2023663776, ack 2104268059, win 342, options [nop,nop,TS val 1037001251 ecr 1037001251], length 0
10:20:55.214088 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flags [P.], seq 1:15, ack 6, win 342, options [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]>
10:20:55.416087 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [F.], seq 6, ack 15, win 342, options [nop,nop,TS val 1037001653 ecr 1037001251], length 0
10:20:55.416804 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flags [F.], seq 15, ack 7, win 342, options [nop,nop,TS val 1037001653 ecr 1037001653], length 0
10:20:55.416818 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [.], ack 16, win 343, options [nop,nop,TS val 1037001653 ecr 1037001653], length 0
10:20:56.147086 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flags [F.], seq 15, ack 7, win 342, options [nop,nop,TS val 1037002384 ecr 1037001653], length 0
10:20:56.147101 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flags [.], ack 16, win 342, options [nop,nop,TS val 1037002384 ecr 1037001653], length 0

On peut voir que certains paquets ont été envoyés à plusieurs reprises et qu'il y a un paquet avec des métadonnées brisées : options [non, inconnu-65 0x0a3dcf62eb3d, [mauvaise option]>. Mais l'essentiel est qu'à la fin, tout a fonctionné correctement - TCP a fait face à sa tâche.

Duplication de paquets

Que pouvez-vous faire d'autre avec réseau? Par exemple, simulez la situation inverse de perte de paquets : duplication de paquets. Cette commande prend également 2 arguments : probabilité et corrélation.

tc qdisc change dev lo root netem duplicate 50% 25%

Changer l'ordre des paquets

Vous pouvez mélanger les sacs de deux manières.

Dans le premier cas, certains paquets sont envoyés immédiatement, le reste avec un délai spécifié. Exemple tiré de la documentation :

tc qdisc change dev lo root netem delay 10ms reorder 25% 50%

Avec une probabilité de 25 % (et une corrélation de 50 %), le paquet sera envoyé immédiatement, le reste sera envoyé avec un délai de 10 millisecondes.

La deuxième méthode consiste à envoyer chaque Nième paquet instantanément avec une probabilité (et une corrélation) donnée, et le reste avec un délai donné. Exemple tiré de la documentation :

tc qdisc change dev lo root netem delay 10ms reorder 25% 50% gap 5

Un colis sur cinq a 25 % de chances d'être envoyé sans délai.

Modification de la bande passante

Généralement partout où ils font référence TBF, mais avec l'aide réseau Vous pouvez également modifier la bande passante de l'interface :

tc qdisc change dev lo root netem rate 56kbit

Cette équipe fera des randonnées autour localhost aussi pénible que de surfer sur Internet via un modem commuté. En plus de définir le débit binaire, vous pouvez également émuler le modèle de protocole de couche liaison : définissez la surcharge du paquet, la taille de la cellule et la surcharge de la cellule. Par exemple, cela peut être simulé ATM et débit 56 kbit/s :

tc qdisc change dev lo root netem rate 56kbit 0 48 5

Simulation du délai d'attente de connexion

Un autre point important dans le plan de test lors de l'acceptation du logiciel concerne les délais d'attente. Ceci est important car dans les systèmes distribués, lorsqu'un des services est désactivé, les autres doivent revenir aux autres à temps ou renvoyer une erreur au client, et en aucun cas ils ne doivent simplement se bloquer, en attendant une réponse ou une connexion. être établit.

Il existe plusieurs façons de procéder : par exemple, utiliser un mock qui ne répond pas, ou se connecter au processus à l'aide d'un débogueur, mettre un point d'arrêt au bon endroit et arrêter le processus (c'est probablement la manière la plus perverse). Mais l’une des solutions les plus évidentes consiste à mettre en place un pare-feu sur les ports ou les hôtes. Cela nous aidera avec ça iptables.

Pour la démonstration, nous allons pare-feu le port 12345 et exécuterons notre script client. Vous pouvez protéger les paquets sortants vers ce port chez l'expéditeur ou les paquets entrants chez le destinataire. Dans mes exemples, les paquets entrants seront protégés par un pare-feu (nous utilisons la chaîne INPUT et l'option --dport). De tels paquets peuvent être DROP, REJECT ou REJECT avec l'indicateur TCP RST, ou avec un hôte ICMP inaccessible (en fait, le comportement par défaut est port icmp inaccessible, et il y a aussi la possibilité d'envoyer une réponse icmp-net-inaccessible, icmp-proto-inaccessible, icmp-net-interdit и hôte-icmp-interdit).

GOUTTE

S'il existe une règle avec DROP, les paquets « disparaîtront » simplement.

iptables -A INPUT -p tcp --dport 12345 -j DROP

Nous lançons le client et constatons qu'il se bloque au stade de la connexion au serveur. Regardons le trafic :
Décharge de trafic

[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
08:28:20.213506 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flags [S], seq 3019694933, win 43690, options [mss 65495,sackOK,TS val 1203046450 ecr 0,nop,wscale 7], length 0
08:28:21.215086 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flags [S], seq 3019694933, win 43690, options [mss 65495,sackOK,TS val 1203047452 ecr 0,nop,wscale 7], length 0
08:28:23.219092 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flags [S], seq 3019694933, win 43690, options [mss 65495,sackOK,TS val 1203049456 ecr 0,nop,wscale 7], length 0
08:28:27.227087 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flags [S], seq 3019694933, win 43690, options [mss 65495,sackOK,TS val 1203053464 ecr 0,nop,wscale 7], length 0
08:28:35.235102 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flags [S], seq 3019694933, win 43690, options [mss 65495,sackOK,TS val 1203061472 ecr 0,nop,wscale 7], length 0

On peut voir que le client envoie des paquets SYN avec un délai d'attente croissant de façon exponentielle. Nous avons donc trouvé un petit bug dans le client : il faut utiliser la méthode settimeout()pour limiter le temps pendant lequel le client tentera de se connecter au serveur.

On supprime immédiatement la règle :

iptables -D INPUT -p tcp --dport 12345 -j DROP

Vous pouvez supprimer toutes les règles en même temps :

iptables -F

Si vous utilisez Docker et que vous devez protéger tout le trafic allant vers le conteneur, vous pouvez le faire comme suit :

iptables -I DOCKER-USER -p tcp -d CONTAINER_IP -j DROP

REJETER

Ajoutons maintenant une règle similaire, mais avec REJECT :

iptables -A INPUT -p tcp --dport 12345 -j REJECT

Le client se ferme après une seconde avec une erreur [Errno 111] Connexion refusée. Regardons le trafic ICMP :

[user@host ~]# tcpdump -i lo -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
08:45:32.871414 IP 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 tcp port 12345 unreachable, length 68
08:45:33.873097 IP 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 tcp port 12345 unreachable, length 68

On voit que le client a reçu deux fois port inaccessible puis s'est terminé par une erreur.

REJETER avec TCP-reset

Essayons d'ajouter l'option --rejeter-avec TCP-reset:

iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with tcp-reset

Dans ce cas, le client quitte immédiatement avec une erreur, car la première requête a reçu un paquet RST :

[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
09:02:52.766175 IP 127.0.0.1.60658 > 127.0.0.1.12345: Flags [S], seq 1889460883, win 43690, options [mss 65495,sackOK,TS val 1205119003 ecr 0,nop,wscale 7], length 0
09:02:52.766184 IP 127.0.0.1.12345 > 127.0.0.1.60658: Flags [R.], seq 0, ack 1889460884, win 0, length 0

REJETER avec icmp-host-unreachable

Essayons une autre option pour utiliser REJECT :

iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with icmp-host-unreachable

Le client se ferme après une seconde avec une erreur [Errno 113] Aucune route vers l'hôte, nous voyons dans le trafic ICMP Hôte ICMP 127.0.0.1 inaccessible.

Vous pouvez également essayer les autres paramètres REJECT, et je me concentrerai sur ceux-ci :)

Simulation du délai d'expiration de la demande

Une autre situation est celle où le client a pu se connecter au serveur, mais ne peut pas lui envoyer de demande. Comment filtrer les paquets pour que le filtrage ne démarre pas immédiatement ? Si vous regardez le trafic de toute communication entre le client et le serveur, vous remarquerez que lors de l'établissement d'une connexion, seuls les indicateurs SYN et ACK sont utilisés, mais lors de l'échange de données, le dernier paquet de requête contiendra l'indicateur PSH. Il s'installe automatiquement pour éviter la mise en mémoire tampon. Vous pouvez utiliser ces informations pour créer un filtre : il autorisera tous les paquets sauf ceux contenant le flag PSH. Ainsi, la connexion sera établie, mais le client ne pourra pas envoyer de données au serveur.

GOUTTE

Pour DROP, la commande ressemblerait à ceci :

iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j DROP

Lancez le client et surveillez le trafic :

Décharge de trafic

[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
10:02:47.549498 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [S], seq 2166014137, win 43690, options [mss 65495,sackOK,TS val 1208713786 ecr 0,nop,wscale 7], length 0
10:02:47.549510 IP 127.0.0.1.12345 > 127.0.0.1.49594: Flags [S.], seq 2341799088, ack 2166014138, win 43690, options [mss 65495,sackOK,TS val 1208713786 ecr 1208713786,nop,wscale 7], length 0
10:02:47.549520 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 1208713786 ecr 1208713786], length 0
10:02:47.549568 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1208713786 ecr 1208713786], length 5
10:02:47.750084 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1208713987 ecr 1208713786], length 5
10:02:47.951088 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1208714188 ecr 1208713786], length 5
10:02:48.354089 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1208714591 ecr 1208713786], length 5

On voit que la connexion est établie et que le client ne peut pas envoyer de données au serveur.

REJETER

Dans ce cas le comportement sera le même : le client ne pourra pas envoyer la requête, mais recevra ICMP 127.0.0.1 port TCP 12345 inaccessible et augmenter le temps entre les resoumissions de demandes de manière exponentielle. La commande ressemble à ceci :

iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j REJECT

REJETER avec TCP-reset

La commande ressemble à ceci :

iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j REJECT --reject-with tcp-reset

Nous savons déjà qu'en utilisant --rejeter-avec TCP-reset le client recevra un paquet RST en réponse, le comportement peut donc être prédit : recevoir un paquet RST alors que la connexion est établie signifie que le socket est fermé de manière inattendue de l'autre côté, ce qui signifie que le client devrait recevoir Connexion réinitialisée par un pair. Exécutons notre script et assurons-nous-en. Et voici à quoi ressemblera le trafic :

Décharge de trafic

[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
10:22:14.186269 IP 127.0.0.1.52536 > 127.0.0.1.12345: Flags [S], seq 2615137531, win 43690, options [mss 65495,sackOK,TS val 1209880423 ecr 0,nop,wscale 7], length 0
10:22:14.186284 IP 127.0.0.1.12345 > 127.0.0.1.52536: Flags [S.], seq 3999904809, ack 2615137532, win 43690, options [mss 65495,sackOK,TS val 1209880423 ecr 1209880423,nop,wscale 7], length 0
10:22:14.186293 IP 127.0.0.1.52536 > 127.0.0.1.12345: Flags [.], ack 1, win 342, options [nop,nop,TS val 1209880423 ecr 1209880423], length 0
10:22:14.186338 IP 127.0.0.1.52536 > 127.0.0.1.12345: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 1209880423 ecr 1209880423], length 5
10:22:14.186344 IP 127.0.0.1.12345 > 127.0.0.1.52536: Flags [R], seq 3999904810, win 0, length 0

REJETER avec icmp-host-unreachable

Je pense qu'il est déjà évident pour tout le monde à quoi ressemblera la commande :) Le comportement du client dans ce cas sera légèrement différent de celui avec un simple REJET : le client n'augmentera pas le délai d'attente entre les tentatives de renvoi du paquet.

[user@host ~]# tcpdump -i lo -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
10:29:56.149202 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
10:29:56.349107 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
10:29:56.549117 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
10:29:56.750125 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
10:29:56.951130 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
10:29:57.152107 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65
10:29:57.353115 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 unreachable, length 65

conclusion

Il n'est pas nécessaire d'écrire une simulation pour tester l'interaction d'un service avec un client ou un serveur bloqué ; il suffit parfois d'utiliser les utilitaires standards de Linux.

Les utilitaires abordés dans l'article ont encore plus de fonctionnalités que celles décrites, vous pouvez donc proposer certaines de vos propres options pour les utiliser. Personnellement, j’en ai toujours assez de ce que j’écris (en fait, encore moins). Si vous utilisez ces utilitaires ou des utilitaires similaires lors de tests dans votre entreprise, veuillez indiquer comment exactement. Sinon, j'espère que votre logiciel s'améliorera si vous décidez de le tester dans des conditions de problèmes de réseau en utilisant les méthodes suggérées.

Source: habr.com

Ajouter un commentaire