Simulando problemas de red en Linux

Hola a todos, mi nombre es Sasha, dirijo las pruebas de backend en FunCorp. Nosotros, como muchos otros, hemos implementado una arquitectura orientada a servicios. Por un lado, esto simplifica el trabajo, porque... Es más fácil probar cada servicio por separado, pero, por otro lado, existe la necesidad de probar la interacción de los servicios entre sí, lo que a menudo ocurre a través de la red.

En este artículo, hablaré de dos utilidades que se pueden utilizar para comprobar escenarios básicos que describen el funcionamiento de una aplicación en presencia de problemas de red.

Simulando problemas de red en Linux

Simulando problemas de red

Normalmente, el software se prueba en servidores de prueba con una buena conexión a Internet. En entornos de producción hostiles, las cosas pueden no ser tan sencillas, por lo que a veces es necesario probar programas en malas condiciones de conexión. En Linux, la utilidad ayudará con la tarea de simular tales condiciones. tc.

tc(abbr. del control de tráfico) le permite configurar la transmisión de paquetes de red en el sistema. Esta utilidad tiene grandes capacidades, puedes leer más sobre ellas. aquí. Aquí consideraré sólo algunos de ellos: estamos interesados ​​en la programación del tráfico, para lo cual utilizamos qdisco, y como necesitamos emular una red inestable, usaremos qdisc sin clases neto.

Iniciemos un servidor de eco en el servidor (yo usé nmap-ncat):

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

Para mostrar en detalle todas las marcas de tiempo en cada paso de la interacción entre el cliente y el servidor, escribí un script Python simple que envía una solicitud. Probar a nuestro servidor de eco.

Código fuente del cliente

#!/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

Iniciémoslo y observemos el tráfico en la interfaz. lo y puerto 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

Volcado de tráfico

