Simularea problemelor de rețea în Linux

Salutare tuturor, numele meu este Sasha, conduc testarea backend la FunCorp. Noi, ca mulți alții, am implementat o arhitectură orientată spre servicii. Pe de o parte, acest lucru simplifică munca, deoarece Este mai ușor să testați fiecare serviciu separat, dar, pe de altă parte, este necesar să testați interacțiunea serviciilor între ele, ceea ce are loc adesea prin rețea.

În acest articol, voi vorbi despre două utilitare care pot fi folosite pentru a verifica scenarii de bază care descriu funcționarea unei aplicații în prezența problemelor de rețea.

Simularea problemelor de rețea în Linux

Simularea problemelor de rețea

De obicei, software-ul este testat pe servere de testare cu o conexiune bună la Internet. În mediile dure de producție, lucrurile s-ar putea să nu fie atât de fluide, așa că uneori trebuie să testați programe în condiții proaste de conexiune. Pe Linux, utilitarul va ajuta la sarcina de a simula astfel de condiții tc.

tc(abr. de la Controlul Traficului) vă permite să configurați transmisia pachetelor de rețea în sistem. Acest utilitar are capacități grozave, puteți citi mai multe despre ele aici. Aici voi lua în considerare doar câteva dintre ele: ne interesează programarea traficului, pentru care folosim qdisc, și deoarece trebuie să emulăm o rețea instabilă, vom folosi qdisc fără clasă netem.

Să lansăm un server echo pe server (am folosit nmap-ncat):

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

Pentru a afișa în detaliu toate marcajele de timp la fiecare pas de interacțiune dintre client și server, am scris un script Python simplu care trimite o cerere Test la serverul nostru de eco.

Cod sursă client

#!/bin/python

import socket
import time

HOST = '127.0.0.1'
PORT = 12345
BUFFER_SIZE = 1024
MESSAGE = "Testn"

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
t1 = time.time()
print "[time before connection: %.5f]" % t1
s.connect((HOST, PORT))
print "[time after connection, before sending: %.5f]" % time.time()
s.send(MESSAGE)
print "[time after sending, before receiving: %.5f]" % time.time()
data = s.recv(BUFFER_SIZE)
print "[time after receiving, before closing: %.5f]" % time.time()
s.close()
t2 = time.time()
print "[time after closing: %.5f]" % t2
print "[total duration: %.5f]" % (t2 - t1)

print data

Să-l lansăm și să ne uităm la traficul de pe interfață lo și portul 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

Halda de trafic

