Simulimi i problemeve të rrjetit në Linux

Përshëndetje të gjithëve, emri im është Sasha, unë drejtoj testimin e backend-it në FunCorp. Ne, si shumë të tjerë, kemi zbatuar një arkitekturë të orientuar drejt shërbimit. Nga njëra anë, kjo e thjeshton punën, sepse... Është më e lehtë për të testuar secilin shërbim veç e veç, por nga ana tjetër, ekziston nevoja për të testuar ndërveprimin e shërbimeve me njëri-tjetrin, gjë që shpesh ndodh përmes rrjetit.

Në këtë artikull, unë do të flas për dy shërbime që mund të përdoren për të kontrolluar skenarët bazë që përshkruajnë funksionimin e një aplikacioni në prani të problemeve të rrjetit.

Simulimi i problemeve të rrjetit në Linux

Simulimi i problemeve të rrjetit

Në mënyrë tipike, softueri testohet në serverët e testimit me një lidhje të mirë në internet. Në mjedise të vështira prodhimi, gjërat mund të mos jenë aq të qetë, kështu që ndonjëherë ju duhet të testoni programet në kushte të këqija lidhjeje. Në Linux, programi do të ndihmojë me detyrën e simulimit të kushteve të tilla tc.

tc(abbr. nga Kontrolli i Trafikut) ju lejon të konfiguroni transmetimin e paketave të rrjetit në sistem. Ky mjet ka aftësi të shkëlqyera, mund të lexoni më shumë rreth tyre këtu. Këtu do të shqyrtoj vetëm disa prej tyre: ne jemi të interesuar për planifikimin e trafikut, për të cilin përdorim qdisc, dhe meqenëse duhet të imitojmë një rrjet të paqëndrueshëm, do të përdorim qdisc pa klasë netem.

Le të hapim një server echo në server (kam përdorur nmap-ncat):

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

Për të shfaqur në detaje të gjitha vulat kohore në çdo hap të ndërveprimit midis klientit dhe serverit, kam shkruar një skript të thjeshtë Python që dërgon një kërkesë Provë 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

Le ta hapim atë dhe të shikojmë trafikun në ndërfaqe lo dhe porti 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

Deponia e 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: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

Gjithçka është standarde: një shtrëngim duarsh me tre drejtime, 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 FIN/ACK dhe ACK dy herë - duke përfunduar lidhjen.

Vonesa e paketës

Tani le ta vendosim vonesën në 500 milisekonda:

tc qdisc add dev lo root netem delay 500ms

Ne nisim klientin dhe shohim që skripti tani funksionon për 2 sekonda:

[user@host ~]# ./client.py
[time before connection: 1578662612.71044]
[time after connection, before sending: 1578662613.71059]
[time after sending, before receiving: 1578662613.71065]
[time after receiving, before closing: 1578662614.72011]
[time after closing: 1578662614.72019]
[total duration: 2.00974]
Response: Test

Çfarë ka në trafik? Le të shohim:

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

Ju mund të shihni se vonesa e pritur prej gjysmë sekonde është shfaqur në ndërveprimin midis klientit dhe serverit. Sistemi sillet shumë më interesant nëse vonesa është më e madhe: kerneli fillon të ridërgojë disa paketa TCP. Le ta ndryshojmë vonesën në 1 sekondë dhe të shikojmë trafikun (nuk do të tregoj daljen e klientit, janë 4 sekondat e pritura në kohëzgjatje totale):

tc qdisc change dev lo root netem delay 1s

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

Mund të shihet se klienti dërgoi një pako SYN dy herë, dhe serveri dërgoi një SYN/ACK dy herë.