[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

Todo es estándar: un protocolo de enlace de tres vías, PSH/ACK y ACK en respuesta dos veces (este es el intercambio de solicitud y respuesta entre el cliente y el servidor, y FIN/ACK y ACK dos veces) para completar la conexión.

Retraso del paquete

Ahora establezcamos el retraso en 500 milisegundos:

tc qdisc add dev lo root netem delay 500ms

Lanzamos el cliente y vemos que el script ahora se ejecuta durante 2 segundos:

[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é hay en el tráfico? Miremos:

Volcado de tráfico

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

Puedes ver que ha aparecido el desfase esperado de medio segundo en la interacción entre el cliente y el servidor. El sistema se comporta de manera mucho más interesante si el retraso es mayor: el núcleo comienza a reenviar algunos paquetes TCP. Cambiemos el retraso a 1 segundo y observemos el tráfico (no mostraré la salida del cliente, se esperan 4 segundos de duración total):

tc qdisc change dev lo root netem delay 1s

Volcado de tráfico

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

Se puede ver que el cliente envió un paquete SYN dos veces y el servidor envió un paquete SYN/ACK dos veces.

Además de un valor constante, el retraso se puede establecer en una desviación, una función de distribución y una correlación (con el valor del paquete anterior). Esto se hace de la siguiente manera:

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

Aquí hemos establecido el retraso entre 100 y 900 milisegundos, los valores se seleccionarán según una distribución normal y habrá una correlación del 50% con el valor de retraso del paquete anterior.

Quizás hayas notado que en el primer comando usé addy luego el cambio. El significado de estos comandos es obvio, así que simplemente agregaré que hay más de los, que se puede utilizar para eliminar la configuración.

Paquete perdido

Intentemos ahora hacer la pérdida de paquetes. Como se puede ver en la documentación, esto se puede hacer de tres maneras: perder paquetes aleatoriamente con cierta probabilidad, usar una cadena de Markov de 2, 3 o 4 estados para calcular la pérdida de paquetes o usar el modelo de Elliott-Gilbert. En el artículo consideraré el primer método (el más simple y obvio), y puedes leer sobre otros. aquí.

Hagamos la pérdida del 50% de los paquetes con una correlación del 25%:

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

Desafortunadamente, tcpdump no podrá mostrarnos claramente la pérdida de paquetes, solo asumiremos que realmente funciona. Y el mayor e inestable tiempo de ejecución del script nos ayudará a verificar esto. cliente.py (se puede completar instantáneamente, o tal vez en 20 segundos), así como una mayor cantidad de paquetes retransmitidos:

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

Agregar ruido a los paquetes

Además de la pérdida de paquetes, puede simular daños en los paquetes: aparecerá ruido en una posición aleatoria del paquete. Hagamos daños en los paquetes con un 50% de probabilidad y sin correlación:

tc qdisc change dev lo root netem corrupt 50%

Ejecutamos el script del cliente (no hay nada interesante allí, pero tardó 2 segundos en completarse), miramos el tráfico:

Volcado de tráfico

[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

Se puede ver que algunos paquetes se enviaron repetidamente y hay un paquete con metadatos rotos: opciones [nop,unknown-65 0x0a3dcf62eb3d,[opción incorrecta]>. Pero lo principal es que al final todo funcionó correctamente: TCP hizo frente a su tarea.

Duplicación de paquetes

¿Qué más puedes hacer con neto? Por ejemplo, simule la situación inversa de pérdida de paquetes: duplicación de paquetes. Este comando también toma 2 argumentos: probabilidad y correlación.

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

Cambiar el orden de los paquetes

Puedes mezclar las bolsas de dos maneras.

En el primero, algunos paquetes se envían inmediatamente y el resto con un retraso específico. Ejemplo de la documentación:

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

Con una probabilidad del 25% (y una correlación del 50%), el paquete se enviará inmediatamente, el resto se enviará con un retraso de 10 milisegundos.

El segundo método es cuando cada enésimo paquete se envía instantáneamente con una probabilidad (y correlación) determinada, y el resto con un retraso determinado. Ejemplo de la documentación:

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

Cada quinto paquete tiene un 25% de posibilidades de ser enviado sin demora.

Cambiar el ancho de banda

Generalmente en todos los lugares a los que se refieren TBF, pero con la ayuda neto También puedes cambiar el ancho de banda de la interfaz:

tc qdisc change dev lo root netem rate 56kbit

Este equipo hará caminatas alrededor localhost tan doloroso como navegar por Internet a través de un módem de acceso telefónico. Además de configurar la tasa de bits, también puede emular el modelo de protocolo de capa de enlace: establezca la sobrecarga del paquete, el tamaño de la celda y la sobrecarga de la celda. Por ejemplo, esto se puede simular ATM y velocidad de bits 56 kbit/seg:

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

Simulando el tiempo de espera de la conexión

Otro punto importante en el plan de pruebas a la hora de aceptar software son los tiempos de espera. Esto es importante porque en los sistemas distribuidos, cuando uno de los servicios está deshabilitado, los demás deben recurrir a los demás a tiempo o devolver un error al cliente, y en ningún caso deben simplemente colgarse, esperando una respuesta o una conexión. por establecerse.

Hay varias formas de hacer esto: por ejemplo, usar un simulacro que no responde o conectarse al proceso usando un depurador, colocar un punto de interrupción en el lugar correcto y detener el proceso (esta es probablemente la forma más pervertida). Pero uno de los más obvios es el firewall de puertos o hosts. Nos ayudará con esto. iptables.

Para demostración, cortaremos el puerto 12345 y ejecutaremos nuestro script de cliente. Puede bloquear los paquetes salientes a este puerto en el remitente o los paquetes entrantes en el receptor. En mis ejemplos, los paquetes entrantes estarán protegidos por firewall (usamos INPUT en cadena y la opción --dport). Dichos paquetes pueden ser DROP, REJECT o REJECT con el indicador TCP RST o con el host ICMP inalcanzable (de hecho, el comportamiento predeterminado es puerto-icmp-inalcanzable, y también existe la posibilidad de enviar una respuesta icmp-net-inalcanzable, icmp-proto-inalcanzable, icmp-net-prohibido и icmp-host-prohibido).

DROP

Si hay una regla con DROP, los paquetes simplemente "desaparecerán".

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

Lanzamos el cliente y vemos que se congela en la etapa de conexión al servidor. Miremos el tráfico:
Volcado de tráfico

[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

Se puede ver que el cliente envía paquetes SYN con un tiempo de espera que aumenta exponencialmente. Entonces encontramos un pequeño error en el cliente: necesitas usar el método settimeout ()para limitar el tiempo durante el cual el cliente intentará conectarse al servidor.

Inmediatamente eliminamos la regla:

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

Puede eliminar todas las reglas a la vez:

iptables -F

Si está utilizando Docker y necesita proteger todo el tráfico que va al contenedor, puede hacerlo de la siguiente manera:

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

RECHAZAR

Ahora agreguemos una regla similar, pero con REJECT:

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

El cliente sale después de un segundo con un error. [Errno 111] Conexión rechazada. Veamos el tráfico 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

Se puede ver que el cliente recibió dos veces. puerto inalcanzable y luego terminó con un error.

RECHAZAR con tcp-reset

Intentemos agregar la opción. --rechazar-con tcp-reset:

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

En este caso, el cliente sale inmediatamente con un error, porque la primera solicitud recibió un paquete 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

RECHAZAR con icmp-host-inalcanzable

Probemos otra opción para usar REJECT:

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

El cliente sale después de un segundo con un error. [Errno 113] No hay ruta al host, vemos en el tráfico ICMP Host ICMP 127.0.0.1 inalcanzable.

También puedes probar los otros parámetros REJECT, y me centraré en estos :)

Simulando el tiempo de espera de la solicitud

Otra situación es cuando el cliente pudo conectarse al servidor, pero no puede enviarle una solicitud. ¿Cómo filtrar paquetes para que el filtrado no comience inmediatamente? Si observa el tráfico de cualquier comunicación entre el cliente y el servidor, notará que al establecer una conexión, solo se utilizan los indicadores SYN y ACK, pero al intercambiar datos, el último paquete de solicitud contendrá el indicador PSH. Se instala automáticamente para evitar el almacenamiento en búfer. Puede utilizar esta información para crear un filtro: permitirá todos los paquetes excepto aquellos que contengan la bandera PSH. Así, se establecerá la conexión, pero el cliente no podrá enviar datos al servidor.

DROP

Para DROP, el comando se vería así:

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

Inicie el cliente y observe el tráfico:

Volcado de tráfico

[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

Vemos que la conexión está establecida y el cliente no puede enviar datos al servidor.

RECHAZAR

En este caso el comportamiento será el mismo: el cliente no podrá enviar la solicitud, pero recibirá ICMP 127.0.0.1 puerto tcp 12345 inalcanzable y aumentar exponencialmente el tiempo entre reenvíos de solicitudes. El comando se ve así:

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

RECHAZAR con tcp-reset

El comando se ve así:

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

Ya sabemos que al usar --rechazar-con tcp-reset el cliente recibirá un paquete RST en respuesta, por lo que se puede predecir el comportamiento: recibir un paquete RST mientras se establece la conexión significa que el socket se cierra inesperadamente en el otro lado, lo que significa que el cliente debería recibir Restablecimiento de la conexión por igual. Ejecutemos nuestro script y asegurémonos de esto. Y así es como se verá el tráfico:

Volcado de tráfico

[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

RECHAZAR con icmp-host-inalcanzable

Creo que ya es obvio para todos cómo se verá el comando :) El comportamiento del cliente en este caso será ligeramente diferente al de un simple RECHAZO: el cliente no aumentará el tiempo de espera entre intentos de reenviar el paquete.

[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

conclusión

No es necesario escribir un simulacro para probar la interacción de un servicio con un cliente o servidor colgado; a veces es suficiente usar utilidades estándar que se encuentran en Linux.

Las utilidades analizadas en el artículo tienen incluso más capacidades que las descritas, por lo que puede crear algunas de sus propias opciones para usarlas. Personalmente, siempre tengo suficiente de lo que escribí (de hecho, incluso menos). Si utiliza estas u otras utilidades similares en las pruebas de su empresa, escriba cómo exactamente. De lo contrario, espero que su software mejore si decide probarlo en condiciones de problemas de red utilizando los métodos sugeridos.

Fuente: habr.com

Añadir un comentario