[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

Totul este standard: o strângere de mână în trei căi, PSH/ACK și ACK ca răspuns de două ori - acesta este schimbul de cerere și răspuns între client și server și FIN/ACK și ACK de două ori - completând conexiunea.

Întârzierea pachetului

Acum să setăm întârzierea la 500 de milisecunde:

tc qdisc add dev lo root netem delay 500ms

Lansăm clientul și vedem că scriptul rulează acum 2 secunde:

[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

Ce este în trafic? Hai sa ne uitam:

Halda de trafic

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

Puteți vedea că întârzierea așteptată de o jumătate de secundă a apărut în interacțiunea dintre client și server. Sistemul se comportă mult mai interesant dacă decalajul este mai mare: nucleul începe să retrimită unele pachete TCP. Să modificăm întârzierea la 1 secundă și să ne uităm la trafic (nu voi afișa rezultatul clientului, sunt cele 4 secunde așteptate în durata totală):

tc qdisc change dev lo root netem delay 1s

Halda de trafic

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

Se poate observa că clientul a trimis un pachet SYN de două ori, iar serverul a trimis un pachet SYN/ACK de două ori.

Pe lângă o valoare constantă, întârzierea poate fi setată la o abatere, o funcție de distribuție și o corelație (cu valoarea pachetului anterior). Acest lucru se face după cum urmează:

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

Aici am setat întârzierea între 100 și 900 de milisecunde, valorile vor fi selectate conform unei distribuții normale și va exista o corelație de 50% cu valoarea întârzierii pentru pachetul anterior.

Poate ați observat că în prima comandă pe care am folosit-o adăuga, și apoi Schimbare. Semnificația acestor comenzi este evidentă, așa că voi adăuga doar că există mai multe del, care poate fi folosit pentru a elimina configurația.

Pierdere de pachete

Să încercăm acum să pierdem pachete. După cum se poate vedea din documentație, acest lucru se poate face în trei moduri: pierderea aleatorie a pachetelor cu o oarecare probabilitate, folosind un lanț Markov de 2, 3 sau 4 stări pentru a calcula pierderea de pachete sau folosind modelul Elliott-Gilbert. În articol voi lua în considerare prima metodă (cea mai simplă și cea mai evidentă) și puteți citi despre altele aici.

Să facem pierderea a 50% din pachete cu o corelație de 25%:

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

Din păcate, tcpdump nu va putea să ne arate clar pierderea pachetelor, vom presupune doar că funcționează cu adevărat. Și timpul de rulare crescut și instabil al scriptului ne va ajuta să verificăm acest lucru. client.py (poate fi finalizat instantaneu, sau poate în 20 de secunde), precum și un număr crescut de pachete retransmise:

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

Adăugarea de zgomot la pachete

Pe lângă pierderea pachetelor, puteți simula deteriorarea pachetului: zgomotul va apărea într-o poziție aleatorie a pachetului. Să dăunăm pachetului cu o probabilitate de 50% și fără corelație:

tc qdisc change dev lo root netem corrupt 50%

Rulăm scriptul client (nimic interesant acolo, dar a durat 2 secunde pentru a finaliza), uită-te la trafic:

Halda de trafic

[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

Se poate observa că unele pachete au fost trimise în mod repetat și există un pachet cu metadate rupte: opțiuni [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]>. Dar principalul lucru este că, în cele din urmă, totul a funcționat corect - TCP și-a făcut față sarcinii.

Dublarea pachetelor

Cu ce ​​altceva poți face netem? De exemplu, simulați situația inversă a pierderii pachetelor - duplicarea pachetelor. Această comandă are și 2 argumente: probabilitate și corelație.

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

Schimbarea ordinii pachetelor

Puteți amesteca pungile în două moduri.

În primul, unele pachete sunt trimise imediat, restul cu o întârziere specificată. Exemplu din documentație:

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

Cu o probabilitate de 25% (și o corelație de 50%) pachetul va fi trimis imediat, restul va fi trimis cu o întârziere de 10 milisecunde.

A doua metodă este atunci când fiecare al N-lea pachet este trimis instantaneu cu o probabilitate dată (și corelație), iar restul cu o întârziere dată. Exemplu din documentație:

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

Fiecare al cincilea pachet are 25% șanse de a fi trimis fără întârziere.

Modificarea lățimii de bandă

De obicei peste tot la care se referă TBF, dar cu ajutorul netem De asemenea, puteți modifica lățimea de bandă a interfeței:

tc qdisc change dev lo root netem rate 56kbit

Această echipă va face drumeții în jur localhost la fel de dureros ca navigarea pe internet printr-un modem dial-up. Pe lângă setarea ratei de biți, puteți, de asemenea, să emulați modelul de protocol al stratului de legătură: setați supraîncărcarea pentru pachet, dimensiunea celulei și supraîncărcarea pentru celulă. De exemplu, acest lucru poate fi simulat ATM și rata de biți 56 kbit/sec:

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

Simularea timpului de expirare a conexiunii

Un alt punct important în planul de testare atunci când se acceptă software-ul este expirarea timpului. Acest lucru este important deoarece în sistemele distribuite, atunci când unul dintre servicii este dezactivat, celelalte trebuie să se întoarcă în timp la celelalte sau să returneze o eroare clientului și în niciun caz nu trebuie să se blocheze pur și simplu, așteptând un răspuns sau o conexiune. a fi stabilit.

Există mai multe modalități de a face acest lucru: de exemplu, utilizați o simulare care nu răspunde sau conectați-vă la proces folosind un depanator, puneți un punct de întrerupere la locul potrivit și opriți procesul (acesta este probabil cel mai pervertit mod). Dar una dintre cele mai evidente este porturile sau gazdele firewall. Ne va ajuta cu asta iptables.

Pentru demonstrație, vom folosi firewall portul 12345 și vom rula scriptul client. Puteți să firewall pachetele de ieșire către acest port la expeditor sau pachetele de intrare la receptor. În exemplele mele, pachetele primite vor fi protejate cu firewall (folosim INPUT în lanț și opțiunea — dport). Astfel de pachete pot fi DROP, REJECT sau REJECT cu semnalul TCP RST sau cu gazda ICMP inaccesabilă (de fapt, comportamentul implicit este icmp-port-inaccesibil, și există și posibilitatea de a trimite un răspuns icmp-net-inaccesibil, icmp-proto-inaccesibil, icmp-net-interzis и icmp-gazdă-interzis).

CĂDERE BRUSCA

Dacă există o regulă cu DROP, pachetele vor „dispărea” pur și simplu.

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

Lansăm clientul și vedem că acesta se blochează în etapa de conectare la server. Să ne uităm la trafic:
Halda de trafic

[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

Se poate observa că clientul trimite pachete SYN cu un timeout care crește exponențial. Așa că am găsit un mic bug în client: trebuie să utilizați metoda settimeout()pentru a limita timpul în care clientul va încerca să se conecteze la server.

Înlăturăm imediat regula:

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

Puteți șterge toate regulile simultan:

iptables -F

Dacă utilizați Docker și trebuie să faceți un firewall pentru tot traficul care merge către container, atunci puteți face acest lucru după cum urmează:

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

RESPINGE

Acum să adăugăm o regulă similară, dar cu REJECT:

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

Clientul iese după o secundă cu o eroare [Errno 111] Conexiune refuzată. Să ne uităm la traficul 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

Se vede că clientul a primit de două ori port inaccesibil și apoi s-a încheiat cu o eroare.

REJECT cu tcp-reset

Să încercăm să adăugăm opțiunea --reject-with tcp-reset:

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

În acest caz, clientul iese imediat cu o eroare, deoarece prima solicitare a primit un pachet 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

REJECT cu icmp-host-unreachable

Să încercăm o altă opțiune pentru utilizarea REJECT:

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

Clientul iese după o secundă cu o eroare [Errno 113] Nicio rută către gazdă, vedem în traficul ICMP Gazda ICMP 127.0.0.1 inaccesibil.

Puteți încerca și ceilalți parametri REJECT și mă voi concentra pe aceștia :)

Simularea timpului de expirare a cererii

O altă situație este atunci când clientul s-a putut conecta la server, dar nu poate trimite o cerere către acesta. Cum se filtrează pachetele, astfel încât filtrarea să nu înceapă imediat? Dacă te uiți la traficul oricărei comunicări între client și server, vei observa că la stabilirea unei conexiuni se folosesc doar steagurile SYN și ACK, dar la schimbul de date, ultimul pachet de solicitare va conține flag-ul PSH. Se instalează automat pentru a evita tamponarea. Puteți utiliza aceste informații pentru a crea un filtru: va permite toate pachetele, cu excepția celor care conțin indicatorul PSH. Astfel, se va stabili conexiunea, dar clientul nu va putea trimite date către server.

CĂDERE BRUSCA

Pentru DROP comanda ar arăta astfel:

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

Lansați clientul și urmăriți traficul:

Halda de trafic

[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

Vedem că conexiunea este stabilită și clientul nu poate trimite date către server.

RESPINGE

În acest caz, comportamentul va fi același: clientul nu va putea trimite cererea, dar va primi Portul ICMP 127.0.0.1 tcp 12345 inaccesibil și crește exponențial timpul dintre retrimiterea cererilor. Comanda arată astfel:

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

REJECT cu tcp-reset

Comanda arată astfel:

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

Știm deja asta atunci când folosim --reject-with tcp-reset clientul va primi un pachet RST ca răspuns, astfel încât comportamentul poate fi prezis: primirea unui pachet RST în timp ce conexiunea este stabilită înseamnă că socket-ul este închis în mod neașteptat pe cealaltă parte, ceea ce înseamnă că clientul ar trebui să primească Resetare Conexiune de la egal la egal. Să rulăm scriptul și să ne asigurăm de asta. Și așa va arăta traficul:

Halda de trafic

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

Cred că este deja evident pentru toată lumea cum va arăta comanda :) Comportamentul clientului în acest caz va fi ușor diferit de cel cu o simplă RESPINGERE: clientul nu va crește timpul de expirare dintre încercările de a retrimite pachetul.

[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

Producție

Nu este necesar să scrieți o simulare pentru a testa interacțiunea unui serviciu cu un client sau un server suspendat, uneori este suficient să folosiți utilități standard găsite în Linux.

Utilitarele discutate în articol au și mai multe capacități decât au fost descrise, așa că puteți veni cu unele dintre propriile opțiuni de utilizare a acestora. Personal, întotdeauna am destul de ceea ce am scris (de fapt, chiar mai puțin). Dacă utilizați aceste utilități sau similare în testarea companiei dvs., vă rugăm să scrieți cum exact. Dacă nu, atunci sper că software-ul dumneavoastră va deveni mai bun dacă decideți să-l testați în condiții de probleme de rețea folosind metodele sugerate.

Sursa: www.habr.com

Adauga un comentariu