Hallo allemaal, mijn naam is Sasha, ik leid de backend testing bij FunCorp. Wij hebben, net als velen, een service-georiënteerde architectuur geïmplementeerd. Enerzijds vergemakkelijkt dat het werk omdat elke service eenvoudiger afzonderlijk te testen is, maar anderzijds ontstaat er de behoefte om de interactie tussen de services te testen, die vaak over het netwerk plaatsvindt.
In dit artikel zal ik twee hulpprogramma's bespreken waarmee je basisscenario's kunt controleren die de werking van de applicatie beschrijven bij netwerkproblemen.

Netwerkproblemen simuleren
Gewoonlijk wordt software getest op testservers met een goede internetverbinding. In de barre omstandigheden van productie kan het echter minder soepel verlopen, daarom moet je af en toe programma's testen onder omstandigheden van een slechte verbinding. In Linux helpt het hulpprogramma tc.
tc (afkorting van Traffic Control) stelt je in staat om de overdracht van netwerkpakketten in het systeem te configureren. Dit hulpprogramma heeft veel mogelijkheden, waarover je meer kunt lezen . Hier zal ik slechts enkele ervan bespreken: we zijn geïnteresseerd in het plannen van verkeer, waarvoor we gebruiken qdisc, en omdat we een onbetrouwbaar netwerk willen emuleren, zullen we classless qdisc gebruiken .
Laten we een echo-server op de server starten (ik heb hiervoor gebruikt ):
ncat -l 127.0.0.1 12345 -k -c 'xargs -n1 -i echo "Response: {}"'
Om gedetailleerde timestamp-informatie te geven over elke stap in de interactie tussen de client en de server, heb ik een eenvoudig script in Python geschreven dat een verzoek verzendt Test naar onze echo-server.
De broncode van de 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
Laten we het uitvoeren en kijken naar het verkeer op de interface lo en poort 12345:
[user@host ~]# python client.py
[tijd voor verbinding: 1578652979.44837]
[tijd na verbinding, voor verzending: 1578652979.44889]
[tijd na verzending, voor ontvangst: 1578652979.44894]
[tijd na ontvangst, voor sluiten: 1578652979.45922]
[tijd na sluiten: 1578652979.45928]
[totaal duur: 0.01091]
Response: Test
Traffic dump
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: uitgebreide uitvoer onderdrukt, gebruik -v of -vv voor volledige protocolontcijfering
luisterend op lo, linktype EN10MB (Ethernet), captura-grootte 262144 bytes
10:42:59.448601 IP 127.0.0.1.54054 > 127.0.0.1.12345: Vlaggen [S], seq 3383332866, win 43690, opties [mss 65495,sackOK,TS val 606325685 ecr 0,nop,wscale 7], lengte 0
10:42:59.448612 IP 127.0.0.1.12345 > 127.0.0.1.54054: Vlaggen [S.], seq 2584700178, ack 3383332867, win 43690, opties [mss 65495,sackOK,TS val 606325685 ecr 606325685,nop,wscale 7], lengte 0
10:42:59.448622 IP 127.0.0.1.54054 > 127.0.0.1.12345: Vlaggen [.], ack 1, win 342, opties [nop,nop,TS val 606325685 ecr 606325685], lengte 0
10:42:59.448923 IP 127.0.0.1.54054 > 127.0.0.1.12345: Vlaggen [P.], seq 1:6, ack 1, win 342, opties [nop,nop,TS val 606325685 ecr 606325685], lengte 5
10:42:59.448930 IP 127.0.0.1.12345 > 127.0.0.1.54054: Vlaggen [.], ack 6, win 342, opties [nop,nop,TS val 606325685 ecr 606325685], lengte 0
10:42:59.459118 IP 127.0.0.1.12345 > 127.0.0.1.54054: Vlaggen [P.], seq 1:15, ack 6, win 342, opties [nop,nop,TS val 606325696 ecr 606325685], lengte 14
10:42:59.459213 IP 127.0.0.1.54054 > 127.0.0.1.12345: Vlaggen [.], ack 15, win 342, opties [nop,nop,TS val 606325696 ecr 606325696], lengte 0
10:42:59.459268 IP 127.0.0.1.54054 > 127.0.0.1.12345: Vlaggen [F.], seq 6, ack 15, win 342, opties [nop,nop,TS val 606325696 ecr 606325696], lengte 0
10:42:59.460184 IP 127.0.0.1.12345 > 127.0.0.1.54054: Vlaggen [F.], seq 15, ack 7, win 342, opties [nop,nop,TS val 606325697 ecr 606325696], lengte 0
10:42:59.460196 IP 127.0.0.1.54054 > 127.0.0.1.12345: Vlaggen [.], ack 16, win 342, opties [nop,nop,TS val 606325697 ecr 606325697], lengte 0
Alles zoals gewoonlijk: driefasige handdruk, PSH/ACK en ACK in reactie twee keer — dit is de uitwisseling van verzoek en antwoord tussen de client en de server, en twee keer FIN/ACK en ACK — afsluiting van de verbinding.
Vertraging van pakketten
Laten we nu een vertraging van 500 milliseconden instellen:
tc qdisc add dev lo root netem delay 500ms
We starten de client en zien dat het script nu 2 seconden duurt:
[user@host ~]# ./client.py
[tijd vóór verbinding: 1578662612.71044]
[tijd na verbinding, vóór verzending: 1578662613.71059]
[tijd na verzending, vóór ontvangst: 1578662613.71065]
[tijd na ontvangst, vóór sluiting: 1578662614.72011]
[tijd na sluiting: 1578662614.72019]
[totaalduur: 2.00974]
Antwoord: Test
Wat zien we in het verkeer? Laten we kijken:
Traffic dump
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
Je kunt zien dat er een verwachte lag van een halve seconde is in de interactie tussen de client en de server. Het wordt veel interessanter als de lag groter is: de kernel begint sommige TCP-pakketten opnieuw te verzenden. Laten we de vertraging op 1 seconde instellen en het verkeer bekijken (ik zal de uitvoer van de client niet tonen, daar zijn de verwachte 4 seconden in totale duur):
tc qdisc change dev lo root netem delay 1s
Traffic dump
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
Het is duidelijk dat de client twee keer een SYN-pakket heeft verzonden en de server heeft twee keer een SYN/ACK verzonden.
Naast de constante waarde kan voor de vertraging ook een afwijking, verdelingsfunctie en correlatie (met de waarde van het vorige pakket) worden opgegeven. Dit gebeurt als volgt:
tc qdisc change dev lo root netem delay 500ms 400ms 50 distribution normal
Hier hebben we een vertraging ingesteld van 100 tot 900 milliseconden, waarbij de waarden worden gekozen volgens een normale verdeling en er 50 procent correlatie is met de vertraging van het vorige pakket.
U heeft misschien opgemerkt dat ik in het eerste commando heb gebruikt add, en vervolgens change. De betekenis van deze commando's is duidelijk, dus ik voeg alleen toe dat er nog een del, waarmee je de configuratie kunt verwijderen.
Pakketverlies
Laten we nu proberen pakketverlies te simuleren. Zoals uit de documentatie blijkt, kan dit op maar liefst drie manieren worden gedaan: pakketten willekeurig verliezen met een bepaalde waarschijnlijkheid, een Markov-keten van 2, 3 of 4 toestanden gebruiken voor het berekenen van het pakketverlies of een Elliot-Gilbert-model gebruiken. In dit artikel behandel ik de eerste (de eenvoudigste en meest voor de hand liggende) manier, maar over de andere methoden kunt u meer lezen. .
We maken 50% pakketverlies met een correlatie van 25%:
tc qdisc add dev lo root netem loss 50% 25%
Helaas, tcpdump kan ons niet duidelijk laten zien wat het pakketverlies is; we moeten aannemen dat het echt werkt. Dit kan worden bevestigd door de toegenomen en onregelmatige scriptwerktijd, Hierin komt de clientcode. (dat kan onmiddellijk uitvoeren, maar kan ook 20 seconden duren), evenals het toegenomen aantal retransmitted-pakketten:
[user@host ~]# netstat -s | grep retransmited; sleep 10; netstat -s | grep retransmited
17147 segmenten opnieuw verzonden
17185 segmenten opnieuw verzonden
Geluid toevoegen aan pakketten
Naast pakketverlies kunnen we ook hun beschadiging simuleren: er verschijnt geluid op een willekeurige positie van het pakket. We maken pakketten met een beschadiging met 50% kans en zonder correlatie:
tc qdisc change dev lo root netem corrupt 50%
We starten het klantscript (er is niets bijzonders aan, maar het duurde 2 seconden), laten we het verkeer bekijken:
Traffic dump
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: gedetailleerde uitvoer onderdrukt, gebruik -v of -vv voor volledige protocolontleding
luistert op lo, link-type EN10MB (Ethernet), capture size 262144 bytes
10:20:54.812434 IP 127.0.0.1.43666 > 127.0.0.1.12345: Vlaggen [S], seq 2023663770, win 43690, opties [mss 65495,sackOK,TS val 1037001049 ecr 0,nop,wscale 7], lengte 0
10:20:54.812449 IP 127.0.0.1.12345 > 127.0.0.1.43666: Vlaggen [S.], seq 2104268044, ack 2023663771, win 43690, opties [mss 65495,sackOK,TS val 1037001049 ecr 1037001049,nop,wscale 7], lengte 0
10:20:54.812458 IP 127.0.0.1.43666 > 127.0.0.1.12345: Vlaggen [.], ack 1, win 342, opties [nop,nop,TS val 1037001049 ecr 1037001049], lengte 0
10:20:54.812509 IP 127.0.0.1.43666 > 127.0.0.1.12345: Vlaggen [P.], seq 1:6, ack 1, win 342, opties [nop,nop,TS val 1037001049 ecr 1037001049], lengte 5
10:20:55.013093 IP 127.0.0.1.43666 > 127.0.0.1.12345: Vlaggen [P.], seq 1:6, ack 1, win 342, opties [nop,nop,TS val 1037001250 ecr 1037001049], lengte 5
10:20:55.013122 IP 127.0.0.1.12345 > 127.0.0.1.43666: Vlaggen [.], ack 6, win 342, opties [nop,nop,TS val 1037001250 ecr 1037001250], lengte 0
10:20:55.014681 IP 127.0.0.1.12345 > 127.0.0.1.43666: Vlaggen [P.], seq 1:15, ack 6, win 342, opties [nop,nop,TS val 1037001251 ecr 1037001250], lengte 14
10:20:55.014745 IP 127.0.0.1.43666 > 127.0.0.1.12345: Vlaggen [.], ack 15, win 340, opties [nop,nop,TS val 1037001251 ecr 1037001251], lengte 0
10:20:55.014823 IP 127.0.0.1.43666 > 127.0.0.1.12345: Vlaggen [F.], seq 2023663776, ack 2104268059, win 342, opties [nop,nop,TS val 1037001251 ecr 1037001251], lengte 0
10:20:55.214088 IP 127.0.0.1.12345 > 127.0.0.1.43666: Vlaggen [P.], seq 1:15, ack 6, win 342, opties [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]
10:20:55.416087 IP 127.0.0.1.43666 > 127.0.0.1.12345: Vlaggen [F.], seq 6, ack 15, win 342, opties [nop,nop,TS val 1037001653 ecr 1037001251], lengte 0
10:20:55.416804 IP 127.0.0.1.12345 > 127.0.0.1.43666: Vlaggen [F.], seq 15, ack 7, win 342, opties [nop,nop,TS val 1037001653 ecr 1037001653], lengte 0
10:20:55.416818 IP 127.0.0.1.43666 > 127.0.0.1.12345: Vlaggen [.], ack 16, win 343, opties [nop,nop,TS val 1037001653 ecr 1037001653], lengte 0
10:20:56.147086 IP 127.0.0.1.12345 > 127.0.0.1.43666: Vlaggen [F.], seq 15, ack 7, win 342, opties [nop,nop,TS val 1037002384 ecr 1037001653], lengte 0
10:20:56.147101 IP 127.0.0.1.43666 > 127.0.0.1.12345: Vlaggen [.], ack 16, win 342, opties [nop,nop,TS val 1037002384 ecr 1037001653], lengte 0
Het is duidelijk dat sommige pakketten opnieuw zijn verzonden en dat er één pakket is met beschadigde metadata: opties [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]>. Maar het belangrijkste is dat alles uiteindelijk correct heeft gewerkt – TCP heeft zijn taak volbracht.
Duplicatie van pakketten
Wat kun je nog meer doen met netem? Например, сымитировать ситуацию, обратную потере пакетов, — дубликацию пакетов. Эта команда также принимает 2 аргумента: вероятность и корреляцию.
tc qdisc change dev lo root netem duplicate 50% 25%
Wijziging van de volgorde van pakketten
Je kunt pakketten schudden op twee manieren.
In de eerste wordt een deel van de pakketten onmiddellijk verzonden, de rest met een bepaalde vertraging. Voorbeeld uit de documentatie:
tc qdisc change dev lo root netem delay 10ms reorder 25% 50%
Met een waarschijnlijkheid van 25% (en correlatie van 50%) wordt het pakket onmiddellijk verzonden; de overige pakketten worden met een vertraging van 10 milliseconden verzonden.
De tweede manier is wanneer elke N-de pakket onmiddellijk wordt verzonden met een bepaalde waarschijnlijkheid (en correlatie), terwijl de anderen met een bepaalde vertraging worden verzonden. Voorbeeld uit de documentatie:
tc qdisc change dev lo root netem delay 10ms reorder 25% 50% gap 5
Elke vijfde pakket met een waarschijnlijkheid van 25% wordt zonder vertraging verzonden.
Wijziging van de bandbreedte
Normaal gesproken wordt er overal naar verwezen met , maar met behulp van netem kan je ook de bandbreedte van de interface wijzigen:
tc qdisc change dev lo root netem rate 56kbit
Dit commando maakt de verbindingen zo localhost net zo pijnlijk als surfen op internet via een dial-up modem. Naast het instellen van de bitrate, kan je ook het model van het datalink-protocol emuleren: overhead voor het pakket, celgrootte en celoverhead instellen. Bijvoorbeeld, zo kan je imiteren en een bitrate van 56 kbit/s.:
tc qdisc change dev lo root netem rate 56kbit 0 48 5
Imiteer connection timeout
Een ander belangrijk punt in het testplan bij de acceptatie van software zijn time-outs. Dit is belangrijk omdat in gedistribueerde systemen, bij het uitschakelen van één van de diensten, de anderen tijdig moeten terugvallen op andere of een fout naar de client moeten retourneren, zonder dat ze simpelweg moeten vastlopen in afwachting van een antwoord of het tot stand brengen van een verbinding.
Er zijn verschillende manieren om dit te doen: bijvoorbeeld een mock gebruiken die niets antwoordt, of een proces koppelen met behulp van een debugger, een breakpoint op de juiste plaats zetten en de uitvoering van het proces stoppen (dit is waarschijnlijk de meest perverse manier). Maar een van de meest voor de hand liggende manieren is om poorten of hosts te firewallen. Hiermee kan ons helpen .
Om een demonstratie te geven, zullen we poort 12345 firewallen en onze clientscript uitvoeren. We kunnen uitgaande pakketten op deze poort bij de zender of inkomende pakketten bij de ontvanger firewallen. In mijn voorbeelden zullen we inkomende pakketten firewallen (we gebruiken chain INPUT en de optie —dport). Deze pakketten kunnen worden gedropt, afgewezen of afgewezen met een TCP-vlag RST; we kunnen ook een ICMP host unreachable sturen (feitelijk is de standaard gedrag icmp-port-unreachable, en we hebben ook de mogelijkheid om te antwoorden met icmp-net-unreachable, icmp-proto-unreachable, icmp-net-prohibited en icmp-host-prohibited).
DROP
Als er een regel met DROP aanwezig is, zullen de pakketten gewoon "verdwijnen".
iptables -A INPUT -p tcp --dport 12345 -j DROP
We starten de client en zien dat deze vastloopt tijdens het verbinden met de server. Laten we het verkeer bekijken:
Traffic dump
[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
Het is zichtbaar dat de client SYN-pakketten verzendt met een exponentieel toenemende timeout. Hier hebben we een klein bugje in de client gevonden: we moeten de methode settimeout(), gebruiken om de tijd te beperken waarbinnen de client zal proberen verbinding te maken met de server.
Laten we de regel onmiddellijk verwijderen:
iptables -D INPUT -p tcp --dport 12345 -j DROPWe kunnen ook meteen alle regels verwijderen:
iptables -F
Als je Docker gebruikt en al het verkeer naar de container wilt firewallen, dan kan dat als volgt:
iptables -I DOCKER-USER -p tcp -d CONTAINER_IP -j DROP
REJECT
Laten we een soortgelijke regel toevoegen, maar met REJECT:
iptables -A INPUT -p tcp --dport 12345 -j REJECT
De client stopt na een seconde met de fout [Errno 111] Connection refused. Laten we het ICMP-verkeer bekijken:
[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
Het is zichtbaar dat de client twee keer ontving port unreachable en daarna met een fout stopte.
REJECT with tcp-reset
Laten we proberen de optie toe te voegen —reject-with tcp-reset:
iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with tcp-reset
In dit geval verlaat de client onmiddellijk met een fout, omdat hij bij het eerste verzoek een RST-pakket ontving:
[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 met icmp-host-onbereikbaar
Laten we nog een andere variant van REJECT proberen:
iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with icmp-host-onbereikbaar
De client stopt na een seconde met de fout [Errno 113] Geen route naar de host, in het ICMP-verkeer zien we ICMP-host 127.0.0.1 onbereikbaar.
Je kunt ook de andere parameters van REJECT proberen, maar ik blijf bij deze 🙂
We simuleren een request timeout.
Een andere situatie is wanneer de client verbinding kan maken met de server, maar geen verzoek kan verzenden. Hoe filter je pakketten zodat de filtering niet meteen begint? Als je kijkt naar het verkeer tussen de client en de server, zie je dat alleen de flags SYN en ACK worden gebruikt bij het tot stand brengen van de verbinding, maar in het laatste verzoekpakket zal de flag PSH aanwezig zijn. Deze wordt automatisch ingesteld om buffering te voorkomen. Je kunt deze informatie gebruiken om een filter te maken: het zal alle pakketten toestaan, behalve die met de PSH-flag. Op deze manier wordt de verbinding tot stand gebracht, maar kan de client geen gegevens naar de server verzenden.
DROP
Voor DROP zal de opdracht er als volgt uitzien:
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j DROP
We starten de client en bekijken het verkeer:
Traffic dump
[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
We see that the connection is established, and the client cannot send data to the server.
REJECT
In this case, the behavior will be the same: the client will not be able to send a request but will continue to receive ICMP 127.0.0.1 tcp port 12345 unreachable and increase the time between resending requests exponentially. The command looks like this:
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j REJECT
REJECT with tcp-reset
The command looks as follows:
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j REJECT --reject-with tcp-reset
We already know that when using —reject-with tcp-reset the client will receive an RST packet in response, so we can predict the behavior: receiving an RST packet when the connection is established indicates an unexpected socket closure on the other side, meaning the client should receive Connection reset by peer. We run our script and verify this. Here's what the traffic will look like:
Traffic dump
[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 met icmp-host-onbereikbaar
I think it’s already clear to everyone what the command will look like 🙂 The client's behavior in this case will differ slightly from what it was with a simple REJECT: the client will not increase the timeout between attempts to resend the packet.
[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
Uitslag
It is not necessary to write a mock to test the interaction of the service with a hung client or server; sometimes it is enough to use standard utilities available in Linux.
De in dit artikel besproken tools hebben nog veel meer mogelijkheden dan beschreven, dus je kunt je eigen manieren van gebruik bedenken. Persoonlijk vind ik altijd genoeg van wat ik heb geschreven (in feite zelfs minder). Als je deze of vergelijkbare tools in je bedrijf voor testing gebruikt, laat me dan alsjeblieft weten hoe. Als dat niet zo is, hoop ik dat je software beter zal worden als je besluit deze manieren te gebruiken om het te controleren bij netwerkproblemen.
Bron: habr.com
