Simulera nÀtverksproblem i Linux

Hej allihopa, jag heter Sasha och jag leder backend-testning pĂ„ FunCorp. Vi har, precis som mĂ„nga andra, implementerat en tjĂ€nstebaserad arkitektur. Å ena sidan förenklar det arbetet eftersom varje tjĂ€nst Ă€r enklare att testa separat, men Ă„ andra sidan uppstĂ„r behovet av att testa interaktionen mellan tjĂ€nster, vilket ofta sker över nĂ€tverket.

I den hÀr artikeln kommer jag att berÀtta om tvÄ verktyg som kan anvÀndas för att testa grundlÀggande scenarier som beskriver applikationens funktion vid nÀtverksproblem.

Simulera nÀtverksproblem i Linux

Simulera nÀtverksproblem

Vanligtvis testas programvara pÄ testservrar med bra internetanslutning. Under de tuffa förhÄllandena i produktion kan allt vara mer komplicerat, sÄ ibland behöver man kontrollera program under dÄliga anslutningar. I Linux hjÀlper verktyget tc.

tc (förkortning av Traffic Control) möjliggör konfiguration av överföring av nÀtverkspaket i systemet. Detta verktyg har stora möjligheter, och du kan lÀsa mer om dem hÀr. HÀr kommer jag att gÄ igenom bara nÄgra av dem: vi Àr intresserade av trafikplanering, för vilket vi anvÀnder qdisc, och eftersom vi behöver simulera ett instabilt nÀtverk kommer vi att anvÀnda classless qdisc netem.

LÄt oss starta en echo-server pÄ servern (jag anvÀnde nmap-ncat):

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

För att detaljera alla tidsstÀmplar vid varje steg av interaktionen mellan klienten och servern har jag skrivit ett enkelt Python-skript som skickar en förfrÄgan Test till vÄr echo-server.

KÀllkoden för 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

LÄt oss köra den och titta pÄ trafiken pÄ grÀnssnittet lo och 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

Trafikdump

