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ërbimeve. Nga njëra anë, kjo e lehtëson punën, pasi çdo shërbim testihet më lehtë veçmas, por nga ana tjetër, krijohet nevoja për të testuar ndërveprimin e shërbimeve me njëra-tjetrën, që shpesh ndodh përmes rrjetit.
Në këtë artikull do të flas për dy utilitete që mund të përdoren për të verifikuar skenarët bazë që përshkruajnë funksionimin e aplikacionit në rast se ka probleme me rrjetin.

Simulimi i problemeve me rrjetin
Zakonisht, softueri testohet në serverë testues me një linjë interneti të mirë. Në kushtet e ashpra të prodhimit, gjithçka mund të mos shkojë ashtu siç duhet, prandaj ndonjëherë është e nevojshme të kontrolloni programet në kushte të lidhjes së dobët. Në Linux, me ndihmën e utilitetit tc.
tc (shkurt nga Traffic Control) ofron mundësi për të rregulluar transmetimin e paketimeve rrjet në sistem. Ky utilitet ka potenciale të mëdha, për të cilat mund të lexoni më shumë . Këtu do të shqyrtoj vetëm disa prej tyre: na intereson planifikimi i trafikut, për çfarë do të përdorim qdisc, dhe pasi na nevojitet të emulojmë një rrjet të paqëndrueshëm, do të përdorim qdisc të pa klasifikuar .
Do të nisim një server echo 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ë shfaqur në detaje të gjitha kohët në çdo hap të ndërveprimit të klientit me serverin, kam shkruar një skrypt të thjeshtë në Python, i cili dërgon kërkesë Test në serverin tonë echo.
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ë shikojmë trafikun në interfacin 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ë ndalur, përdorni -v ose -vv për dekodimin e plotë të protokollit
duke dëgjuar në lo, lloji i lidhjes EN10MB (Ethernet), madhësia e kapjes 262144 bajtë
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 standarde: dorëzim me tre palë, PSH/ACK dhe ACK në përgjigje dy herë — kjo ë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 paketeve
Tani do të vendosim vonesën prej 500 milisekonda:
tc qdisc add dev lo root netem delay 500ms
Po nis 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ë ndodh në trafik? Të shohim:
Dump i trafikut
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
Mund të shihni se në ndërveprimin mes klientit dhe serverit ka një vonesë të pritur prej gjysmë sekonde. Më interesante është se si sillet sistemi nëse vonesa është më e madhe: bërthama fillon të dërgojë sërish disa paketa TCP. Të ndryshojmë vonesën në 1 sekondë dhe ta shohim trafikun (nuk do ta tregoj rezultatin e klientit, aty janë 4 sekonda 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
Kjoqë tregon se klienti dërgoi dy herë paketa SYN dhe serveri gjithashtu dërgoi dy herë SYN/ACK.
Përveç vlerës konstante, mund të caktoni devijimin, funksionin e shpërndarjes dhe korrelacionin (me vlerën e paketës së mëparshme të dërguar). Kjo bëhet si më poshtë:
tc qdisc change dev lo root netem delay 500ms 400ms 50 distribution normal
Këtu vendosëm një vonesë në intervalin nga 100 deri në 900 milisekonda, vlerat do të kërkohen në përputhje me shpërndarjen normale dhe do të ketë një korrelacion 50 përqind 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 add, dhe pastaj change. Vlera e këtyre komandave është evidente, prandaj do të shtoj vetëm se ka gjithashtu del, me të cilin mund të hiqni konfigurimin.
Humbja e paketimeve
Tani do të provojmë të bëjmë humbjen e paketimeve. Siç duket nga dokumentacioni, kjo mund të realizohet në tre mënyra: të humbasim paketa rastësisht me ndonjë mundësi, të përdorim një zinxhir Markov për llogaritjen e humbjes së paketave me 2, 3 ose 4 gjendje ose të përdorim modelin Elliot-Gilbert. Në këtë artikull do të shqyrtoj mënyrën e parë (më të thjeshtë dhe më evidente), ndërsa për të tjerat mund të lexoni. .
Të simulojmë humbjen e 50% të pakove me korrelacion 25%:
tc qdisc add dev lo root netem loss 50% 25%
Pështu tcpdump nuk do të na tregojë në mënyrë të qartë humbjen e pakove, do të supozonim vetëm se ajo funksionon me të vërtetë. Dhe do ta konfirmojmë këtë përmes rritjes dhe pa stabilitetit të kohës së ekzekutimit të skenarit client.py (mund të përfundojë menjëherë, ose mund të zgjasë deri në 20 sekonda), si dhe rritja e numrit të pakove 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ë pakot
Përveç humbjes së pakove, mund të imitojmë dëmtimin e tyre: në një pozicion të rastësishëm të paketës do të shfaqet zhurmë. Të simulojmë dëmtimin e pakove me një probabilitet prej 50% dhe pa korrelacion:
tc qdisc change dev lo root netem corrupt 50%
Nisemi me skenarin e klientit (nuk ka asgjë interesante, por u ekzekutua për 2 sekonda), shikojmë trafikun:
Dump i trafikut
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: dalja e detajuar është e ndaluar, përdorni -v ose -vv për dekodimin e plotë të protokollit
duke përgjuar në lo, lloji i lidhjes EN10MB (Ethernet), madhësia e kapjes 262144 bytes
10:20:54.812434 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flag [S], seq 2023663770, win 43690, opsione [mss 65495,sackOK,TS val 1037001049 ecr 0,nop,wscale 7], gjatësi 0
10:20:54.812449 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flag [S.], seq 2104268044, ack 2023663771, win 43690, opsione [mss 65495,sackOK,TS val 1037001049 ecr 1037001049,nop,wscale 7], gjatësi 0
10:20:54.812458 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flag [.], ack 1, win 342, opsione [nop,nop,TS val 1037001049 ecr 1037001049], gjatësi 0
10:20:54.812509 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flag [P.], seq 1:6, ack 1, win 342, opsione [nop,nop,TS val 1037001049 ecr 1037001049], gjatësi 5
10:20:55.013093 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flag [P.], seq 1:6, ack 1, win 342, opsione [nop,nop,TS val 1037001250 ecr 1037001049], gjatësi 5
10:20:55.013122 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flag [.], ack 6, win 342, opsione [nop,nop,TS val 1037001250 ecr 1037001250], gjatësi 0
10:20:55.014681 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flag [P.], seq 1:15, ack 6, win 342, opsione [nop,nop,TS val 1037001251 ecr 1037001250], gjatësi 14
10:20:55.014745 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flag [.], ack 15, win 340, opsione [nop,nop,TS val 1037001251 ecr 1037001251], gjatësi 0
10:20:55.014823 IP 127.0.0.1.43666 > 127.0.0.5.12345: Flag [F.], seq 2023663776, ack 2104268059, win 342, opsione [nop,nop,TS val 1037001251 ecr 1037001251], gjatësi 0
10:20:55.214088 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flag [P.], seq 1:15, ack 6, win 342, opsione [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]
10:20:55.416087 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flag [F.], seq 6, ack 15, win 342, opsione [nop,nop,TS val 1037001653 ecr 1037001251], gjatësi 0
10:20:55.416804 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flag [F.], seq 15, ack 7, win 342, opsione [nop,nop,TS val 1037001653 ecr 1037001653], gjatësi 0
10:20:55.416818 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flag [.], ack 16, win 343, opsione [nop,nop,TS val 1037001653 ecr 1037001653], gjatësi 0
10:20:56.147086 IP 127.0.0.1.12345 > 127.0.0.1.43666: Flag [F.], seq 15, ack 7, win 342, opsione [nop,nop,TS val 1037002384 ecr 1037001653], gjatësi 0
10:20:56.147101 IP 127.0.0.1.43666 > 127.0.0.1.12345: Flag [.], ack 16, win 342, opsione [nop,nop,TS val 1037002384 ecr 1037001653], gjatësi 0
Është e dukshme se disa paketa janë dërguar përsëri dhe ka një paketë me metadata të dëmtuara: options [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]>. Por gjëja kryesore është që përfundimisht gjithçka funksionoi siç duhej — TCP përmbushi 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 paketave
Mund të përzihen paketat, dhe kjo mund të bëhet në dy mënyra.
Në të parën, një pjesë e paketave dërgohet menjëherë, ndonjëra — me një vonesë të caktuar. Një shembull nga dokumentacioni:
tc qdisc change dev lo root netem delay 10ms reorder 25% 50%
Me një probabilitet prej 25% (dhe korrelacion 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 N-të paketë dërgohet menjëherë me një probabilitet të caktuar (dhe korrelacion), ndërsa të tjerat — me një vonesë të caktuar. Një shembull nga dokumentacioni:
tc qdisc change dev lo root netem delay 10ms reorder 25% 50% gap 5
Çdo e pesta paketë me një probabilitet prej 25% do të dërgohet pa vonesë.
Ndryshimi i kapacitetit
Për zakonisht dërgohen , por me ndihmën e netem mund të ndryshohet kapaciteti i ndërfaqes:
tc qdisc change dev lo root netem rate 56kbit
Ky komandë do t'i bëjë vizitat në localhost po aq torturuese sa surfing në internet përmes një modem dial-up. Përveç caktimit të bitrate-it, gjithashtu mund të imitohet modeli i protokollit të nivelit të kanaleve: të caktohet overhead për paketën, madhësia e qelizës dhe overhead për qelizën. Për shembull, në këtë mënyrë mund të imitohet dhe bitrate 56 kbit/sec.:
tc qdisc change dev lo root netem rate 56kbit 0 48 5
Imitim i connection timeout
Një pikë tjetër e rëndësishme në planin e testimit gjatë pranimit të softuerit — timeout-et. Kjo është e rëndësishme, sepse në sistemet e shpërndara, kur një nga shërbimet ndërpritet, të tjerat duhet të kalojnë në kohë në shërbime të tjera ose të kthejnë një gabim për klientin, përndryshe nuk duhet kurrsesi të ngecin duke pritur përgjigje ose krijimin e një lidhjeje.
Ka disa mënyra për ta bërë këtë: për shembull, përdorimi i një moku, i cili nuk përgjigjet, ose lidhja në një proces me anë të një debagger-i, duke vendosur një breakpoint në vendin e duhur dhe ndalur ekzekutimin e procesit (kjo, ndoshta, është mënyra më e çmendur). Por një nga mënyrat më të dukshme — është të bllokosh portet ose hostet. Në këtë do të na ndihmojë .
Për demonstrim, do të mbrojmë portin 12345 dhe do të ekzekutojmë skriptin tonë të klientit. Mund të mbrojmë paketat dalëse në këtë port te dërguesi ose ato hyrëse në pranues. Në shembujt e mi, do të mbrohen paketat hyrëse (duke përdorur chain INPUT dhe opsionin —dport). Të tilla paketa mund të bëhen DROP, REJECT ose REJECT me flamurin TCP RST, mund të dërgohet me ICMP host unreachable (në të vërtetë, komportimi default është icmp-port-unreachable, dhe ka gjithashtu mundësinë për të dërguar përgjigje me 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
Nisni klientin dhe shihni se çfarë ndodh, ai ngec në fazën e lidhjes me serverin. Shihni trafikun:
Dump i trafikut
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: output-i detajuar është reduktuar, përdorni -v ose -vv për dekodimin e plotë të protokollit
po përgjohet në lo, lloji i lidhjes EN10MB (Ethernet), madhësia e kapjes 262144 bajt
08:28:20.213506 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flamuj [S], seq 3019694933, win 43690, opsionet [mss 65495,sackOK,TS val 1203046450 ecr 0,nop,wscale 7], gjatësi 0
08:28:21.215086 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flamuj [S], seq 3019694933, win 43690, opsionet [mss 65495,sackOK,TS val 1203047452 ecr 0,nop,wscale 7], gjatësi 0
08:28:23.219092 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flamuj [S], seq 3019694933, win 43690, opsionet [mss 65495,sackOK,TS val 1203049456 ecr 0,nop,wscale 7], gjatësi 0
08:28:27.227087 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flamuj [S], seq 3019694933, win 43690, opsionet [mss 65495,sackOK,TS val 1203053464 ecr 0,nop,wscale 7], gjatësi 0
08:28:35.235102 IP 127.0.0.1.32856 > 127.0.0.1.12345: Flamuj [S], seq 3019694933, win 43690, opsionet [mss 65495,sackOK,TS val 1203061472 ecr 0,nop,wscale 7], gjatësi 0
E duket se klienti dërgon paketa SYN me një kohë MATURIMI që rritet eksponencialisht. Këtu gjetëm një bug të vogël në klient: duhet të përdorim metodën settimeout(), për të kufizuar kohën brenda të cilës klienti do të përpiqet të lidhë me serverin.
Menjëherë heqim rregullin:
iptables -D INPUT -p tcp --dport 12345 -j DROPMund të hiqni gjithashtu të gjitha rregullat:
iptables -F
Nëse po përdorni Docker dhe ju nevojitet të mbrojnë të gjithë trafikun që po shkon në kontejner, mund ta bëni këtë në mënyrë të tillë:
iptables -I DOCKER-USER -p tcp -d CONTAINER_IP -j DROP
REJECT
Tani, le të shtojmë një rregull të ngjashëm, por me REJECT:
iptables -A INPUT -p tcp --dport 12345 -j REJECT
Klienti ndalet pas një sekonde me gabimin [Errno 111] Connection refused. Shihni trafikun ICMP:
[user@host ~]# tcpdump -i lo -nn icmp
tcpdump: output-i detajuar është reduktuar, përdorni -v ose -vv për dekodimin e plotë të protokollit
po përgjohet në lo, lloji i lidhjes EN10MB (Ethernet), madhësia e kapjes 262144 bajt
08:45:32.871414 IP 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 tcp port 12345 unreachable, gjatësi 68
08:45:33.873097 IP 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 tcp port 12345 unreachable, gjatësi 68
E duket se klienti ka marrë dy herë port unreachable dhe pas kësaj përfundoi me gabim.
REJECT me tcp-reset
Le të përpiqemi 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 një gabim, sepse për herë të parë mori një paketë RST:
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: output i hollësishëm i shtypur, përdorni -v ose -vv për dekodimin e plotë të protokollit
po dëgjohet në lo, lloji i lidhjes EN10MB (Ethernet), madhësia e kapjes 262144 bite
09:02:52.766175 IP 127.0.0.1.60658 > 127.0.0.1.12345: Flags [S], seq 1889460883, win 43690, opsione [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
Le 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 ndalet pas një sekonde me gabimin [Errno 113] Nuk ka rrugë për në host, në trafikun ICMP shohim ICMP host 127.0.0.1 i paarrirshëm.
Mund të provoni gjithashtu parametrat e tjerë të REJECT, por unë do të ndalem te këto 🙂
Simulojmë request timeout
Një situatë tjetër është kur klienti ka arritur të lidhet me serverin, por nuk mund të dërgojë atij një kërkesë. Si t'i filtrojmë paketat që filtrimi të fillojë si të mos bëhet menjëherë? Nëse shikoni në trafikun e çdo komunikimi midis klientit dhe serverit, mund të vëreni se gjatë krijimit të lidhjes përdoren vetëm flamujt SYN dhe ACK, ndërsa gjatë shkëmbimit të të dhënave në paketën përfundimtare të kërkesës do të ketë flamurin PSH. Ai vendoset automatikisht për të shmangur buferimin. Mund të përdorni këtë informacion për të krijuar një filtr: ai do të kalojë të gjitha paketat, përveç atyre që përmbajnë flamurin PSH. Në këtë mënyrë, lidhja do të vendoset, por klienti nuk do të mund të dërgojë të dhëna te serveri.
DROP
Për DROP, komanda do të duket kështu:
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j DROP
Nisim klientin dhe shohim trafikun:
Dump i trafikut
[user@host ~]# tcpdump -i lo -nn port 12345
tcpdump: output i hollësishëm i shtypur, përdorni -v ose -vv për dekodimin e plotë të protokollit
po dëgjohet në lo, lloji i lidhjes EN10MB (Ethernet), madhësia e kapjes 262144 bite
10:02:47.549498 IP 127.0.0.1.49594 > 127.0.0.1.12345: Flags [S], seq 2166014137, win 43690, opsione [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: Flags [S.], seq 2341799088, ack 2166014138, win 43690, opsione [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: Flags [.], ack 1, win 342, opsione [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: Flags [P.], seq 1:6, ack 1, win 342, opsione [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: Flags [P.], seq 1:6, ack 1, win 342, opsione [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: Flags [P.], seq 1:6, ack 1, win 342, opsione [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: Flags [P.], seq 1:6, ack 1, win 342, opsione [nop,nop,TS val 1208714591 ecr 1208713786], gjatësi 5
Vërejmë se lidhja është vendosur dhe klienti nuk mund të dërgojë të dhëna në server.
REJECT
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 tcp port 12345 i paarritshëm dhe do të rrisë kohën ndërmjet rinisjes së kërkesës në eksponencial. Komanda duket kështu:
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j REJECT
REJECT me tcp-reset
Komanda duket si më poshtë:
iptables -A INPUT -p tcp --tcp-flags PSH PSH --dport 12345 -j REJECT --reject-with tcp-reset
Ne tashmë e dimë se gjatë përdorimit —reject-with tcp-reset klienti do të marrë një paketë RST si përgjigje, kështu që mund të parashikojmë sjelljen: marrja e paketës RST gjatë një lidhjeje të vendosur do të thotë mbyllje të papritur të soketit nga ana tjetër, pra, klienti duhet të marrë Connection reset by peer. Aktivizojmë skriptin tonë dhe e konfirmojmë këtë. Ja si do të duket trafiku:
Dump i trafikut
[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 me icmp-host-unreachable
Mendoj se tashmë është e qartë për të gjithë se si do të duket komanda 🙂 Sjellja e klientit në këtë rast do të ndryshojë pak nga ajo që ishte me REJECT të zakonshëm: klienti nuk do të rrisë timeout-in ndërmjet përpjekjeve për të rinisur paketën.
[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 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 i paarritshë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ërfundimi
Nuk është e nevojshme të shkruani një mock për të testuar ndërveprimin e shërbimit me një klient ose server të ngjitur, ndonjëherë mjafton të përdorni utilitarët standard që ekzistojnë në Linux.
Utilitet që janë shqyrtuar në këtë artikull kanë më shumë mundësi sesa është përshkruar, prandaj mund të gjeni disa variante të përdorimit të tyre. Personalish, gjithmonë më mjafton ajo që kam shkruar (në të vërtetë edhe më pak). Nëse i përdorni këto ose të ngjashme utilitete në testimin në kompaninë tuaj, ju lutem tregoni se si pikërisht. Nëse jo, shpresoj që software-i juaj do të bëhet më i mirë, nëse vendosni t'i testoni në kushte të vështira rrjetesh me metodat e propozuara.
Burimi: habr.com
