Simulace síťových problémů v Linuxu

Ahoj všichni, jmenuji se Sasha a vedu backend testování ve FunCorp. Stejně jako mnoho dalších jsme implementovali architekturu orientovanou na služby. Na jednu stranu to zjednodušuje práci, protože... Jednodušší je testovat každou službu zvlášť, ale na druhou stranu je potřeba otestovat vzájemnou interakci služeb, ke které často dochází po síti.

V tomto článku budu hovořit o dvou obslužných programech, které lze použít ke kontrole základních scénářů popisujících fungování aplikace v případě problémů se sítí.

Simulace síťových problémů v Linuxu

Simulace síťových problémů

Software se obvykle testuje na testovacích serverech s dobrým připojením k internetu. V drsných produkčních prostředích nemusí být věci tak plynulé, takže někdy potřebujete otestovat programy ve špatných podmínkách připojení. V Linuxu tento nástroj pomůže s úkolem simulovat takové podmínky tc.

tc(zkr. z řízení dopravy) umožňuje konfigurovat přenos síťových paketů v systému. Tento nástroj má skvělé schopnosti, můžete si o nich přečíst více zde. Zde uvedu jen některé z nich: zajímá nás plánování dopravy, pro které používáme qdisc, a protože potřebujeme emulovat nestabilní síť, použijeme beztřídní qdisc netem.

Spusťte na serveru echo server (použil jsem nmap-ncat):

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

Abych podrobně zobrazil všechna časová razítka v každém kroku interakce mezi klientem a serverem, napsal jsem jednoduchý skript Python, který odešle požadavek test na náš echo server.

Zdrojový kód klienta

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

Pojďme to spustit a podívat se na provoz na rozhraní lo a 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

Dopravní skládka