[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: versökta utdata dÀmpas, anvÀnd -v eller -vv för full protokollavkodning
lyssnar pÄ lo, lÀnktyp EN10MB (Ethernet), fÄngststorlek 262144 byte
10:42:59.448601 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flaggor [S], seq 3383332866, win 43690, alternativ [mss 65495,sackOK,TS val 606325685 ecr 0,nop,wscale 7], lÀngd 0
10:42:59.448612 IP 127.0.0.1.12345 > 127.0.0.1.54054: Flaggor [S.], seq 2584700178, ack 3383332867, win 43690, alternativ [mss 65495,sackOK,TS val 606325685 ecr 606325685,nop,wscale 7], lÀngd 0
10:42:59.448622 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flaggor [.], ack 1, win 342, alternativ [nop,nop,TS val 606325685 ecr 606325685], lÀngd 0
10:42:59.448923 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flaggor [P.], seq 1:6, ack 1, win 342, alternativ [nop,nop,TS val 606325685 ecr 606325685], lÀngd 5
10:42:59.448930 IP 127.0.0.1.12345 > 127.0.0.1.54054: Flaggor [.], ack 6, win 342, alternativ [nop,nop,TS val 606325685 ecr 606325685], lÀngd 0
10:42:59.459118 IP 127.0.0.1.12345 > 127.0.0.1.54054: Flaggor [P.], seq 1:15, ack 6, win 342, alternativ [nop,nop,TS val 606325696 ecr 606325685], lÀngd 14
10:42:59.459213 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flaggor [.], ack 15, win 342, alternativ [nop,nop,TS val 606325696 ecr 606325696], lÀngd 0
10:42:59.459268 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flaggor [F.], seq 6, ack 15, win 342, alternativ [nop,nop,TS val 606325696 ecr 606325696], lÀngd 0
10:42:59.460184 IP 127.0.0.1.12345 > 127.0.0.1.54054: Flaggor [F.], seq 15, ack 7, win 342, alternativ [nop,nop,TS val 606325697 ecr 606325696], lÀngd 0
10:42:59.460196 IP 127.0.0.1.54054 > 127.0.0.1.12345: Flaggor [.], ack 16, win 342, alternativ [nop,nop,TS val 606325697 ecr 606325697], lÀngd 0

Allt Àr standard: tredelat handskakning, PSH/ACK och ACK som svar tvÄ gÄnger - detta Àr utbytet av förfrÄgningar och svar mellan klient och server, och tvÄ gÄnger FIN/ACK och ACK - avslut av anslutningen.

Pakettid

Nu stÀller vi in försening pÄ 500 millisekunder:

tc qdisc add dev lo root netem delay 500ms

Vi startar klienten och ser att skriptet nu körs i 2 sekunder:

[user@host ~]# ./client.py
[tid före anslutning: 1578662612.71044]
[tid efter anslutning, före avsÀndning: 1578662613.71059]
[tid efter avsÀndning, före mottagning: 1578662613.71065]
[tid efter mottagning, före stÀngning: 1578662614.72011]
[tid efter stÀngning: 1578662614.72019]
[total varaktighet: 2.00974]
Svar: Test

Vad hÀnder med trafiken? Vi tittar:

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 gÄr att se att det uppstÄr en förvÀntad latens pÄ en halv sekund i interaktionen mellan klienten och servern. Det Àr mycket mer intressant att se hur systemet beter sig nÀr latensen Àr lÀngre: kÀrnan börjar Äterigen skicka vissa TCP-paket. LÄt oss Àndra fördröjningen till 1 sekund och kolla trafiken (jag kommer inte att visa klientens utdata, dÀr Àr den förvÀntade total varaktigheten 4 sekunder):

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 Àr tydligt att klienten skickade SYN-paket tvÄ gÄnger, medan servern skickade SYN/ACK tvÄ gÄnger.

Utöver det konstanta vÀrdet kan fördröjningen ocksÄ stÀllas in med en avvikelse, en fördelning och en korrelation (med vÀrdet för det föregÄende paketet). Detta görs pÄ följande sÀtt:

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

HÀr har vi stÀllt in fördröjningen pÄ mellan 100 och 900 millisekunder, vÀrdena kommer att vÀljas enligt normalfördelningen och kommer att ha en 50-procentig korrelation med fördröjningens vÀrde för det föregÄende paketet.

Du kanske har lagt mÀrke till att jag anvÀnde add, och klicka sedan change. VÀrdet av dessa kommandon Àr uppenbart, sÄ jag lÀgger till att det ocksÄ finns del, med vilket man kan ta bort konfigurationen.

Paketförlust

LÄt oss nu försöka Ästadkomma paketförlust. Som framgÄr av dokumentationen kan detta göras pÄ tre olika sÀtt: antingen genom att slumpmÀssigt förlora paket med viss sannolikhet, eller genom att anvÀnda en Markovkedja med 2, 3 eller 4 tillstÄnd för att berÀkna paketförlust, eller genom att anvÀnda Elliot-Gilbert-modellen. I artikeln kommer jag att behandla det första (det enklaste och mest uppenbara) sÀttet, och för de andra kan man lÀsa. hÀr.

Vi kommer att simulera en paketförlust pÄ 50 % med en korrelation pÄ 25 %:

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

TyvÀrr, Fungerar libdns korrekt? => Kör kan inte visa oss paketförlusten tydligt, vi fÄr bara anta att det verkligen fungerar. Och att bekrÀfta detta kommer att vara den ökade och instabila exekveringstiden för skriptet client.py (kan köras omedelbart eller ta 20 sekunder), samt det ökade antalet retransmiterade paket:

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

TillÀgg av brus i paketen

Förutom paketförlust kan vi ocksÄ simulera paketskador: ett brus kommer att upptrÀda pÄ en slumpmÀssig position i paketet. Vi kommer att skapa skador pÄ paketen med 50 % sannolikhet och utan korrelation:

tc qdisc change dev lo root netem corrupt 50%

Vi kör klientskriptet (inget intressant dÀr, men det kördes i 2 sekunder), vi tittar pÄ trafiken:

Trafikdump

[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: den verbala utmatningen Àr dÀmpad, anvÀnd -v eller -vv för fullstÀndig protokollavkodning
lyssnar pÄ lo, lÀnktyp EN10MB (Ethernet), fÄngststorlek 262144 bytes
10:20:54.812434 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flaggor [S], seq 2023663770, win 43690, alternativ [mss 65495,sackOK,TS val 1037001049 ecr 0,nop,wscale 7], lÀngd 0
10:20:54.812449 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flaggor [S.], seq 2104268044, ack 2023663771, win 43690, alternativ [mss 65495,sackOK,TS val 1037001049 ecr 1037001049,nop,wscale 7], lÀngd 0
10:20:54.812458 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flaggor [.], ack 1, win 342, alternativ [nop,nop,TS val 1037001049 ecr 1037001049], lÀngd 0
10:20:54.812509 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flaggor [P.], seq 1:6, ack 1, win 342, alternativ [nop,nop,TS val 1037001049 ecr 1037001049], lÀngd 5
10:20:55.013093 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flaggor [P.], seq 1:6, ack 1, win 342, alternativ [nop,nop,TS val 1037001250 ecr 1037001049], lÀngd 5
10:20:55.013122 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flaggor [.], ack 6, win 342, alternativ [nop,nop,TS val 1037001250 ecr 1037001250], lÀngd 0
10:20:55.014681 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flaggor [P.], seq 1:15, ack 6, win 342, alternativ [nop,nop,TS val 1037001251 ecr 1037001250], lÀngd 14
10:20:55.014745 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flaggor [.], ack 15, win 340, alternativ [nop,nop,TS val 1037001251 ecr 1037001251], lÀngd 0
10:20:55.014823 IP 127.0.0.1.43666 > 127.0.0.5.12345: Flaggor [F.], seq 2023663776, ack 2104268059, win 342, alternativ [nop,nop,TS val 1037001251 ecr 1037001251], lÀngd 0
10:20:55.214088 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flaggor [P.], seq 1:15, ack 6, win 342, alternativ [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]> 
10:20:55.416087 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flaggor [F.], seq 6, ack 15, win 342, alternativ [nop,nop,TS val 1037001653 ecr 1037001251], lÀngd 0
10:20:55.416804 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flaggor [F.], seq 15, ack 7, win 342, alternativ [nop,nop,TS val 1037001653 ecr 1037001653], lÀngd 0
10:20:55.416818 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flaggor [.], ack 16, win 343, alternativ [nop,nop,TS val 1037001653 ecr 1037001653], lÀngd 0
10:20:56.147086 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flaggor [F.], seq 15, ack 7, win 342, alternativ [nop,nop,TS val 1037002384 ecr 1037001653], lÀngd 0
10:20:56.147101 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flaggor [.], ack 16, win 342, alternativ [nop,nop,TS val 1037002384 ecr 1037001653], lÀngd 0

Det Ă€r tydligt att vissa paket skickades om och det finns ett paket med trasig metadata: options [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]>. Men det viktigaste Ă€r att allt till slut fungerade korrekt – TCP klarade av sin uppgift.

Dublering av paket

Vad mer kan man göra med hjĂ€lp av netem? ĐĐ°ĐżŃ€ĐžĐŒĐ”Ń€, ŃŃ‹ĐŒĐžŃ‚ĐžŃ€ĐŸĐČать сотуацою, ĐŸĐ±Ń€Đ°Ń‚ĐœŃƒŃŽ ĐżĐŸŃ‚Đ”Ń€Đ” паĐșĐ”Ń‚ĐŸĐČ, — ЎублОĐșацою паĐșĐ”Ń‚ĐŸĐČ. Эта ĐșĐŸĐŒĐ°ĐœĐŽĐ° таĐșжД ĐżŃ€ĐžĐœĐžĐŒĐ°Đ”Ń‚ 2 Đ°Ń€ĐłŃƒĐŒĐ”ĐœŃ‚Đ°: ĐČĐ”Ń€ĐŸŃŃ‚ĐœĐŸŃŃ‚ŃŒ Đž ĐșĐŸŃ€Ń€Đ”Đ»ŃŃ†ĐžŃŽ.

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

Ändring av paketordningen

Man kan blanda paket pÄ tvÄ sÀtt.

I det första skickas en del paket omedelbart, medan de andra skickas med en viss fördröjning. Exempel frÄn dokumentationen:

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

Med 25% sannolikhet (och korrelation 50%) skickas paketet omedelbart, medan de andra skickas med en fördröjning pÄ 10 millisekunder.

Det andra sÀttet Àr att varje N:e paket skickas omedelbart med en given sannolikhet (och korrelation), medan de andra skickas med en viss fördröjning. Exempel frÄn dokumentationen:

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

Var femte paket med 25% sannolikhet kommer att skickas utan fördröjning.

Ändring av bandbredd

Vanligtvis hÀnvisar man till TBF, men med hjÀlp av netem kan man ocksÄ Àndra bandbredden pÄ grÀnssnittet:

tc qdisc change dev lo root netem rate 56kbit

Detta kommando kommer att göra överföringar pÄ localhost lika plÄgsamma som att surfa pÄ internet via en uppringd modem. Förutom att stÀlla in bitrÀntet kan man ocksÄ simulera en kanallagsprotokollmodell: ange overhead för paketet, cellstorlek och overhead för cellen. Till exempel kan man simulera ATM och en bitrÀnt pÄ 56 kbit/s:

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

Simulera connection timeout

Ännu en viktig punkt i testplanen vid programvaruacceptans Ă€r tidsgrĂ€nser. Detta Ă€r viktigt, eftersom i distribuerade system, vid avstĂ€ngning av en tjĂ€nst, ska de andra i tid falla tillbaka pĂ„ andra eller returnera ett fel till klienten; de fĂ„r inte bara hĂ€nga, vĂ€ntandes pĂ„ svar eller att anslutningen upprĂ€ttas.

Det finns flera sÀtt att göra detta: till exempel anvÀnda en mock som inte svarar, eller ansluta till processen med en debugger, sÀtta en breakpoint pÄ rÀtt plats och stoppa processens utförande (detta Àr kanske det mest absurda sÀttet). Men ett av de mest uppenbara sÀtten Àr att blockera portar eller vÀrdar. Detta kan hjÀlpa oss. iptables.

För demonstrationen kommer vi att brandvĂ€gsgöra port 12345 och köra vĂ„rt klientskript. Vi kan brandvĂ€gga utgĂ„ende paket pĂ„ denna port hos avsĂ€ndaren eller inkommande pĂ„ mottagaren. I mina exempel kommer vi att brandvĂ€gga inkommande paket (vi anvĂ€nder kedjan INPUT och alternativet —dport). För dessa paket kan man göra DROP, REJECT eller REJECT med TCP-flagg RST, det gĂ„r Ă€ven att anvĂ€nda ICMP för host oĂ„tkomlig (det vanliga beteendet Ă€r icmp-port-unreachable, och det finns ocksĂ„ möjlighet att skicka som svar icmp-net-unreachable, icmp-proto-unreachable, icmp-net-prohibited och icmp-host-prohibited).

DROP

Om det finns en regel med DROP kommer paketen bara att "försvinna".

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

Vi startar klienten och ser att den hÀnger vid anslutningen till servern. Vi kollar trafiken:
Trafikdump

[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: detaljerad utskrift undertryckt, anvÀnd -v eller -vv för full protokollavkodning
lyssnar pÄ lo, lÀnktyp EN10MB (Ethernet), fÄngststorlek 262144 byt
08:28:20.213506 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flaggor [S], sekvens 3019694933, vinst 43690, alternativ [mss 65495,sackOK,TS val 1203046450 ecr 0,nop,wscale 7], lÀngd 0
08:28:21.215086 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flaggor [S], sekvens 3019694933, vinst 43690, alternativ [mss 65495,sackOK,TS val 1203047452 ecr 0,nop,wscale 7], lÀngd 0
08:28:23.219092 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flaggor [S], sekvens 3019694933, vinst 43690, alternativ [mss 65495,sackOK,TS val 1203049456 ecr 0,nop,wscale 7], lÀngd 0
08:28:27.227087 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flaggor [S], sekvens 3019694933, vinst 43690, alternativ [mss 65495,sackOK,TS val 1203053464 ecr 0,nop,wscale 7], lÀngd 0
08:28:35.235102 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flaggor [S], sekvens 3019694933, vinst 43690, alternativ [mss 65495,sackOK,TS val 1203061472 ecr 0,nop,wscale 7], lÀngd 0

Vi ser att klienten skickar SYN-paket med en exponentiellt ökande timeout. HÀr har vi hittat en liten bugg i klienten: den mÄste anvÀnda metoden settimeout(), för att begrÀnsa tiden som klienten kommer att försöka ansluta till servern.

Vi tar omedelbart bort regeln:

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

Man kan ta bort alla regler direkt:

iptables -F

Om du anvÀnder Docker och behöver brandvÀggsskydda all trafik som gÄr till containern, kan du göra det pÄ följande sÀtt:

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

REJECT

Nu lÀgger vi till en liknande regel, men med REJECT:

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

Klienten avslutas efter en sekund med felet [Errno 111] Connection refused. Vi kollar ICMP-trafiken:

[user@host ~]# tcpdump -i lo -nn icmp
tcpdump: detaljerad utskrift undertryckt, anvÀnd -v eller -vv för full protokollavkodning
lyssnar pÄ lo, lÀnktyp EN10MB (Ethernet), fÄngststorlek 262144 byt
08:45:32.871414 IP 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 tcp port 12345 oÄtkomlig, lÀngd 68
08:45:33.873097 IP 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 tcp port 12345 oÄtkomlig, lÀngd 68

Det Àr tydligt att klienten tvÄ gÄnger fick port oÄtkomlig och avslutades med ett fel efter detta.

REJECT med tcp-reset

LĂ„t oss prova att lĂ€gga till alternativet —reject-with tcp-reset:

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

I det hÀr fallet fÄr klienten omedelbart ett fel, eftersom den fick ett RST-paket pÄ första förfrÄgan:

[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 med icmp-host-unreachable

LÄt oss prova ett annat alternativ för anvÀndning av REJECT:

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

Klienten avslutas efter en sekund med felet [Errno 113] Ingen vÀg till vÀrd, i ICMP-trafiken ser vi ICMP-vÀrden 127.0.0.1 otillgÀnglig.

Du kan ocksĂ„ prova andra parametrar för REJECT, men jag kommer att stanna vid dessa 🙂

Simulera begÀrning timeout

En annan situation Àr nÀr klienten lyckas ansluta till servern, men inte kan skicka en begÀran. Hur kan man filtrera paket sÄ att filtreringen inte börjar omedelbart? Om man ser pÄ trafiken frÄn all kommunikation mellan klienten och servern kan man mÀrka att endast SYN- och ACK-flaggor anvÀnds vid etableringen av anslutningen, medan i sista paketet av förfrÄgan finns flaggan PSH. Den sÀtts automatiskt för att undvika buffring. Denna information kan anvÀndas för att skapa en filter: den kommer att slÀppa igenom alla paket utom de som innehÄller PSH-flagga. PÄ sÄ sÀtt kommer anslutningen att etableras, men klienten kan inte skicka data till servern.

DROP

För DROP kommer kommandot att se ut pÄ följande sÀtt:

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

Vi startar klienten och ser trafiken:

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
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 att anslutningen har upprÀttats och att klienten inte kan skicka data till servern.

REJECT

I det hÀr fallet kommer beteendet att vara detsamma: klienten kommer inte kunna skicka en begÀran, men kommer att ta emot ICMP 127.0.0.1 tcp port 12345 otillgÀnglig och öka tiden mellan omförsÀndning av begÀran exponentiellt. Kommandot ser ut sÄ hÀr:

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

REJECT med tcp-reset

Kommandot ser ut som följer:

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

Vi vet redan att nĂ€r vi anvĂ€nder —reject-with tcp-reset klienten fĂ„r ett RST-paket som svar, sĂ„ vi kan förutsĂ€ga beteendet: att fĂ„ ett RST-paket nĂ€r anslutningen Ă€r etablerad betyder en ovĂ€ntad stĂ€ngning av sockeln frĂ„n andra sidan, vilket innebĂ€r att klienten bör fĂ„ Connection reset by peer. Vi kör vĂ„rt skript och verifierar detta. SĂ„ hĂ€r kommer trafiken att se ut:

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
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

Jag tror att det redan Ă€r klart för alla hur kommandot kommer att se ut 🙂 Klientens beteende i detta fall kommer att skilja sig nĂ„got frĂ„n det med en enkel REJECT: klienten kommer inte att öka timeouten mellan försök att omförsĂ€nda paketet.

[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

Utdata

Det Àr inte nödvÀndigt att skriva ett mock-up för att kontrollera interaktionen mellan tjÀnsten och en hÀngande klient eller server, ibland Àr det tillrÀckligt att anvÀnda standardverktyg som finns i Linux.

De verktyg som beskrivs i artikeln har fler möjligheter Àn som beskrivits, sÄ du kan komma pÄ egna sÀtt att anvÀnda dem. Personligen behöver jag alltid bara det jag har skrivit om (faktiskt till och med mindre). Om du anvÀnder dessa eller liknande verktyg för testning i ditt företag, vÀnligen skriv hur. Om du inte gör det, hoppas jag att din programvara kommer att bli bÀttre om du beslutar dig för att testa den under nÀtverksproblem som föreslagits.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster