Hej alle sammen, mit navn er Sasha, og jeg leder backend-testning hos FunCorp. Ligesom mange andre har vi implementeret en serviceorienteret arkitektur. På den ene side forenkler det arbejdet, da hver service er lettere at teste individuelt, men på den anden side opstår der behov for at teste interaktionen mellem tjenester, som ofte foregår over nettet.
I denne artikel vil jeg fortælle om to værktøjer, som kan bruges til at teste grundlæggende scenarier, der beskriver applikationens funktion ved netværksproblemer.

Simulering af netværksproblemer
Normalt testes software på testservere med en god internetforbindelse. Under de barske forhold i produktionen kan alt være mindre glat, så det nogle gange er nødvendigt at teste programmer under dårlige forbindelser. I Linux kan værktøjet tc.
tc (forkortelse for Traffic Control) giver mulighed for at konfigurere transmissionen af netværkspakker i systemet. Dette værktøj har omfattende funktioner, som kan læses mere om . Her vil jeg kun se på nogle af dem: vi er interesseret i trafikstyring, og derfor bruger vi qdisc, og da vi skal simulere et ustabilt netværk, vil vi bruge classless qdisc .
Lad os starte en echo-server på serveren (jeg brugte ):
ncat -l 127.0.0.1 12345 -k -c 'xargs -n1 -i echo "Response: {}"'
For at vise alle tidsstempler detaljeret på hvert trin i klientens interaktion med serveren, har jeg skrevet et simpelt script i Python, som sender en forespørgsel Test til vores echo-server.
Kildekoden til klienten
#!/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
Lad os køre det og se på trafikken på grænsefladen lo og port 12345:
[user@host ~]# python client.py
[tid før forbindelse: 1578652979.44837]
[tid efter forbindelse, før afsendelse: 1578652979.44889]
[tid efter afsendelse, før modtagelse: 1578652979.44894]
[tid efter modtagelse, før lukning: 1578652979.45922]
[tid efter lukning: 1578652979.45928]
[total varighed: 0.01091]
Response: Test
Trafikdump
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: udvidet output undertrykt, brug -v eller -vv for fuld protokol dekodning
lytter på lo, link-type EN10MB (Ethernet), capture størrelse 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
Alt er standard: trevejs håndtryk, PSH/ACK og ACK som svar to gange - dette er udveksling af anmodning og svar mellem klient og server, og to gange FIN/ACK og ACK - afslutning af forbindelsen.
Forsinkelse af pakker
Lad os nu indstille en forsinkelse på 500 millisekunder:
tc qdisc add dev lo root netem delay 500ms
Vi starter klienten og ser, at scriptet nu kører i 2 sekunder:
[user@host ~]# ./client.py
[tid før forbindelse: 1578662612.71044]
[tid efter forbindelse, før sending: 1578662613.71059]
[tid efter sending, før modtagelse: 1578662613.71065]
[tid efter modtagelse, før lukning: 1578662614.72011]
[tid efter lukning: 1578662614.72019]
[total varighed: 2.00974]
Svar: Test
Hvad med trafikken? Lad os kigge:
Trafikdump
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
Det kan ses, at der opstod et forventet lag på en halv sekund i interaktionen mellem klienten og serveren. Det bliver langt mere interessant, hvordan systemet reagerer, hvis laget bliver større: kernen begynder at sende nogle TCP-pakker igen. Lad os ændre forsinkelsen til 1 sekund og se på trafikken (jeg vil ikke vise klientens output, der er forventede 4 sekunder i total varighed):
tc qdisc change dev lo root netem delay 1s
Trafikdump
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
Det er tydeligt, at klienten har sendt SYN-pakker to gange, mens serveren har sendt SYN/ACK to gange.
Udover konstantværdi kan der angives afvigelse, fordelingsfunktion og korrelation (med værdien for den foregående pakke) for forsinkelsen. Dette kan gøres som følger:
tc qdisc change dev lo root netem delay 500ms 400ms 50 distribution normal
Her har vi angivet en forsinkelse mellem 100 og 900 millisekunder, værdierne vil blive valgt i henhold til normalfordelingen og der vil være 50 procent korrelation med forsinkelsen for den foregående pakke.
Du har måske bemærket, at jeg i den første kommando brugte add, og derefter change. Betydningen af disse kommandoer er indlysende, så jeg vil blot tilføje, at der også findes del, som kan fjerne konfigurationen.
Pakkeforskydning
Lad os nu prøve at skabe pakkeforskydning. Som det fremgår af dokumentationen, kan dette gøres på hele tre måder: ved tilfældigt at tabe pakker med en vis sandsynlighed, ved at bruge en Markov kæde med 2, 3 eller 4 tilstande eller ved at anvende Elliott-Gilbert modellen. I artiklen vil jeg se på den første (den enkleste og mest oplagte) metode, mens du kan læse om de andre. .
Vi simulerer et tab på 50 % af pakkerne med en korrelation på 25 %:
tc qdisc add dev lo root netem loss 50% 25%
Desværre, tcpdump vil ikke kunne vise os tabet af pakkerne visuelt, vi må kun antage, at det virkelig virker. Og det kan vi bekræfte ved hjælp af den øgede og ustabile scriptkørselstid. client.py (kan køre øjeblikkeligt, eller det kan tage 20 sekunder), samt det øgede antal retransmitterede pakker:
[user@host ~]# netstat -s | grep retransmited; sleep 10; netstat -s | grep retransmited
17147 segmenter retransmitteret
17185 segmenter retransmitteret
Tilføjelse af støj i pakkerne
Ud over tab af pakker kan vi simulere deres beskadigelse: der vil optræde støj i en tilfældig position i pakken. Vi vil lave beskadigelse af pakker med 50 % sandsynlighed og uden korrelation:
tc qdisc change dev lo root netem corrupt 50%
Vi kører klientskriptet (der er ikke noget interessant, men det blev kørt i 2 sekunder), vi ser på trafikken:
Trafikdump
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: detaljeret output undertrykt, brug -v eller -vv for fuld protokolafkodning
lytter på lo, link-type EN10MB (Ethernet), capture-størrelse 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
Det er tydeligt, at nogle pakker er blevet sendt igen, og der er en pakke med beskadigede metadata: options [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]>. Men det vigtigste er, at alt til sidst fungerede korrekt – TCP klarede sin opgave.
Dublering af pakker
Hvad mere kan man gøre med netem? Например, сымитировать ситуацию, обратную потере пакетов, — дубликацию пакетов. Эта команда также принимает 2 аргумента: вероятность и корреляцию.
tc qdisc change dev lo root netem duplicate 50% 25%
Ændring af pakkeordnet
Man kan blande pakkerne, på to måder.
I den første del sendes nogle pakker straks, mens de øvrige sendes med en given forsinkelse. Et eksempel fra dokumentationen:
tc qdisc change dev lo root netem delay 10ms reorder 25% 50%
Med en sandsynlighed på 25% (og en korrelation på 50%) vil pakken blive sendt straks, mens de øvrige sendes med en forsinkelse på 10 millisekunder.
Den anden metode er, at hver N-te pakke sendes øjeblikkeligt med en given sandsynlighed (og korrelation), mens de øvrige sendes med en given forsinkelse. Et eksempel fra dokumentationen:
tc qdisc change dev lo root netem delay 10ms reorder 25% 50% gap 5
Hver femte pakke med 25% sandsynlighed vil blive sendt uden forsinkelse.
Ændring af båndbredde
Normalt sendes der til , men man kan også ændre båndbredde på interface ved hjælp af netem :
tc qdisc change dev lo root netem rate 56kbit
Denne kommando vil gøre localhost sådanne udflugter lige så pinefulde som at surfe på internettet via en dial-up modem. Udover at sætte bitrate kan man også emulere en kanalprotokolmodel: angive overhead for en pakke, celle størrelse og overhead for en celle. For eksempel kan man simulere og bitrate på 56 kbit/s.:
tc qdisc change dev lo root netem rate 56kbit 0 48 5
Simulerer connection timeout
Endnu et vigtigt punkt i testplanen ved accept af software – timeouts. Dette er vigtigt, fordi i distribuerede systemer, hvis en af tjenesterne slukker, skal de andre rettidigt falde tilbage til andre eller returnere en fejl til kunden, de må under ingen omstændigheder bare hænge og vente på svar eller forbindelse.
Der er flere måder at gøre dette på: for eksempel at bruge en mock, der ikke svarer, eller tilslutte sig processen med en debugger, sætte en breakpoint det rigtige sted og stoppe procesens udførelse (det er nok den mest bizarre måde). Men en af de mest oplagte er at firewalle porte eller værter. Dette vil hjælpe os med .
Til demonstration vil vi firewall port 12345 og køre vores klient-script. Man kan firewall udgående pakker på denne port hos afsenderen eller indgående på modtageren. I mine eksempler vil indgående pakker blive firewall- og (vi bruger chain INPUT og option —dport). Disse pakker kan blive DROPPED, REJECTED eller REJECTED med TCP-flag RST, man kan også sende ICMP host unreachable (faktisk er standardadfærden icmp-port-unreachable, og der er også mulighed for at sende som svar icmp-net-unreachable, icmp-proto-unreachable, icmp-net-prohibited og icmp-host-prohibited).
DROP
Hvis der er en regel med DROP, vil pakkerne blot "forsvinde".
iptables -A INPUT -p tcp --dport 12345 -j DROP
Vi starter klienten og ser, at den hænger ved forbindelse til serveren. Vi ser på trafikken:
Trafikdump
[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
Det er tydeligt, at klienten sender SYN-pakker med en eksponentielt stigende timeout. Her har vi fundet en lille fejl i klienten: metoden settimeout(), skal bruges for at begrænse tiden, hvor klienten vil forsøge at oprette forbindelse til serveren.
Vi fjerner straks reglen:
iptables -D INPUT -p tcp --dport 12345 -j DROPMan kan fjerne alle regler på én gang:
iptables -F
Hvis du bruger Docker, og du skal firewall hele trafikken til containeren, kan det gøres som følger:
iptables -I DOCKER-USER -p tcp -d CONTAINER_IP -j DROP
REJECT
Nu tilføjer vi en tilsvarende regel, men med REJECT:
iptables -A INPUT -p tcp --dport 12345 -j REJECT
Klienten afsluttes efter et sekund med en fejl [Errno 111] Connection refused. Vi ser på ICMP-trafikken:
[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
Det er tydeligt, at klienten har modtaget port unreachable to gange, og efter dette afsluttede den med en fejl.
REJECT with tcp-reset
Lad os prøve at tilføje optionen —reject-with tcp-reset:
iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with tcp-reset
I dette tilfælde springer klienten straks ud med en fejl, fordi den på den første forespørgsel fik en RST-pakke:
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbos output undertrykt, brug -v eller -vv for fuld protokol dekodning
lytter på lo, link-type EN10MB (Ethernet), fangststørrelse 262144 byte
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 med icmp-host-unreachable
Lad os prøve endnu en mulighed for at bruge REJECT:
iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with icmp-host-unreachable
Klienten afsluttes efter et sekund med en fejl [Errno 113] Ingen rute til værten, i ICMP-trafikken ser vi ICMP-vært 127.0.0.1 utilgængelig.
Du kan også prøve de andre REJECT-parametre, mens jeg stopper ved disse 🙂
Simulerer request timeout
En anden situation — er når klienten kunne forbinde til serveren, men ikke kan sende en forespørgsel til den. Hvordan filtrerer man pakker, så filtreringen begynder som om den ikke straks? Hvis man ser på trafikken mellem klienten og serveren, kan man bemærke, at ved oprettelse af forbindelsen bruges kun flags SYN og ACK, mens ved dataudveksling i den sidste pakke forespørgsel vil der være flag PSH. Det sættes automatisk for at undgå buffering. Man kan bruge denne information til at oprette et filter: det vil tillade alle pakker undtagen dem, der indeholder flag PSH. På den måde vil forbindelsen blive oprettet, men klienten vil ikke kunne sende data til serveren.
DROP
For DROP vil kommandoen se således ud:
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j DROP
Starter klienten og ser på trafikken:
Trafikdump
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: verbos output undertrykt, brug -v eller -vv for fuld protokol dekodning
lytter på lo, link-type EN10MB (Ethernet), fangststørrelse 262144 byte
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
Vi ser, at forbindelsen er etableret, og klienten kan ikke sende data til serveren.
REJECT
I dette tilfælde vil adfærden forblive den samme: klienten vil ikke kunne sende en anmodning, men vil modtage ICMP 127.0.0.1 tcp port 12345 utilgængelig og øge tiden mellem genforsøg af anmodningen eksponentielt. Kommandoen ser således ud:
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j REJECT
REJECT with tcp-reset
Kommandoen ser sådan ud:
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j REJECT --reject-with tcp-reset
Vi ved allerede, at ved brug af —reject-with tcp-reset vil klienten modtage et RST-pakke som svar, så vi kan forudsige adfærden: modtagelse af et RST-pakke ved en etableret forbindelse betyder en uventet lukning af socket'en fra den anden side, hvilket betyder, at klienten skal modtage Connection reset by peer. Vi kører vores script og bekræfter dette. Og sådan vil trafikken se ud:
Trafikdump
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: detaljeret output undertrykt, brug -v eller -vv for fuld protokol dekodning
lytter på 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 med icmp-host-unreachable
Jeg tror, det allerede er klart for alle, hvordan kommandoen vil se ud 🙂 Klientens adfærd i dette tilfælde vil være lidt anderledes end med en simpel REJECT: klienten vil ikke øge timeout mellem forsøge på at genforsende pakken.
[user@host ~]# tcpdump -i lo -nn icmp
tcpdump: detaljeret output undertrykt, brug -v eller -vv for fuld protokol dekodning
lytter på 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 utilgængelig, length 65
10:29:56.349107 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 utilgængelig, length 65
10:29:56.549117 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 utilgængelig, length 65
10:29:56.750125 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 utilgængelig, length 65
10:29:56.951130 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 utilgængelig, length 65
10:29:57.152107 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 utilgængelig, length 65
10:29:57.353115 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 utilgængelig, length 65
Output
Det er ikke nødvendigt at skrive en mock til at teste interaktionen mellem servicen og en hængende klient eller server, nogle gange er det tilstrækkeligt at bruge de standardværktøjer, der findes i Linux.
De værktøjer, der er omtalt i artiklen, har endnu flere muligheder, end der er beskrevet, så du kan finde på dine egne måder at bruge dem på. Personligt synes jeg altid, at det, jeg har skrevet om, er tilstrækkeligt (faktisk endda mindre). Hvis du bruger disse eller lignende værktøjer til testning i din virksomhed, vil jeg gerne høre, hvordan. Hvis ikke, håber jeg, at din software bliver bedre, hvis du vælger at teste den under netværksproblemer med de foreslåede metoder.
Kilde: habr.com