[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

Vše je standardní: třícestný handshake, PSH/ACK a ACK jako odpověď dvakrát - to je výměna požadavku a odpovědi mezi klientem a serverem a FIN/ACK a ACK dvakrát - dokončení spojení.

Zpoždění paketů

Nyní nastavíme zpoždění na 500 milisekund:

tc qdisc add dev lo root netem delay 500ms

Spustíme klienta a uvidíme, že skript nyní běží na 2 sekundy:

[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

Co je v provozu? Podívejme se:

Dopravní skládka

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

Můžete vidět, že se v interakci mezi klientem a serverem objevilo očekávané zpoždění půl sekundy. Systém se chová mnohem zajímavěji, pokud je zpoždění větší: jádro začne znovu odesílat některé TCP pakety. Změňme zpoždění na 1 sekundu a podívejme se na provoz (nebudu ukazovat výstup klienta, v celkovém trvání jsou očekávané 4 sekundy):

tc qdisc change dev lo root netem delay 1s

Dopravní skládka

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

Je vidět, že klient poslal SYN paket dvakrát a server poslal SYN/ACK dvakrát.

Kromě konstantní hodnoty lze zpoždění nastavit na odchylku, distribuční funkci a korelaci (s hodnotou pro předchozí paket). To se provádí následovně:

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

Zde jsme nastavili zpoždění mezi 100 a 900 milisekundami, hodnoty budou vybrány podle normálního rozdělení a bude existovat 50% korelace s hodnotou zpoždění pro předchozí paket.

Možná jste si všimli, že v prvním příkazu, který jsem použil přidata pak přeměna. Význam těchto příkazů je zřejmý, takže jen dodám, že je toho víc del, který lze použít k odstranění konfigurace.

Ztráta paketů

Zkusme nyní provést ztrátu paketů. Jak je vidět z dokumentace, lze to provést třemi způsoby: náhodnou ztrátou paketů s určitou pravděpodobností, použitím Markovova řetězce 2, 3 nebo 4 stavů pro výpočet ztráty paketů nebo použitím Elliott-Gilbertova modelu. V článku se budu zabývat první (nejjednodušší a nejzřejmější) metodou a o dalších si můžete přečíst zde.

Udělejme ztrátu 50 % paketů s korelací 25 %:

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

Bohužel, tcpdump nebude moci jasně ukázat ztrátu paketů, budeme pouze předpokládat, že to opravdu funguje. A zvýšená a nestabilní doba běhu skriptu nám to pomůže ověřit. client.py (lze dokončit okamžitě nebo možná za 20 sekund), stejně jako zvýšený počet znovu odeslaných paketů:

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

Přidání šumu do paketů

Kromě ztráty paketů můžete simulovat poškození paketů: na náhodné pozici paketu se objeví šum. Udělejme poškození paketů s 50% pravděpodobností a bez korelace:

tc qdisc change dev lo root netem corrupt 50%

Spustíme klientský skript (nic zajímavého, ale dokončení trvalo 2 sekundy), podívejte se na provoz:

Dopravní skládka

[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

Je vidět, že některé pakety byly odeslány opakovaně a existuje jeden paket s poškozenými metadaty: možnosti [nop,unknown-65 0x0a3dcf62eb3d,[špatná volba]>. Ale hlavní je, že nakonec vše fungovalo správně - TCP si se svým úkolem poradil.

Duplikace paketů

Co jiného můžete dělat netem? Například simulujte obrácenou situaci ztráty paketů – duplikaci paketů. Tento příkaz také přebírá 2 argumenty: pravděpodobnost a korelaci.

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

Změna pořadí balíčků

Sáčky můžete míchat dvěma způsoby.

V první jsou některé pakety odeslány okamžitě, zbytek se zadaným zpožděním. Příklad z dokumentace:

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

S pravděpodobností 25 % (a korelací 50 %) bude paket odeslán okamžitě, zbytek bude odeslán se zpožděním 10 milisekund.

Druhá metoda je, když je každý N-tý paket odeslán okamžitě s danou pravděpodobností (a korelací) a zbytek s daným zpožděním. Příklad z dokumentace:

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

Každý pátý balík má 25% šanci na bezodkladné odeslání.

Změna šířky pásma

Obvykle všude, kam odkazují TBF, ale s pomocí netem Můžete také změnit šířku pásma rozhraní:

tc qdisc change dev lo root netem rate 56kbit

Tento tým bude podnikat výlety po okolí localhost stejně bolestivé jako surfování na internetu přes vytáčený modem. Kromě nastavení datového toku můžete také emulovat model protokolu spojové vrstvy: nastavit režii pro paket, velikost buňky a režii pro buňku. To lze například simulovat bankomat a bitrate 56 kbit/s:

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

Simulace časového limitu připojení

Dalším důležitým bodem v plánu testování při přijímání softwaru jsou časové limity. To je důležité, protože v distribuovaných systémech, když je jedna ze služeb deaktivována, ostatní se musí včas vrátit k ostatním nebo vrátit chybu klientovi a v žádném případě by neměly jednoduše zavěsit a čekat na odpověď nebo připojení. k založení.

Existuje několik způsobů, jak to udělat: například použít mock, který nereaguje, nebo se připojit k procesu pomocí debuggeru, umístit bod přerušení na správné místo a zastavit proces (toto je pravděpodobně nejzvrácenější způsob). Ale jeden z nejzřejmějších je porty firewallu nebo hostitelé. Pomůže nám s tím iptables.

Pro demonstraci použijeme port firewallu 12345 a spustíme klientský skript. Můžete firewall odchozí pakety na tento port u odesílatele nebo příchozí pakety u příjemce. V mých příkladech budou příchozí pakety chráněny firewallem (používáme chain INPUT a volbu --dport). Takové pakety mohou být DROP, REJECT nebo REJECT s příznakem TCP RST nebo s nedosažitelným hostitelem ICMP (ve skutečnosti je výchozí chování icmp-port-nedostupný, a je zde i možnost zaslat odpověď icmp-net-nedostupný, icmp-proto-nedostupný, icmp-net-zakázáno и icmp-host-zakázáno).

DROP

Pokud existuje pravidlo s DROP, pakety jednoduše „zmizí“.

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

Spustíme klienta a vidíme, že zamrzne ve fázi připojování k serveru. Podívejme se na provoz:
Dopravní skládka

[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

Je vidět, že klient posílá SYN pakety s exponenciálně se zvyšujícím časovým limitem. Takže jsme našli malou chybu v klientovi: musíte použít metodu settimeout()omezit dobu, po kterou se bude klient pokoušet připojit k serveru.

Okamžitě odstraňujeme pravidlo:

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

Všechna pravidla můžete smazat najednou:

iptables -F

Pokud používáte Docker a potřebujete firewall pro veškerý provoz směřující do kontejneru, můžete to udělat následovně:

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

ODMÍTNOUT

Nyní přidáme podobné pravidlo, ale s REJECT:

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

Klient po sekundě skončí s chybou [Errno 111] Připojení odmítnuto. Podívejme se na provoz 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

Je vidět, že klient dostal dvakrát port nedosažitelný a pak skončil s chybou.

REJECT s tcp-reset

Zkusme přidat možnost --reject-with tcp-reset:

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

V tomto případě klient okamžitě skončí s chybou, protože první požadavek obdržel paket 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

REJECT s icmp-host-unreachable

Zkusme jinou možnost použití REJECT:

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

Klient po sekundě skončí s chybou [Errno 113] Žádná cesta k hostiteli, vidíme v provozu ICMP Hostitel ICMP 127.0.0.1 je nedostupný.

Můžete také vyzkoušet ostatní parametry REJECT a na ty se zaměřím :)

Simulace časového limitu požadavku

Jiná situace je, když se klient mohl připojit k serveru, ale nemůže na něj odeslat požadavek. Jak filtrovat pakety, aby se filtrování nespustilo hned? Pokud se podíváte na provoz jakékoli komunikace mezi klientem a serverem, všimnete si, že při navazování spojení se používají pouze příznaky SYN a ACK, ale při výměně dat bude poslední paket požadavku obsahovat příznak PSH. Instaluje se automaticky, aby se zabránilo ukládání do vyrovnávací paměti. Tyto informace můžete použít k vytvoření filtru: povolí všechny pakety kromě těch, které obsahují příznak PSH. Spojení se tedy naváže, ale klient nebude moci odesílat data na server.

DROP

Pro DROP by příkaz vypadal takto:

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

Spusťte klienta a sledujte provoz:

Dopravní skládka

[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

Vidíme, že spojení je navázáno a klient nemůže odeslat data na server.

ODMÍTNOUT

V tomto případě bude chování stejné: klient nebude moci požadavek odeslat, ale bude jej přijímat ICMP 127.0.0.1 tcp port 12345 nedostupný a exponenciálně prodlužovat dobu mezi opakovaným odesláním požadavků. Příkaz vypadá takto:

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

REJECT s tcp-reset

Příkaz vypadá takto:

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

To už poznáme při používání --reject-with tcp-reset klient obdrží jako odpověď paket RST, takže chování lze předvídat: přijetí paketu RST během navazování spojení znamená, že soket je neočekávaně uzavřen na druhé straně, což znamená, že klient by měl přijmout Reset připojení peerem. Spusťte náš skript a přesvědčte se o tom. A takto bude vypadat provoz:

Dopravní skládka

[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

REJECT s icmp-host-unreachable

Myslím, že už je všem jasné, jak bude příkaz vypadat :) Chování klienta se v tomto případě bude mírně lišit od toho s jednoduchým ODMÍTNUTÍM: klient nezvýší časový limit mezi pokusy o opětovné odeslání paketu.

[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

Výkon

K otestování interakce služby se zavěšeným klientem nebo serverem není nutné psát mock, někdy stačí použít standardní nástroje, které najdete v Linuxu.

Pomůcky popsané v článku mají ještě více možností, než byly popsány, takže si můžete vymyslet nějaké vlastní možnosti jejich použití. Osobně mám vždy dost toho, o čem jsem psal (vlastně i méně). Pokud tyto nebo podobné utility používáte při testování ve vaší firmě, napište prosím jak přesně. Pokud ne, pak doufám, že se váš software zlepší, pokud se jej rozhodnete otestovat v podmínkách síťových problémů pomocí navrhovaných metod.

Zdroj: www.habr.com

Přidat komentář