Përshëndetje të gjithëve, unë quhem Sasha dhe drejtoj testimin e backend-it në FunCorp. Ne, si shumë të tjerë, kemi implementuar një arkitekturë të orientuar drejt shërbimit. Nga një anë, kjo e lehtëson punën, pasi çdo shërbim është më i lehtë për t'u testuar veçmas, por nga ana tjetër, lind nevoja për të testuar ndërveprimin mes shërbimeve, i cili shpesh ndodh përmes rrjetit.
Në këtë artikull do të flas për dy mjete, me anë të të cilave mund të kontrolloni skenarët bazë që përshkruajnë funksionimin e aplikacionit në kushte të problemeve me rrjetin.

Simulimi i problemeve me rrjetin
Zakonisht, software-i testohet në servera testimi me një kanal të mirë interneti. Në kushtet e ashpra të prodhimit, gjithçka nuk mund të jetë kaq e lehtë, prandaj ndonjëherë duhet të kontrollohet programet në kushte të lidhjes së dobët. Në Linux, për detyrën e simulimit të këtyre kushteve ndihmon mjeti tc.
tc (shkurtim për Traffic Control) lejon konfigurimin e transmetimit të pakove të rrjetit në sistem. Ky mjet ka mundësi të mëdha, për t'u njohur më shumë rreth tyre mund të lexoni . Këtu, do të shqyrtoj vetëm disa prej tyre: na intereson planifikimi i trafikut, për të cilin ne përdorim qdisc, dhe pasi na nevojitet të imitojmë një rrjet të paqëndrueshëm, do të përdorim classless qdisc .
Do ta nisim echo-serverin në server (unë përdora për këtë ):
ncat -l 127.0.0.1 12345 -k -c 'xargs -n1 -i echo "Përgjigje: {}"'
Për të treguar detajisht të gjithë timestamp-at në çdo hap të bashkëpunimit të klientit me serverin, shkrova një skenar të thjeshtë në Python që dërgon një kërkesë Test në echo-serverin tonë.
Kodi burimor i klientit
#!/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
Do ta nisim atë dhe do të shohim në trafik në ndërfaqen lo dhe portin 12345:
[user@host ~]# python client.py
[koha para lidhjes: 1578652979.44837]
[koha pas lidhjes, para dërgimit: 1578652979.44889]
[koha pas dërgimit, para marrjes: 1578652979.44894]
[koha pas marrjes, para mbylljes: 1578652979.45922]
[koha pas mbylljes: 1578652979.45928]
[koha totale: 0.01091]
Përgjigje: Test
Dump i trafikut
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: output i detajuar është e shtypur, përdorni -v ose -vv për dekodimin e plotë të protokollit
po dëgjon në lo, tipi i lidhjes EN10MB (Ethernet), madhësia e kapjes 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
Të gjitha janë standarde: trojkat, PSH/ACK dhe ACK në përgjigje dy herë — ky është shkëmbimi i kërkesës dhe përgjigjes midis klientit dhe serverit, dhe dy herë FIN/ACK dhe ACK — përfundimi i lidhjes.
Vonesa e paketave
Tani do të vendosim një vonesë prej 500 milisekondash:
tc qdisc add dev lo root netem delay 500ms
Nisemi me klientin dhe shohim se tani skripti ekzekutohet për 2 sekonda:
[user@host ~]# ./client.py
[koha para lidhjes: 1578662612.71044]
[koha pas lidhjes, para dërgimit: 1578662613.71059]
[koha pas dërgimit, para marrjes: 1578662613.71065]
[koha pas marrjes, para mbylljes: 1578662614.72011]
[koha pas mbylljes: 1578662614.72019]
[koha totale: 2.00974]
Përgjigja: Test
Çfarë është në trafik? Po shohim:
Dump i trafikut
13:23:33.210520 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flakset [S], seq 1720950927, fole 43690, mundësi [mss 65495,sackOK,TS val 615958947 ecr 0,nop,wscale 7], gjatësi 0
13:23:33.710554 IP 127.0.0.1.12345 > 127.0.0.1.58694: Flakset [S.], seq 1801168125, ack 1720950928, fole 43690, mundësi [mss 65495,sackOK,TS val 615959447 ecr 615958947,nop,wscale 7], gjatësi 0
13:23:34.210590 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flakset [.], ack 1, fole 342, mundësi [nop,nop,TS val 615959947 ecr 615959447], gjatësi 0
13:23:34.210657 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flakset [P.], seq 1:6, ack 1, fole 342, mundësi [nop,nop,TS val 615959947 ecr 615959447], gjatësi 5
13:23:34.710680 IP 127.0.0.1.12345 > 127.0.0.1.58694: Flakset [.], ack 6, fole 342, mundësi [nop,nop,TS val 615960447 ecr 615959947], gjatësi 0
13:23:34.719371 IP 127.0.0.1.12345 > 127.0.0.1.58694: Flakset [P.], seq 1:15, ack 6, fole 342, mundësi [nop,nop,TS val 615960456 ecr 615959947], gjatësi 14
13:23:35.220106 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flakset [.], ack 15, fole 342, mundësi [nop,nop,TS val 615960957 ecr 615960456], gjatësi 0
13:23:35.220188 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flakset [F.], seq 6, ack 15, fole 342, mundësi [nop,nop,TS val 615960957 ecr 615960456], gjatësi 0
13:23:35.720994 IP 127.0.0.1.12345 > 127.0.0.1.58694: Flakset [F.], seq 15, ack 7, fole 342, mundësi [nop,nop,TS val 615961457 ecr 615960957], gjatësi 0
13:23:36.221025 IP 127.0.0.1.58694 > 127.0.0.1.12345: Flakset [.], ack 16, fole 342, mundësi [nop,nop,TS val 615961957 ecr 615961457], gjatësi 0
Vërehet se në ndërveprimin midis klientit dhe serverit ka një vonesë të pritur prej gjysmë sekonde. Sistemi sillet shumë më interesant nëse vonesa është më e madhe: bërthama fillon të dërgojë disa TCP-paketa përsëri. Le ta ndryshojmë vonesën në 1 sekondë dhe të shohim trafikun (nuk do të tregoj daljen e klientit, aty janë 4 sekonda të pritura në total):
tc qdisc change dev lo root netem delay 1s
Dump i trafikut
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
Është e qartë se klienti dërgoi dy herë paketën SYN, ndërsa serveri dërgoi dy herë SYN/ACK.
Përveç vlerës konstante, për vonesën mund të përcaktohet një devijim, funksioni i shpërndarjes dhe korrelacioni (me vlerën për paketën e mëparshme). Kjo bëhet si më poshtë:
tc qdisc change dev lo root netem delay 500ms 400ms 50 distribution normal
Këtu kemi caktuar një vonesë në intervalin nga 100 deri në 900 milisekonda, vlerat do të zgjidhen në përputhje me shpërndarjen normale dhe do të ketë 50% korrelacion me vlerën e vonesës për paketën e mëparshme.
Mund të keni vënë re se në komandën e parë kam përdorur shto, dhe pastaj ndrysho. Vlera e këtyre komandave është e qartë, prandaj do të shtoj vetëm se ka gjithashtu fshij, me të cilin mund të hiqni konfigurimin.
Humbja e paketave
Tani le të provoni të realizoni humbjen e paketave. Siç shihet nga dokumentacioni, kjo mund të arrihet në tre mënyra: të humbni paketat në mënyrë të rastësishme me ndonjë probabilitet, të përdorni një zinxhir Markov me 2, 3 ose 4 gjendje për të llogaritur humbjen e paketit ose të përdorni modelin e Elliot-Gilbert. Në artikullin e këtij do të shqyrtoj mënyrën e parë (më të thjeshtën dhe më të dukshme), ndërsa për të tjerat mund të lexoni. .
Të bëjmë humbjen e 50% të paketave me korelyacion 25%:
tc qdisc add dev lo root netem loss 50% 25%
Fatkeqësisht, tcpdump nuk mund të na tregojë vizualisht humbjen e paketave, do të supozjmë vetëm se ajo vërtet funksionon. Ndihma në këtë do të vijë nga rritja dhe paqëndrueshmëria e kohës së funksionimit të skriptit client.py (mund të ekzekutohet menjëherë, ose mund të zgjasë deri në 20 sekonda), si dhe rritja e numrit të paketave të ripërsëritura:
[user@host ~]# netstat -s | grep retransmited; sleep 10; netstat -s | grep retransmited
17147 segmente të ripërsëritura
17185 segmente të ripërsëritura
Shtimi i zhurmës në paketa
Përveç humbjes së paketave, mund të imitojmë dëmtimin e tyre: një zhurmë do të shfaqet në një pozicion të rastësishëm të paketës. Do të bëjmë dëmtimin e paketave me një probabilitet 50% dhe pa korelyacion:
tc qdisc change dev lo root netem corrupt 50%
Nis skriptin e klientit (nuk ka asgjë interesante, por është ekzekutuar për 2 sekonda), shohim trafikun:
Dump i trafikut
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: output i detajuar është shtypur, përdor -v ose -vv për dekodimin e plotë të protokollit
në për 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
Është e qartë se disa paketa janë dërguar përsëri dhe ka një paketë me meta të prishura: options [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]>. Por e rëndësishmja është se në fund të fundit çdo gjë funksionoi siç duhet — TCP e realizoi detyrën e tij.
Dublimi i paketimeve
Çfarë tjetër mund të bëhet me netem? Например, сымитировать ситуацию, обратную потере пакетов, — дубликацию пакетов. Эта команда также принимает 2 аргумента: вероятность и корреляцию.
tc qdisc change dev lo root netem duplicate 50% 25%
Ndryshimi i rendit të paketimeve
Mund të përzihen paketat, dhe madje në dy mënyra.
Në të parën, një pjesë e paketimeve dërgohet menjëherë, ndërsa të tjerat — me një vonesë të caktuar. Shembulli nga dokumentacioni:
tc qdisc change dev lo root netem delay 10ms reorder 25% 50%
Me një mundësi prej 25% (dhe korrelacion prej 50%), paketa do të dërgohet menjëherë, ndërsa të tjerat do të dërgohen me një vonesë prej 10 milisekondash.
Mënyra e dytë është kur çdo paketë N dërgohet menjëherë me një probabilitet (dhe korrelacion) të caktuar, ndërsa të tjerat — me një vonesë të caktuar. Shembulli nga dokumentacioni:
tc qdisc change dev lo root netem delay 10ms reorder 25% 50% gap 5
Çdo pakete e pestë me një probabilitet prej 25% do të dërgohet pa vonesë.
Ndryshimi i kapacitetit të kalimit
Më shumë dërgohen në çdo rast te , por gjithashtu me netem mund të ndryshohet kapaciteti i ndërlidhjes:
tc qdisc change dev lo root netem rate 56kbit
Kjo komandë do të bëjë që localhost të ngjashme me të dhimbshme si surfing në internet me një modem dial-up. Përveç vendosjes së bitrate-it, mund të emuloni gjithashtu modelin e protokollit të nivelit të kanaleve: të vendosni overhead për paketën, madhësinë e qelizës dhe overhead për qelizën. Për shembull, kështu mund të simulohet dhe bitrate 56 kbit/sek.:
tc qdisc change dev lo root netem rate 56kbit 0 48 5
Simulojmë connection timeout
Një pikë tjetër e rëndësishme në planin e testimit gjatë pranimit të software-it është timeout-i. Kjo është e rëndësishme, sepse në sistemet e shpërndara, kur ndalon një nga shërbimet, të tjerët duhet të kalojnë në mënyrë të përshtatshme tek të tjerët ose të kthejnë një gabim për klientin, për këtë arsye ato nuk duhet të mbeten thjesht të bllokuara, duke pritur për përgjigje ose për të vendosur një lidhje.
Ka disa mënyra për ta bërë këtë: për shembull, të përdorni një mock që nuk përgjigjet fare, ose të lidheni me procesin duke përdorur debugger-in, të vendosni një breakpoint në vendin e duhur dhe të ndaloni ekzekutimin e procesit (kjo është ndoshta mënyra më e çuditshme). Por një nga mënyrat më të dukshme është të bllokoni portet ose host-at. Me këtë do të na ndihmojë .
Për demonstrim do të bllokojmë portin 12345 dhe do të aktivizojmë skriptin tonë të klientit. Mund të bllokoni paketat dalëse në këtë port nga dërguesi ose ato hyrëse në pranues. Në shembujt e mi do të bllokojmë paketat hyrëse (do të përdorim chain INPUT dhe opsionin —dport). Paketat e tilla mund të bëjnë DROP, REJECT ose REJECT me flamurin TCP RST, ose mund të dërgojmë ICMP host unreachable (në të vërtetë, sjellja e parazgjedhur është icmp-port-unreachable, dhe ka gjithashtu mundësinë të dërgojmë përgjigje icmp-net-unreachable, icmp-proto-unreachable, icmp-net-prohibited dhe icmp-host-prohibited).
DROP
Nëse ka një rregull me DROP, paketat do të «zhduken» thjesht.
iptables -A INPUT -p tcp --dport 12345 -j DROP
Çelim klientin dhe shohim që ai ngec në fazën e lidhjes me serverin. Shikojmë trafikun:
Dump i trafikut
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: output i detajuar e fshehur, përdorni -v ose -vv për dekodimin e plotë të protokollit
po dëgjon në lo, tip i lidhjes EN10MB (Ethernet), madhësia e kapjes 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
Të dhënat tregojnë se klienti dërgon paketa SYN me një kohë pritje që rritet eksponencialisht. Këtu gjetëm një defekt të vogël në klient: duhet të përdoret metoda settimeout(), për të kufizuar kohën brenda së cilës klienti do të përpiqet të lidhet me serverin.
Menjëherë eliminojmë rregullin:
iptables -D INPUT -p tcp --dport 12345 -j DROPMund të hiqni menjëherë të gjitha rregullat:
iptables -F
Nëse po përdorni Docker dhe ju nevojitet të menaxhoni të gjithë trafikun që shkon në kontejner, mund ta bëni këtë si më poshtë:
iptables -I DOCKER-USER -p tcp -d CONTAINER_IP -j DROP
REFUZO
Tani tani do të shtojmë një rregull të ngjashëm, por me REJECT:
iptables -A INPUT -p tcp --dport 12345 -j REJECT
Klienti përfundon pas një sekonde me gabim [Errno 111] Connection refused. Po shohim trafikun ICMP:
[user@host ~]# tcpdump -i lo -nn icmp
tcpdump: output-i detajuar është shtypur, përdorni -v ose -vv për dekodimin e plotë të protokollit
në dëgjim në lo, lloji i lidhjes EN10MB (Ethernet), madhësia e kapjes 262144 byte
08:45:32.871414 IP 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 tcp port 12345 i papërmbushur, gjatësi 68
08:45:33.873097 IP 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 tcp port 12345 i papërmbushur, gjatësi 68
Duket se klienti mori dy herë port i papërmbushur dhe pas kësaj përfundoi me gabim.
REJECT me tcp-reset
Tani do të provojmë të shtojmë opsionin —reject-with tcp-reset:
iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with tcp-reset
Në këtë rast, klienti del menjëherë me gabim, sepse në kërkesën e parë mori paketën RST:
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: output-i detajuar është shtypur, përdorni -v ose -vv për dekodimin e plotë të protokollit
në dëgjim në lo, lloji i lidhjes EN10MB (Ethernet), madhësia e kapjes 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], gjatësi 0
09:02:52.766184 IP 127.0.0.1.12345 > 127.0.0.1.60658: Flags [R.], seq 0, ack 1889460884, win 0, gjatësi 0
REJECT me icmp-host-unreachable
Tani do të provojmë një variant tjetër të përdorimit të REJECT:
iptables -A INPUT -p tcp --dport 12345 -j REJECT --reject-with icmp-host-unreachable
Klienti përfundon pas një sekonde me gabim [Errno 113] No route to host, në trafikun ICMP shohim ICMP host 127.0.0.1 i papërmbushur.
Mund të provoni gjithashtu parametrat e tjerë REJECT, ndërsa unë do të ndalem te këta 🙂
Imitojmë kohën e skadimit të kërkesës
Një tjetër situatë është kur klienti mund të lidhet me serverin, por nuk mund të dërgojë një kërkesë. Si të filtrojmë paketat që filtruese të fillojë siç duhet? Nëse shihni trafikun e çdo komunikimi midis klientit dhe serverit, mund të vëreni se gjatë vendosjes së lidhjes përdoren vetëm flamujt SYN dhe ACK, dhe kur shkëmbehen të dhënat në paketën e fundit të kërkesës do të jetë flamuri PSH. Ai vendoset automatikisht për të shmangur bllokimin. Mund ta përdorni këtë informacion për të krijuar një filtrues: ai do të lejojë të gjitha paketat, përveç atyre që përmbajnë flamurin PSH. Kështu, lidhja do të vendoset, por klienti nuk do të mund të dërgojë të dhëna në server.
DROP
Për DROP komanda do të duket si më poshtë:
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j DROP
Nisni klientin dhe shikoni trafikun:
Dump i trafikut
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: pamje me detaje të fikura, përdorni -v ose -vv për dekodimin e plotë të protokollit
po dëgjon në lo, lloji i lidhjes EN10MB (Ethernet), madhësia e kapjes 262144 bajt
10:02:47.549498 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flag [S], seq 2166014137, win 43690, opsionet [mss 65495,sackOK,TS val 1208713786 ecr 0,nop,wscale 7], gjatësi 0
10:02:47.549510 IP 127.0.0.1.12345 > 127.0.0.1.49594: Flag [S.], seq 2341799088, ack 2166014138, win 43690, opsionet [mss 65495,sackOK,TS val 1208713786 ecr 1208713786,nop,wscale 7], gjatësi 0
10:02:47.549520 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flag [.], ack 1, win 342, opsionet [nop,nop,TS val 1208713786 ecr 1208713786], gjatësi 0
10:02:47.549568 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flag [P.], seq 1:6, ack 1, win 342, opsionet [nop,nop,TS val 1208713786 ecr 1208713786], gjatësi 5
10:02:47.750084 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flag [P.], seq 1:6, ack 1, win 342, opsionet [nop,nop,TS val 1208713987 ecr 1208713786], gjatësi 5
10:02:47.951088 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flag [P.], seq 1:6, ack 1, win 342, opsionet [nop,nop,TS val 1208714188 ecr 1208713786], gjatësi 5
10:02:48.354089 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flag [P.], seq 1:6, ack 1, win 342, opsionet [nop,nop,TS val 1208714591 ecr 1208713786], gjatësi 5
E shohim që lidhja është vendosur dhe klienti nuk mund të dërgojë të dhëna në server.
REFUZO
Në këtë rast, sjellja do të jetë e njëjtë: klienti nuk do të mund të dërgojë kërkesë, por do të marrë ICMP 127.0.0.1 porti tcp 12345 i papërshkueshëm dhe do të rrisë kohën midis ripërsëritjeve të kërkesës në mënyrë eksponenciale. Komanda duket kështu:
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j REJECT
REJECT me tcp-reset
Komanda duket kështu:
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j REJECT --reject-with tcp-reset
Ne e dimë se, kur përdoret, —reject-with tcp-reset klienti do të marrë një paketë RST si përgjigje, kështu që mund të parashikohet sjellja: marrëja e paketës RST gjatë një lidhjeje të vendosur do të thotë mbyllje të papritur të soketit nga ana tjetër, që do të thotë se klienti duhet të marrë Connection reset by peer. Të lançojmë skriptin tonë dhe ta verifikojmë këtë. Ja si do të dukej trafiku:
Dump i trafikut
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: output i detajuar është kufizuar, përdorni -v ose -vv për të shkarkuar kodin e plotë të protokollit
po dëgjon në lo, lloji i lidhjes EN10MB (Ethernet), madhësia e kapjes 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 me icmp-host-unreachable
Mendoj se tashmë është evidente për të gjithë se si do të duket ekipi 🙂 Sjellja e klientit në këtë rast do të jetë paksa ndryshe nga ajo që ishte me një REJECT të thjeshtë: klienti nuk do të rrisë kohën e pritjes ndërmjet përpjekjeve për të dërguar përsëri paketin.
[user@host ~]# tcpdump -i lo -nn icmp
tcpdump: outputi i detajuar është shtypur, përdorni -v ose -vv për dekodifikimin e plotë të protokollit
duke dëgjuar në lo, lloj-lidhje EN10MB (Ethernet), madhësia e kapjes 262144 byte
10:29:56.149202 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 i paarritshëm, gjatësi 65
10:29:56.349107 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 i paarritshëm, gjatësi 65
10:29:56.549117 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 i paarritshëm, gjatësi 65
10:29:56.750125 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 ipaarritshëm, gjatësi 65
10:29:56.951130 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 i paarritshëm, gjatësi 65
10:29:57.152107 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 i paarritshëm, gjatësi 65
10:29:57.353115 IP 127.0.0.1 > 127.0.0.1: ICMP host 127.0.0.1 i paarritshëm, gjatësi 65
Përfundim
Nuk është e nevojshme të shkruani një mok për të verifikuar interaksionin e shërbimit me një klient ose server që është ngjitur, ndonjëherë mjafton të përdorni utilitarët standard që janë në Linux.
Mjetet e trajtuara në këtë artikull kanë shumë më shumë mundësi se sa janë përmendur, kështu që mund të krijoni disa variante të përdorimit të tyre. Personalish, gjithmonë mjafton ajo që kam shkruar (në të vërtetë, madje edhe më pak). Nëse përdorni këto ose mjete të ngjashme për testimin në kompaninë tuaj, ju lutem, ndajini se si saktësisht. Nëse jo, shpresoj se softueri juaj do të bëhet më cilësor nëse vendosni ta kontrolloni atë përmes mënyrave të propozuara për të përballuar problemet me rrjetin.
Burimi: habr.com