Përveç një vlere konstante, vonesa mund të vendoset në një devijim, një funksion shpërndarjeje dhe një korrelacion (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 vendosur vonesën midis 100 dhe 900 milisekonda, vlerat do të zgjidhen sipas një shpërndarjeje normale dhe do të ketë një korrelacion 50% me vlerën e vonesës për paketën e mëparshme.

Ju mund ta keni vënë re këtë në komandën e parë që përdora shtoj, dhe pastaj ndryshim. Kuptimi i këtyre komandave është i qartë, kështu që unë thjesht do të shtoj se ka më shumë del, i cili mund të përdoret për të hequr konfigurimin.

Humbja e paketave

Tani le të përpiqemi të bëjmë humbjen e paketave. Siç shihet nga dokumentacioni, kjo mund të bëhet në tre mënyra: humbja e paketave në mënyrë të rastësishme me disa probabilitete, duke përdorur një zinxhir Markov me 2, 3 ose 4 gjendje për të llogaritur humbjen e paketave, ose duke përdorur modelin Elliott-Gilbert. Në artikull do të shqyrtoj metodën e parë (më të thjeshtë dhe më të dukshme), dhe mund të lexoni për të tjerët këtu.

Le të bëjmë humbjen e 50% të paketave me një korrelacion prej 25%:

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

Për fat të keq, tcpdump nuk do të jetë në gjendje të na tregojë qartë humbjen e paketave, ne vetëm do të supozojmë se me të vërtetë funksionon. Dhe koha e shtuar dhe e paqëndrueshme e ekzekutimit të skenarit do të na ndihmojë ta verifikojmë këtë. klient.py (mund të plotësohet në çast, ose ndoshta në 20 sekonda), si dhe një numër i shtuar i paketave të ritransmetuara:

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

Shtimi i zhurmës në pako

Përveç humbjes së paketës, mund të simuloni dëmtimin e paketës: zhurma do të shfaqet në një pozicion të rastësishëm të paketës. Le të bëjmë dëmtim të paketës me një probabilitet 50% dhe pa korrelacion:

tc qdisc change dev lo root netem corrupt 50%

Ne ekzekutojmë skriptin e klientit (asgjë interesante atje, por u deshën 2 sekonda për të përfunduar), shikoni trafikun:

Deponia e 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: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

Mund të shihet se disa pako janë dërguar në mënyrë të përsëritur dhe ka një pako me meta të dhëna të prishura: opsionet [jo, e panjohur-65 0x0a3dcf62eb3d,[opt i keq]>. Por gjëja kryesore është se në fund gjithçka funksionoi si duhet - TCP u përball me detyrën e saj.

Dyfishimi i paketave

Çfarë tjetër mund të bëni me netem? Për shembull, simuloni situatën e kundërt të humbjes së paketave - dyfishimi i paketave. Kjo komandë merr gjithashtu 2 argumente: probabilitetin dhe korrelacionin.

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

Ndryshimi i renditjes së paketave

Mund të përzieni qeset në dy mënyra.

Në të parën, disa pako dërgohen menjëherë, pjesa tjetër me një vonesë të caktuar. Shembull nga dokumentacioni:

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

Me një probabilitet prej 25% (dhe një korrelacion prej 50%) paketa do të dërgohet menjëherë, pjesa tjetër do të dërgohet me një vonesë prej 10 milisekonda.

Metoda e dytë është kur çdo paketë e N-të dërgohet menjëherë me një probabilitet (dhe korrelacion) të caktuar, dhe pjesa tjetër me një vonesë të caktuar. Shembull nga dokumentacioni:

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

Çdo paketë e pestë ka një shans 25% për t'u dërguar pa vonesë.

Ndryshimi i gjerësisë së brezit

Zakonisht kudo që i referohen TBF, por me ndihmën netem Ju gjithashtu mund të ndryshoni gjerësinë e brezit të ndërfaqes:

tc qdisc change dev lo root netem rate 56kbit

Ky ekip do të bëjë udhëtime përreth localhost po aq e dhimbshme sa lundrimi në internet nëpërmjet një modemi dial-up. Përveç vendosjes së shpejtësisë së biteve, mund të imitoni gjithashtu modelin e protokollit të shtresës së lidhjes: vendosni koston e përgjithshme për paketën, madhësinë e qelizës dhe koston e përgjithshme për qelizën. Për shembull, kjo mund të simulohet Bankomat dhe shpejtësia e biteve 56 kbit/sek:

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

Simulimi i skadimit të lidhjes

Një tjetër pikë e rëndësishme në planin e provës kur pranoni softuer janë afatet. Kjo është e rëndësishme sepse në sistemet e shpërndara, kur një nga shërbimet çaktivizohet, të tjerët duhet t'u kthehen të tjerëve në kohë ose t'i kthejnë një gabim klientit, dhe në asnjë rast nuk duhet thjesht të varen, duke pritur për një përgjigje ose një lidhje. të themelohet.

Ka disa mënyra për ta bërë këtë: për shembull, përdorni një tallje që nuk përgjigjet, ose lidheni me procesin duke përdorur një korrigjues, vendosni një pikë ndërprerjeje në vendin e duhur dhe ndaloni procesin (kjo është ndoshta mënyra më e çoroditur). Por një nga më të dukshmet është muri i murit të zjarrit ose hostet. Do të na ndihmojë me këtë iptables.

Për demonstrim, ne do të vendosim murin e zjarrit 12345 dhe do të ekzekutojmë skriptin tonë të klientit. Ju mund t'i fiksoni paketat dalëse në këtë port tek dërguesi ose paketat hyrëse te marrësi. Në shembujt e mi, paketat hyrëse do të kenë mur zjarri (ne përdorim zinxhirin INPUT dhe opsionin --dport). Paketa të tilla mund të jenë DROP, REJECT ose REJECT me flamurin TCP RST, ose me host ICMP të paarritshëm (në fakt, sjellja e paracaktuar është icmp-port-i paarritshëm, dhe ekziston edhe mundësia për të dërguar një përgjigje icmp-net-i paarritshëm, icmp-proto-i paarritshëm, icmp-net-i ndaluar и icmp-host-i ndaluar).

R DNI

Nëse ekziston një rregull me DROP, paketat thjesht do të "zhduken".

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

Ne lëshojmë klientin dhe shohim që ai ngrin në fazën e lidhjes me serverin. Le të shohim trafikun:
Deponia e 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
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

Mund të shihet se klienti dërgon pako SYN me një afat kohor në rritje në mënyrë eksponenciale. Pra, gjetëm një gabim të vogël te klienti: duhet të përdorni metodën settimeout ()për të kufizuar kohën gjatë së cilës klienti do të përpiqet të lidhet me serverin.

Ne heqim menjëherë rregullin:

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

Ju mund t'i fshini të gjitha rregullat menjëherë:

iptables -F

Nëse jeni duke përdorur Docker dhe duhet të izoloni të gjithë trafikun që shkon në kontejner, atëherë mund ta bëni si më poshtë:

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

REFUZOJË

Tani le të shtojmë një rregull të ngjashëm, por me REJECT:

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

Klienti del pas një sekonde me një gabim [Errno 111] Lidhja u refuzua. Le të shohim trafikun ICMP:

[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

Mund të shihet se klienti ka marrë dy herë port i paarritshëm dhe më pas përfundoi me një gabim.

REFUZOJ me tcp-rivendosje

Le të përpiqemi të shtojmë opsionin --refuzo-me tcp-rivendosje:

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 kërkesa e parë mori një paketë RST:

[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

REFUZO me icmp-host-unarritable

Le të provojmë një opsion tjetër për përdorimin e REJECT:

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

Klienti del pas një sekonde me një gabim [Errno 113] Nuk ka rrugë për të pritur, shohim në trafikun ICMP Pritësi ICMP 127.0.0.1 i paarritshëm.

Ju gjithashtu mund të provoni parametrat e tjerë REJECT, dhe unë do të fokusohem në këto :)

Simulimi i skadimit të kërkesës

Një situatë tjetër është kur klienti ishte në gjendje të lidhej me serverin, por nuk mund t'i dërgojë një kërkesë atij. Si të filtroni paketat në mënyrë që filtrimi të mos fillojë menjëherë? Nëse shikoni trafikun e çdo komunikimi ndërmjet klientit dhe serverit, do të vini re se gjatë krijimit të një lidhjeje përdoren vetëm flamujt SYN dhe ACK, por gjatë shkëmbimit të të dhënave, paketa e fundit e kërkesës do të përmbajë flamurin PSH. Instalohet automatikisht për të shmangur buferimin. Ju mund ta përdorni këtë informacion për të krijuar një filtër: 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ë jetë në gjendje të dërgojë të dhëna në server.

R DNI

Për DROP komanda do të duket kështu:

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

Nisni klientin dhe shikoni trafikun:

Deponia e 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: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

Ne shohim që lidhja është krijuar dhe klienti nuk mund të dërgojë të dhëna në server.

REFUZOJË

Në këtë rast sjellja do të jetë e njëjtë: klienti nuk do të mund ta dërgojë kërkesën, por do ta marrë Porta ICMP 127.0.0.1 tcp 12345 e paarritshme dhe rrisni kohën ndërmjet ridorëzimit të kërkesave në mënyrë eksponenciale. Komanda duket si kjo:

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

REFUZOJ me tcp-rivendosje

Komanda duket si kjo:

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

Ne tashmë e dimë këtë kur përdorim --refuzo-me tcp-rivendosje klienti do të marrë një paketë RST si përgjigje, kështu që sjellja mund të parashikohet: marrja e një pakete RST ndërsa lidhja është vendosur do të thotë se priza është mbyllur papritur në anën tjetër, që do të thotë se klienti duhet të marrë Lidhja u rivendos nga kolegët. Le të ekzekutojmë skenarin tonë dhe të sigurohemi për këtë. Dhe kështu do të duket trafiku:

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

REFUZO me icmp-host-unarritable

Unë mendoj se është tashmë e qartë për të gjithë se si do të duket komanda :) Sjellja e klientit në këtë rast do të jetë paksa e ndryshme nga ajo me një REFUZIM të thjeshtë: klienti nuk do të rrisë kohën midis përpjekjeve për të ridërguar 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 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

Prodhim

Nuk është e nevojshme të shkruani një tallje për të testuar ndërveprimin e një shërbimi me një klient ose server të varur; ndonjëherë mjafton të përdorni shërbimet standarde që gjenden në Linux.

Shërbimet e diskutuara në artikull kanë edhe më shumë aftësi sesa u përshkruan, kështu që ju mund të gjeni disa nga opsionet tuaja për përdorimin e tyre. Personalisht, gjithmonë kam mjaft nga ato që kam shkruar (në fakt, edhe më pak). Nëse përdorni këto ose shërbime të ngjashme gjatë testimit në kompaninë tuaj, ju lutemi shkruani se si saktësisht. Nëse jo, atëherë shpresoj se softueri juaj do të bëhet më i mirë nëse vendosni ta testoni atë në kushtet e problemeve të rrjetit duke përdorur metodat e sugjeruara.

Burimi: www.habr.com

Shto një koment