Ցանցային խնդիրների մոդելավորում Linux-ում

Ողջույն բոլորին, իմ անունը Սաշա է, ես ղեկավարում եմ Backend-ի թեստավորում FunCorp-ում: Մենք, ինչպես շատ ուրիշներ, ներդրել ենք սպասարկման վրա հիմնված ճարտարապետություն: Սա մի կողմից հեշտացնում է աշխատանքը, քանի որ... Ավելի հեշտ է յուրաքանչյուր ծառայություն առանձին թեստավորել, բայց մյուս կողմից անհրաժեշտություն կա փորձարկել ծառայությունների փոխազդեցությունը միմյանց հետ, ինչը հաճախ տեղի է ունենում ցանցի միջոցով։

Այս հոդվածում ես կխոսեմ երկու կոմունալ ծառայությունների մասին, որոնք կարող են օգտագործվել հիմնական սցենարները ստուգելու համար, որոնք նկարագրում են հավելվածի աշխատանքը ցանցային խնդիրների առկայության դեպքում:

Ցանցային խնդիրների մոդելավորում Linux-ում

Ցանցային խնդիրների մոդելավորում

Սովորաբար, ծրագրակազմը փորձարկվում է լավ ինտերնետ կապով թեստային սերվերների վրա: Արտադրական կոշտ միջավայրում ամեն ինչ կարող է այնքան էլ հարթ չլինել, այնպես որ երբեմն անհրաժեշտ է փորձարկել ծրագրերը վատ կապի պայմաններում: Linux-ում կոմունալը կօգնի նման պայմանների մոդելավորման առաջադրանքին tc.

tc(կրճատ Traffic Control-ից) թույլ է տալիս կարգավորել ցանցային փաթեթների փոխանցումը համակարգում: Այս կոմունալն ունի մեծ հնարավորություններ, կարող եք ավելին կարդալ դրանց մասին այստեղ. Այստեղ ես կդիտարկեմ դրանցից միայն մի քանիսը. մեզ հետաքրքրում է երթևեկության ժամանակացույցը, որի համար մենք օգտագործում ենք qdisc, և քանի որ մենք պետք է ընդօրինակենք անկայուն ցանցը, մենք կօգտագործենք դասակարգային qdisc netem.

Եկեք գործարկենք echo սերվեր սերվերի վրա (ես օգտագործել եմ nmap-ncat):

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

Հաճախորդի և սերվերի միջև փոխազդեցության յուրաքանչյուր քայլում բոլոր ժամանակային դրոշմները մանրամասն ցուցադրելու համար ես գրել եմ Python-ի մի պարզ սցենար, որը հարցում է ուղարկում: փորձարկում մեր echo սերվերին:

Հաճախորդի աղբյուրի կոդը

#!/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

Եկեք գործարկենք այն և նայենք ինտերֆեյսի տրաֆիկին lo և նավահանգիստ 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

Ճանապարհային աղբանոց

[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

Ամեն ինչ ստանդարտ է. եռակողմ ձեռքսեղմում, PSH/ACK և ACK երկու անգամ ի պատասխան՝ սա խնդրանքի և պատասխանի փոխանակում է հաճախորդի և սերվերի միջև, և FIN/ACK և ACK երկու անգամ՝ ավարտելով կապը:

Փաթեթի հետաձգում

Հիմա եկեք ուշացումը դնենք 500 միլիվայրկյան.

tc qdisc add dev lo root netem delay 500ms

Մենք գործարկում ենք հաճախորդը և տեսնում ենք, որ սցենարն այժմ աշխատում է 2 վայրկյան.

[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

Ի՞նչ կա երթևեկության մեջ: Եկեք նայենք.

Ճանապարհային աղբանոց

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

Դուք կարող եք տեսնել, որ սպասվող կես վայրկյանի հետաձգումը հայտնվել է հաճախորդի և սերվերի փոխազդեցության մեջ: Համակարգն իրեն շատ ավելի հետաքրքիր է պահում, եթե հետաձգումն ավելի մեծ է. միջուկը սկսում է նորից ուղարկել որոշ TCP փաթեթներ: Եկեք փոխենք ուշացումը 1 վայրկյանի և նայենք տրաֆիկին (չեմ ցուցադրի հաճախորդի ելքը, կան սպասվող 4 վայրկյան ընդհանուր տևողությամբ).

tc qdisc change dev lo root netem delay 1s

Ճանապարհային աղբանոց

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

Կարելի է տեսնել, որ հաճախորդը երկու անգամ ուղարկել է SYN փաթեթ, իսկ սերվերը երկու անգամ ուղարկել է SYN/ACK:

Ի հավելումն հաստատուն արժեքի, ուշացումը կարող է սահմանվել շեղման, բաշխման ֆունկցիայի և հարաբերակցության (նախորդ փաթեթի արժեքի հետ): Դա արվում է հետևյալ կերպ.

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

Այստեղ մենք սահմանել ենք ուշացումը 100-ից 900 միլիվայրկյանների միջև, արժեքները կընտրվեն ըստ նորմալ բաշխման և կլինի 50% հարաբերակցություն նախորդ փաթեթի հետաձգման արժեքի հետ:

Դուք, հավանաբար, նկատել եք, որ իմ օգտագործած առաջին հրամանում ավելացնելեւ հետո փոփոխություն. Այս հրամանների իմաստը ակնհայտ է, ուստի ես պարզապես կավելացնեմ, որ կա ավելին որ, որը կարող է օգտագործվել կոնֆիգուրացիան հեռացնելու համար:

Փաթեթի կորուստ

Եկեք հիմա փորձենք անել փաթեթների կորուստ: Ինչպես երևում է փաստաթղթերից, դա կարելի է անել երեք եղանակով՝ պատահականորեն կորցնել փաթեթներ՝ որոշակի հավանականությամբ, օգտագործելով 2, 3 կամ 4 վիճակների Մարկովյան շղթա՝ փաթեթների կորուստը հաշվարկելու համար, կամ օգտագործելով Էլիոթ-Գիլբերտ մոդելը: Հոդվածում ես կքննարկեմ առաջին (ամենապարզ և ակնհայտ) մեթոդը, և դուք կարող եք կարդալ մյուսների մասին այստեղ.

Եկեք կատարենք փաթեթների 50% կորուստը 25% հարաբերակցությամբ.

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

Ցավոք սրտի, tcpdump չի կարողանա մեզ հստակ ցույց տալ փաթեթների կորուստը, մենք միայն կենթադրենք, որ այն իսկապես աշխատում է: Եվ սցենարի ավելացած և անկայուն գործարկման ժամանակը կօգնի մեզ ստուգել դա: client.py (կարող է լրացվել ակնթարթորեն, կամ գուցե 20 վայրկյանում), ինչպես նաև վերահաղորդվող փաթեթների քանակի ավելացում.

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

Փաթեթներին աղմուկի ավելացում

Բացի փաթեթների կորստից, դուք կարող եք մոդելավորել փաթեթի վնասը. աղմուկը կհայտնվի պատահական փաթեթի դիրքում: Եկեք փաթեթի վնաս հասցնենք 50% հավանականությամբ և առանց հարաբերակցության.

tc qdisc change dev lo root netem corrupt 50%

Մենք գործարկում ենք հաճախորդի սկրիպտը (այնտեղ ոչ մի հետաքրքիր բան չկա, բայց ավարտելու համար պահանջվեց 2 վայրկյան), նայեք տրաֆիկին.

Ճանապարհային աղբանոց

[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

Կարելի է տեսնել, որ որոշ փաթեթներ բազմիցս ուղարկվել են, և կա մեկ փաթեթ կոտրված մետատվյալներով. տարբերակներ [nop,unknown-65 0x0a3dcf62eb3d,[bad opt]>. Բայց գլխավորն այն է, որ ի վերջո ամեն ինչ ճիշտ աշխատեց. TCP-ն հաղթահարեց իր խնդիրը:

Փաթեթների կրկնօրինակում

Էլ ինչով կարող ես անել netem? Օրինակ, մոդելավորեք փաթեթների կորստի հակառակ իրավիճակը՝ փաթեթների կրկնօրինակում: Այս հրամանը վերցնում է նաև 2 արգումենտ՝ հավանականություն և հարաբերակցություն:

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

Փաթեթների հերթականության փոփոխություն

Դուք կարող եք խառնել տոպրակները երկու եղանակով.

Առաջինում որոշ փաթեթներ ուղարկվում են անմիջապես, մնացածը՝ սահմանված ուշացումով։ Փաստաթղթից օրինակ.

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

25% հավանականությամբ (և 50% հարաբերակցությամբ) փաթեթը կուղարկվի անմիջապես, մնացածը կուղարկվի 10 միլիվայրկյան ուշացումով։

Երկրորդ մեթոդն այն է, երբ յուրաքանչյուր N-րդ փաթեթ ուղարկվում է ակնթարթորեն՝ տվյալ հավանականությամբ (և հարաբերակցությամբ), իսկ մնացածը՝ որոշակի ուշացումով: Փաստաթղթից օրինակ.

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

Յուրաքանչյուր հինգերորդ փաթեթն առանց ուշացման ուղարկելու 25% հավանականություն ունի:

Փոխելով թողունակությունը

Սովորաբար ամենուր, որտեղ նրանք վերաբերում են TBF, բայց օգնությամբ netem Կարող եք նաև փոխել ինտերֆեյսի թողունակությունը.

tc qdisc change dev lo root netem rate 56kbit

Այս թիմը շրջագայություններ կանի շուրջը localhost նույնքան ցավոտ, որքան համացանցում դիալ-ափ մոդեմի միջոցով ճամփորդելը: Բացի բիթերի արագությունը սահմանելուց, դուք կարող եք նաև ընդօրինակել կապի շերտի արձանագրության մոդելը. սահմանել փաթեթի վերին ծախսը, բջջի չափը և բջջի վերին ծախսը: Օրինակ, սա կարելի է մոդելավորել Բանկոմատը և բիթային արագություն 56 կբիթ/վրկ:

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

Միացման ժամանակի սիմուլյացիա

Փորձարկման պլանի մեկ այլ կարևոր կետ, երբ ընդունում եք ծրագրակազմը, ժամանակի ընդհատումն է: Սա կարևոր է, քանի որ բաշխված համակարգերում, երբ ծառայություններից մեկն անջատված է, մյուսները պետք է ժամանակին վերադառնան մյուսներին կամ սխալը վերադարձնեն հաճախորդին, և ոչ մի դեպքում չպետք է պարզապես կախվեն՝ սպասելով պատասխանի կամ կապի։ ստեղծվելիք։

Դա անելու մի քանի եղանակ կա. օրինակ՝ օգտագործեք ծաղր, որը չի արձագանքում, կամ միացեք պրոցեսին՝ օգտագործելով վրիպազերծիչ, ճիշտ տեղում տեղադրեք ընդմիջման կետ և դադարեցրեք գործընթացը (սա թերևս ամենաայլասերված ձևն է): Բայց ամենաակնհայտներից մեկը firewall նավահանգիստները կամ հոսթներն են: Դա մեզ կօգնի այս հարցում iptables.

Ցուցադրման համար մենք կփակենք 12345 նավահանգիստը և գործարկենք մեր հաճախորդի սկրիպտը: Դուք կարող եք firewall ելքային փաթեթները ուղարկել այս նավահանգիստին կամ մուտքային փաթեթները ստացողի մոտ: Իմ օրինակներում մուտքային փաթեթները կփակվեն (մենք օգտագործում ենք շղթայական INPUT և տարբերակը --դպորտ) Նման փաթեթները կարող են լինել DROP, REJECT կամ REJECT TCP դրոշակով RST, կամ ICMP հոսթինգի անհասանելի (իրականում լռելյայն վարքագիծն է. icmp-port-անհասանելի, և կա նաև պատասխան ուղարկելու հնարավորություն icmp-net- անհասանելի, icmp-proto-անհասանելի, icmp-net- արգելված է и icmp-host-արգելվում է).

Իջնել

Եթե ​​կա DROP-ի կանոն, փաթեթները պարզապես «կվերանան»:

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

Մենք գործարկում ենք հաճախորդը և տեսնում ենք, որ այն սառչում է սերվերին միանալու փուլում։ Եկեք նայենք երթևեկությանը.
Ճանապարհային աղբանոց

[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

Կարելի է տեսնել, որ հաճախորդը ուղարկում է SYN փաթեթներ՝ էքսպոնենցիալ աճող ժամանակով: Այսպիսով, մենք հաճախորդի մոտ գտանք մի փոքր սխալ. դուք պետք է օգտագործեք մեթոդը settimeout ()սահմանափակել այն ժամանակը, որի ընթացքում հաճախորդը կփորձի միանալ սերվերին:

Մենք անմիջապես հանում ենք կանոնը.

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

Դուք կարող եք միանգամից ջնջել բոլոր կանոնները.

iptables -F

Եթե ​​դուք օգտագործում եք Docker-ը և ձեզ անհրաժեշտ է firewall-ել դեպի կոնտեյներ գնացող ամբողջ տրաֆիկը, ապա կարող եք դա անել հետևյալ կերպ.

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

Մերժել

Հիմա եկեք ավելացնենք նմանատիպ կանոն, բայց REJECT-ով.

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

Հաճախորդը մի վայրկյանից դուրս է գալիս սխալմամբ [Errno 111] Միացումը մերժվեց. Եկեք նայենք 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

Երևում է, որ հաճախորդը ստացել է երկու անգամ նավահանգիստը անհասանելի է իսկ հետո ավարտվեց սխալմամբ:

ՄԵՐԺԵԼ tcp-reset-ով

Փորձենք ավելացնել տարբերակը -- մերժել-tcp-reset-ով:

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

Այս դեպքում հաճախորդը անմիջապես դուրս է գալիս սխալով, քանի որ առաջին հարցումը ստացել է 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

ՄԵՐԺԵԼ icmp-host-unreachable-ով

Փորձենք REJECT-ի օգտագործման մեկ այլ տարբերակ.

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

Հաճախորդը մի վայրկյանից դուրս է գալիս սխալմամբ [Errno 113] հյուրընկալող երթուղի չկա, մենք տեսնում ենք ICMP տրաֆիկում ICMP հյուրընկալող 127.0.0.1 անհասանելի է.

Կարող եք նաև փորձել REJECT-ի մյուս պարամետրերը, և ես կկենտրոնանամ դրանց վրա :)

Հարցման ժամկետի սիմուլյացիա

Մեկ այլ իրավիճակ է, երբ հաճախորդը կարողացել է միանալ սերվերին, բայց չի կարող նրան հարցում ուղարկել: Ինչպե՞ս զտել փաթեթները, որպեսզի զտումը անմիջապես չսկսվի: Եթե ​​նայեք հաճախորդի և սերվերի միջև ցանկացած հաղորդակցության երթևեկությանը, ապա կնկատեք, որ կապ հաստատելիս օգտագործվում են միայն SYN և ACK դրոշները, սակայն տվյալների փոխանակման ժամանակ վերջին հարցման փաթեթը կպարունակի PSH դրոշը: Այն տեղադրվում է ավտոմատ կերպով՝ բուֆերացումից խուսափելու համար: Դուք կարող եք օգտագործել այս տեղեկատվությունը զտիչ ստեղծելու համար. այն թույլ կտա բոլոր փաթեթները, բացառությամբ PSH դրոշ պարունակող փաթեթների: Այսպիսով, կապը կհաստատվի, բայց հաճախորդը չի կարողանա տվյալներ ուղարկել սերվեր:

Իջնել

DROP-ի համար հրամանը կունենա հետևյալ տեսքը.

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

Գործարկեք հաճախորդը և դիտեք երթևեկությունը.

Ճանապարհային աղբանոց

[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

Մենք տեսնում ենք, որ կապը հաստատված է, և հաճախորդը չի կարող տվյալներ ուղարկել սերվերին:

Մերժել

Այս դեպքում վարքագիծը նույնն է լինելու՝ հաճախորդը չի կարողանա հարցումն ուղարկել, այլ ստանալ ICMP 127.0.0.1 tcp պորտ 12345 անհասանելի է և երկրաչափականորեն մեծացնել հարցումների վերաներկայացման միջև ընկած ժամանակը: Հրամանն այսպիսի տեսք ունի.

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

ՄԵՐԺԵԼ tcp-reset-ով

Հրամանն այսպիսի տեսք ունի.

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

Մենք դա արդեն գիտենք օգտագործելիս -- մերժել-tcp-reset-ով հաճախորդը ի պատասխան կստանա RST փաթեթ, ուստի վարքագիծը կարելի է կանխատեսել. 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
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

ՄԵՐԺԵԼ icmp-host-unreachable-ով

Կարծում եմ, բոլորի համար արդեն ակնհայտ է, թե ինչ տեսք կունենա հրամանը :) Հաճախորդի վարքագիծն այս դեպքում մի փոքր կտարբերվի պարզ ՄԵՐԺՈՒՄով. հաճախորդը չի ավելացնի փաթեթը նորից ուղարկելու փորձերի միջև ընկած ժամանակահատվածը:

[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

Արտադրողականություն

Անհրաժեշտ չէ ծաղր գրել՝ կախված հաճախորդի կամ սերվերի հետ ծառայության փոխազդեցությունը ստուգելու համար, երբեմն բավական է օգտագործել Linux-ում հայտնաբերված ստանդարտ կոմունալ ծառայությունները:

Հոդվածում քննարկված կոմունալ ծառայություններն ունեն նույնիսկ ավելի շատ հնարավորություններ, քան նկարագրված էին, այնպես որ կարող եք դրանք օգտագործելու ձեր որոշ տարբերակներ առաջարկել: Անձամբ ես միշտ բավարարում եմ այն, ինչի մասին գրել եմ (իրականում նույնիսկ ավելի քիչ): Եթե ​​դուք օգտագործում եք այս կամ նմանատիպ կոմունալ ծառայությունները ձեր ընկերությունում փորձարկման ժամանակ, խնդրում ենք գրել, թե կոնկրետ ինչպես: Եթե ​​ոչ, ապա հուսով եմ, որ ձեր ծրագրակազմը կդառնա ավելի լավը, եթե որոշեք այն փորձարկել ցանցային խնդիրների պայմաններում՝ օգտագործելով առաջարկվող մեթոդները:

Source: www.habr.com

Добавить комментарий