අපි XDP මත DDoS ප්‍රහාර වලින් ආරක්ෂාව ලියන්නෙමු. න්යෂ්ටික කොටස

eXpress Data Path (XDP) තාක්‍ෂණය මඟින් පැකට් කර්නල් ජාල තොගයට ඇතුළු වීමට පෙර ලිනක්ස් අතුරුමුහුණත් මත අහඹු ගමනාගමන සැකසුම් සිදු කිරීමට ඉඩ සලසයි. XDP යෙදුම - DDoS ප්‍රහාර වලින් ආරක්ෂා වීම (CloudFlare), සංකීර්ණ පෙරහන්, සංඛ්‍යාලේඛන එකතුව (Netflix). XDP වැඩසටහන් ක්‍රියාත්මක කරනු ලබන්නේ eBPF අතථ්‍ය යන්ත්‍රය මගිනි, එබැවින් පෙරහන් වර්ගය අනුව ඒවායේ කේතය සහ පවතින කර්නල් ක්‍රියාකාරිත්වය යන දෙකටම සීමා ඇත.

ලිපිය XDP හි ඇති බොහෝ ද්‍රව්‍යවල අඩුපාඩු පිරවීමට අදහස් කෙරේ. පළමුව, ඔවුන් XDP හි විශේෂාංග වහාම මග හරින සූදානම් කළ කේතයක් සපයයි: එය සත්‍යාපනය සඳහා සූදානම් කර ඇත හෝ ගැටළු ඇති කිරීමට තරම් සරල ය. ඔබ පසුව ඔබේ කේතය මුල සිට ලිවීමට උත්සාහ කරන විට, සාමාන්‍ය දෝෂ සමඟ කුමක් කළ යුතු දැයි ඔබට අදහසක් නැත. දෙවනුව, ඔවුන්ගේම අන්තරායන් තිබියදීත්, VM සහ දෘඩාංග නොමැතිව XDP දේශීයව පරීක්ෂා කිරීමේ ක්‍රම ආවරණය නොවේ. පාඨය XDP සහ eBPF ගැන උනන්දුවක් දක්වන ජාලකරණය සහ Linux ගැන හුරුපුරුදු ක්‍රමලේඛකයින් සඳහා අදහස් කෙරේ.

මෙම කොටසේදී, XDP පෙරහන එකලස් කර ඇති ආකාරය සහ එය පරීක්ෂා කරන්නේ කෙසේද යන්න අපි විස්තරාත්මකව තේරුම් ගනිමු, එවිට අපි පැකට් සැකසුම් මට්ටමින් සුප්රසිද්ධ SYN කුකීස් යාන්ත්රණයේ සරල අනුවාදයක් ලියන්නෙමු. අපි තවමත් "සුදු ලැයිස්තුවක්" සාදන්නේ නැත
සත්‍යාපිත සේවාලාභීන්, කවුන්ටර තබාගෙන පෙරහන කළමනාකරණය කරන්න - ප්‍රමාණවත් ලඝු-සටහන්.

අපි C වලින් ලියන්නෙමු - එය විලාසිතාවක් නොවේ, නමුත් එය ප්රායෝගිකයි. සියලුම කේතය GitHub හි අවසානයේ ඇති සබැඳිය හරහා ලබා ගත හැකි අතර ලිපියේ විස්තර කර ඇති අදියර අනුව කැපවීම් වලට බෙදා ඇත.

වියාචනය. මෙම ලිපිය අතරතුර, මම DDoS ප්‍රහාර වැළැක්වීම සඳහා කුඩා විසඳුමක් සංවර්ධනය කරමි, මන්ද මෙය XDP සහ මගේ ප්‍රවීණත්වය සඳහා යථාර්ථවාදී කාර්යයකි. කෙසේ වෙතත්, ප්රධාන ඉලක්කය වන්නේ තාක්ෂණය අවබෝධ කර ගැනීමයි; මෙය සූදානම් කළ ආරක්ෂාවක් නිර්මාණය කිරීම සඳහා මාර්ගෝපදේශයක් නොවේ. නිබන්ධන කේතය ප්‍රශස්ත කර නැති අතර සමහර සූක්ෂ්මතා මඟ හැරේ.

XDP කෙටි දළ විශ්ලේෂණය

ලේඛන සහ පවතින ලිපි අනුපිටපත් නොකිරීමට මම ප්‍රධාන කරුණු පමණක් ගෙනහැර දක්වමි.

එබැවින්, පෙරහන් කේතය කර්නලය තුළට පටවනු ලැබේ. එන පැකට් පෙරහන වෙත යවනු ලැබේ. ප්රතිඵලයක් වශයෙන්, පෙරහන තීරණයක් ගත යුතුය: පැකට්ටුව කර්නලය තුළට (XDP_PASS), drop packet (XDP_DROP) හෝ ආපසු යවන්න (XDP_TX) ෆිල්ටරයට පැකේජය වෙනස් කළ හැකිය, මෙය විශේෂයෙන් සත්ය වේ XDP_TX. ඔබට වැඩසටහන අවලංගු කිරීමටද හැකිය (XDP_ABORTED) සහ පැකේජය නැවත සකසන්න, නමුත් මෙය සමාන වේ assert(0) - දෝෂහරණය සඳහා.

eBPF (Extended Berkley Packet Filter) අථත්‍ය යන්ත්‍රය හිතාමතාම සරල කර ඇති අතර එමඟින් කේත ලූප් නොවන බවත් අන් අයගේ මතකයට හානි නොවන බවත් කර්නලයට පරීක්ෂා කළ හැකිය. සමුච්චිත සීමා කිරීම් සහ චෙක්පත්:

  • ලූප (පසුපසට) තහනම් කර ඇත.
  • දත්ත සඳහා තොගයක් ඇත, නමුත් ශ්‍රිත නොමැත (සියලු C ශ්‍රිතයන් පේළිගත කළ යුතුය).
  • ස්ටැක් සහ පැකට් බෆරයෙන් පිටත මතක ප්‍රවේශයන් තහනම් වේ.
  • කේත ප්රමාණය සීමිතයි, නමුත් ප්රායෝගිකව මෙය ඉතා වැදගත් නොවේ.
  • විශේෂ කර්නල් කාර්යයන් (eBPF උපකාරකයින්) වෙත පමණක් ඇමතුම් සඳහා අවසර ඇත.

පෙරහනක් සැලසුම් කිරීම සහ ස්ථාපනය කිරීම මේ ආකාරයෙන් පෙනේ:

  1. මූලාශ්ර කේතය (උදා kernel.c) වස්තුවට සම්පාදනය කර ඇත (kernel.o) eBPF අතථ්‍ය යන්ත්‍ර නිර්මාණ ශිල්පය සඳහා. 2019 ඔක්තෝබර් වන විට, eBPF වෙත සම්පාදනය ක්ලැන්ග් විසින් සහාය දක්වන අතර GCC 10.1 හි පොරොන්දු වී ඇත.
  2. මෙම වස්තු කේතයේ කර්නල් ව්‍යුහයන් වෙත ඇමතුම් තිබේ නම් (උදාහරණයක් ලෙස, වගු සහ කවුන්ටර), ඒවායේ හැඳුනුම්පත් ශුන්‍ය මගින් ප්‍රතිස්ථාපනය වේ, එයින් අදහස් වන්නේ එවැනි කේතය ක්‍රියාත්මක කළ නොහැකි බවයි. කර්නලය තුළට පැටවීමට පෙර, ඔබ විසින් කර්නල් ඇමතුම් හරහා නිර්මාණය කරන ලද විශේෂිත වස්තූන්ගේ හැඳුනුම්පත් සමඟ මෙම ශුන්‍ය ප්‍රතිස්ථාපනය කළ යුතුය (කේතය සම්බන්ධ කරන්න). ඔබට මෙය බාහිර උපයෝගිතා සමඟ කළ හැකිය, නැතහොත් ඔබට විශේෂිත පෙරහනක් සම්බන්ධ කර පූරණය කරන වැඩසටහනක් ලිවිය හැකිය.
  3. කර්නලය පටවන ලද වැඩසටහන සත්‍යාපනය කරයි. චක්‍ර නොමැති වීම සහ පැකට් සහ ස්ටැක් මායිම් ඉක්මවා නොයෑම පරීක්ෂා කරනු ලැබේ. සත්‍යාපනය කරන්නාට කේතය නිවැරදි බව ඔප්පු කළ නොහැකි නම්, වැඩසටහන ප්‍රතික්ෂේප කරනු ලැබේ - ඔබට ඔහුව සතුටු කිරීමට හැකි විය යුතුය.
  4. සාර්ථක සත්‍යාපනයෙන් පසුව, කර්නලය විසින් eBPF ගෘහ නිර්මාණ වස්තු කේතය පද්ධති ගෘහ නිර්මාණ ශිල්පය සඳහා යන්ත්‍ර කේතයට සම්පාදනය කරයි (මේ මොහොතේම).
  5. වැඩසටහන අතුරු මුහුණතට සම්බන්ධ වන අතර පැකට් සැකසීම ආරම්භ කරයි.

XDP කර්නලය තුළ ක්‍රියාත්මක වන බැවින්, දෝෂහරණය සිදු කරනු ලබන්නේ ට්‍රේස් ලොග් සහ, ඇත්ත වශයෙන්ම, වැඩසටහන පෙරහන් කරන හෝ ජනනය කරන පැකට් භාවිතා කරමිනි. කෙසේ වෙතත්, බාගත කළ කේතය පද්ධතිය සඳහා ආරක්ෂිත බව eBPF සහතික කරයි, එබැවින් ඔබට ඔබේ දේශීය ලිනක්ස් මත සෘජුවම XDP සමඟ අත්හදා බැලිය හැකිය.

පරිසරය සකස් කිරීම

සභාව

Clang හට eBPF ගෘහ නිර්මාණ ශිල්පය සඳහා වස්තු කේතය කෙලින්ම නිපදවිය නොහැක, එබැවින් ක්‍රියාවලිය පියවර දෙකකින් සමන්විත වේ:

  1. C කේතය LLVM බයිට්කේතයට සම්පාදනය කරන්න (clang -emit-llvm).
  2. බයිට්කේතය eBPF වස්තු කේතය බවට පරිවර්තනය කරන්න (llc -march=bpf -filetype=obj).

ෆිල්ටරයක් ​​ලියන විට, සහායක කාර්යයන් සහ මැක්රෝස් සහිත ගොනු කිහිපයක් ප්රයෝජනවත් වනු ඇත කර්නල් පරීක්ෂණ වලින්. ඒවා කර්නල් අනුවාදයට ගැලපීම වැදගත් වේ (KVER) ඒවා බාගන්න helpers/:

export KVER=v5.3.7
export BASE=https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/plain/tools/testing/selftests/bpf
wget -P helpers --content-disposition "${BASE}/bpf_helpers.h?h=${KVER}" "${BASE}/bpf_endian.h?h=${KVER}"
unset KVER BASE

Arch Linux සඳහා Makefile (කර්නලය 5.3.7):

CLANG ?= clang
LLC ?= llc

KDIR ?= /lib/modules/$(shell uname -r)/build
ARCH ?= $(subst x86_64,x86,$(shell uname -m))

CFLAGS = 
    -Ihelpers 
    
    -I$(KDIR)/include 
    -I$(KDIR)/include/uapi 
    -I$(KDIR)/include/generated/uapi 
    -I$(KDIR)/arch/$(ARCH)/include 
    -I$(KDIR)/arch/$(ARCH)/include/generated 
    -I$(KDIR)/arch/$(ARCH)/include/uapi 
    -I$(KDIR)/arch/$(ARCH)/include/generated/uapi 
    -D__KERNEL__ 
    
    -fno-stack-protector -O2 -g

xdp_%.o: xdp_%.c Makefile
    $(CLANG) -c -emit-llvm $(CFLAGS) $< -o - | 
    $(LLC) -march=bpf -filetype=obj -o $@

.PHONY: all clean

all: xdp_filter.o

clean:
    rm -f ./*.o

KDIR කර්නල් ශීර්ෂයන් සඳහා මාර්ගය අඩංගු වේ, ARCH - පද්ධති ගෘහ නිර්මාණ ශිල්පය. බෙදාහැරීම් අතර මාර්ග සහ මෙවලම් තරමක් වෙනස් විය හැක.

ඩේබියන් 10 (කර්නලය 4.19.67) සඳහා වෙනස්කම් සඳහා උදාහරණය

# другая команда
CLANG ?= clang
LLC ?= llc-7

# другой каталог
KDIR ?= /usr/src/linux-headers-$(shell uname -r)
ARCH ?= $(subst x86_64,x86,$(shell uname -m))

# два дополнительных каталога -I
CFLAGS = 
    -Ihelpers 
    
    -I/usr/src/linux-headers-4.19.0-6-common/include 
    -I/usr/src/linux-headers-4.19.0-6-common/arch/$(ARCH)/include 
    # далее без изменений

CFLAGS සහායක ශීර්ෂ සහිත නාමාවලියක් සහ කර්නල් ශීර්ෂ සහිත නාමාවලි කිහිපයක් සම්බන්ධ කරන්න. සංකේතය __KERNEL__ පෙරණය කර්නලය තුළ ක්‍රියාත්මක වන බැවින් UAPI (පරිශීලක අවකාශය API) ශීර්ෂයන් කර්නල් කේතය සඳහා අර්ථ දක්වා ඇත.

අට්ටි ආරක්ෂාව අබල කළ හැක (-fno-stack-protector), eBPF කේත සත්‍යාපකය තවමත් සීමාවෙන් පිටත උල්ලංඝනය කිරීම් සඳහා පරීක්ෂා කරන බැවිනි. eBPF බයිට්කේතයේ ප්‍රමාණය සීමිත බැවින් එය වහාම ප්‍රශස්තිකරණය ක්‍රියාත්මක කිරීම වටී.

සියලුම පැකට් පසුකර කිසිවක් නොකරන පෙරහනකින් පටන් ගනිමු:

#include <uapi/linux/bpf.h>

#include <bpf_helpers.h>

SEC("prog")
int xdp_main(struct xdp_md* ctx) {
    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";

කණ්ඩායම make එකතු කරයි xdp_filter.o. දැන් එය උත්සාහ කිරීමට කොහෙද?

පරීක්ෂණ ස්ථාවරය

ස්ථාවරයේ අතුරුමුහුණත් දෙකක් ඇතුළත් විය යුතුය: පෙරනයක් ඇති සහ පැකට් යවනු ලබන ඒවා මත. අපගේ ෆිල්ටරය සමඟ සාමාන්‍ය යෙදුම් ක්‍රියා කරන ආකාරය පරීක්ෂා කිරීම සඳහා මේවා ඔවුන්ගේම IP සහිත සම්පූර්ණ ලිනක්ස් උපාංග විය යුතුය.

veth (අථත්‍ය ඊතර්නෙට්) වර්ගයේ උපාංග අපට සුදුසු ය: මේවා එකිනෙකට සෘජුවම “සම්බන්ධ” වූ අතථ්‍ය ජාල අතුරුමුහුණත් යුගලයකි. ඔබට ඒවා මේ ආකාරයට නිර්මාණය කළ හැකිය (මෙම කොටසේ සියලුම විධාන ip සිට සිදු කරනු ලැබේ root):

ip link add xdp-remote type veth peer name xdp-local

එය xdp-remote и xdp-local - උපාංග නම්. මත xdp-local (192.0.2.1/24) සමඟ පෙරහනක් අමුණා ඇත xdp-remote (192.0.2.2/24) පැමිණෙන ගමනාගමනය යවනු ලැබේ. කෙසේ වෙතත්, ගැටළුවක් ඇත: අතුරුමුහුණත් එකම යන්ත්‍රයේ ඇති අතර, ලිනක්ස් ඒවායින් එකකට අනෙක හරහා ගමනාගමනය නොයනු ඇත. ඔබට මෙය උපක්‍රමශීලී නීති මගින් විසඳාගත හැක iptables, නමුත් ඔවුන්ට පැකේජ වෙනස් කිරීමට සිදුවනු ඇත, එය දෝෂහරණය සඳහා අපහසු වේ. ජාල නාම අවකාශ භාවිතා කිරීම වඩා හොඳය (මෙතැන් සිට netns).

ජාල නාම අවකාශයක අතුරුමුහුණත්, මාර්ගගත වගු සහ අනෙකුත් නෙට්න් වල සමාන වස්තූන්ගෙන් හුදකලා වූ NetFilter රීති මාලාවක් අඩංගු වේ. සෑම ක්‍රියාවලියක්ම නාම අවකාශයක ක්‍රියාත්මක වන අතර ප්‍රවේශය ඇත්තේ එම දැල්වල වස්තූන් වෙත පමණි. පෙරනිමියෙන්, පද්ධතියට සියලුම වස්තූන් සඳහා තනි ජාල නාම අවකාශයක් ඇත, එබැවින් ඔබට ලිනක්ස් හි වැඩ කළ හැකි අතර netns ගැන නොදන්න.

අපි අලුත් namespace එකක් හදමු xdp-test සහ එය එහි ගෙන යන්න xdp-remote.

ip netns add xdp-test
ip link set dev xdp-remote netns xdp-test

එවිට ක්රියාවලිය ක්රියාත්මක වේ xdp-test, "දකින්නේ" නැත xdp-local (එය පෙරනිමියෙන් නෙට්න්හි පවතිනු ඇත) සහ පැකට්ටුවක් 192.0.2.1 වෙත යවන විට එය එය හරහා ගමන් කරයි. xdp-remoteමක්නිසාද යත්, මෙම ක්‍රියාවලියට ප්‍රවේශ විය හැකි 192.0.2.0/24 හි ඇති එකම අතුරු මුහුණත එය වන බැවිනි. මෙය ද ප්රතිවිරුද්ධ දිශාවට ක්රියා කරයි.

netns අතර ගමන් කරන විට, අතුරු මුහුණත පහළට ගොස් එහි ලිපිනය අහිමි වේ. netns හි අතුරු මුහුණත වින්‍යාස කිරීමට, ඔබ ධාවනය කළ යුතුය ip ... මෙම විධාන නාම අවකාශයේ ip netns exec:

ip netns exec xdp-test 
    ip address add 192.0.2.2/24 dev xdp-remote
ip netns exec xdp-test 
    ip link set xdp-remote up

ඔබට පෙනෙන පරිදි, මෙය සැකසීමෙන් වෙනස් නොවේ xdp-local පෙරනිමි නාම අවකාශයේ:

    ip address add 192.0.2.1/24 dev xdp-local
    ip link set xdp-local up

දුවනවා නම් tcpdump -tnevi xdp-local, සිට එවන ලද පැකට් බව ඔබට පෙනේ xdp-test, මෙම අතුරු මුහුණත වෙත භාර දෙනු ලැබේ:

ip netns exec xdp-test   ping 192.0.2.1

ෂෙල් එකක් දියත් කිරීම පහසුය xdp-test. ගබඩාවේ ස්ක්‍රිප්ට් එකක් ඇත, එය ස්ථාවරය සමඟ ස්වයංක්‍රීයව වැඩ කරයි; උදාහරණයක් ලෙස, ඔබට විධානය සමඟ ස්ථාවරය වින්‍යාසගත කළ හැකිය. sudo ./stand up සහ එය මකා දමන්න sudo ./stand down.

ලුහුබැඳීම

ෆිල්ටරය මේ ආකාරයට උපාංගය සමඟ සම්බන්ධ වේ:

ip -force link set dev xdp-local xdp object xdp_filter.o verbose

ප්රධාන -force තවත් එකක් දැනටමත් සම්බන්ධ කර ඇත්නම් නව වැඩසටහනක් සම්බන්ධ කිරීමට අවශ්‍ය වේ. “කිසිදු ප්‍රවෘත්තියක් ශුභ ආරංචියක් නොවේ” යනු මෙම විධානය ගැන නොවේ, ඕනෑම අවස්ථාවක නිගමනය විශාල ය. දක්වන්න verbose විකල්ප, නමුත් එය සමඟ එකලස් කිරීමේ ලැයිස්තුවක් සහිත කේත සත්‍යාපනයේ ක්‍රියාකාරිත්වය පිළිබඳ වාර්තාවක් දිස්වේ:

Verifier analysis:

0: (b7) r0 = 2
1: (95) exit

අතුරු මුහුණතෙන් වැඩසටහන විසන්ධි කරන්න:

ip link set dev xdp-local xdp off

ස්ක්‍රිප්ට් එකේ මේවා විධාන sudo ./stand attach и sudo ./stand detach.

පෙරහනක් ඇමිණීමෙන්, ඔබට එය සහතික කළ හැකිය ping දිගටම ක්‍රියාත්මක වේ, නමුත් වැඩසටහන ක්‍රියාත්මක වේද? අපි ලඝු-සටහන් එකතු කරමු. කාර්යය bpf_trace_printk() සමාන printf(), නමුත් රටා හැර වෙනත් තර්ක තුනක් දක්වා සහ සහය දක්වන්නේ සීමිත පිරිවිතර ලැයිස්තුවක් පමණි. මැක්රෝ bpf_printk() ඇමතුම සරල කරයි.

   SEC("prog")
   int xdp_main(struct xdp_md* ctx) {
+      bpf_printk("got packet: %pn", ctx);
       return XDP_PASS;
   }

ප්‍රතිදානය සක්‍රීය කළ යුතු කර්නල් ට්‍රේස් නාලිකාව වෙත යයි:

echo -n 1 | sudo tee /sys/kernel/debug/tracing/options/trace_printk

පණිවිඩ පොට බලන්න:

cat /sys/kernel/debug/tracing/trace_pipe

මෙම විධාන දෙකම ඇමතුමක් ලබා දෙයි sudo ./stand log.

Ping දැන් මෙවැනි පණිවිඩ අවුලුවාලිය යුතුය:

<...>-110930 [004] ..s1 78803.244967: 0: got packet: 00000000ac510377

ඔබ සත්‍යාපනය කරන්නාගේ ප්‍රතිදානය දෙස සමීපව බැලුවහොත්, ඔබට අමුතු ගණනය කිරීම් පෙනෙනු ඇත:

0: (bf) r3 = r1
1: (18) r1 = 0xa7025203a7465
3: (7b) *(u64 *)(r10 -8) = r1
4: (18) r1 = 0x6b63617020746f67
6: (7b) *(u64 *)(r10 -16) = r1
7: (bf) r1 = r10
8: (07) r1 += -16
9: (b7) r2 = 16
10: (85) call bpf_trace_printk#6
<...>

කාරණය වන්නේ eBPF වැඩසටහන් වල දත්ත අංශයක් නොමැති වීමයි, එබැවින් ආකෘති තන්තුවක් කේතනය කිරීමේ එකම ක්‍රමය VM විධානවල ක්ෂණික තර්ක වේ:

$ python -c "import binascii; print(bytes(reversed(binascii.unhexlify('0a7025203a74656b63617020746f67'))))"
b'got packet: %pn'

මෙම හේතුව නිසා, නිදොස් කිරීමේ ප්‍රතිදානය ප්‍රතිඵලයක් ලෙස ලැබෙන කේතය විශාල ලෙස පුපුරවා හරියි.

XDP පැකට් යැවීම

අපි පෙරහන වෙනස් කරමු: එන පැකට් සියල්ල ආපසු යැවීමට ඉඩ දෙන්න. ජාල දෘෂ්ටි කෝණයකින් මෙය වැරදියි, මන්දයත් ශීර්ෂකවල ලිපින වෙනස් කිරීමට අවශ්ය වනු ඇත, නමුත් දැන් ප්රතිපත්තිමය වශයෙන් කාර්යය වැදගත් වේ.

       bpf_printk("got packet: %pn", ctx);
-      return XDP_PASS;
+      return XDP_TX;
   }

අපි දියත් කරනවා tcpdump මත xdp-remote. එය එක හා සමාන පිටතට යන සහ එන ICMP Echo ඉල්ලීම පෙන්විය යුතු අතර ICMP Echo පිළිතුර පෙන්වීම නැවැත්විය යුතුය. නමුත් එය නොපෙන්වයි. එය වැඩ සඳහා බව හැරෙනවා XDP_TX මත වැඩසටහනේ xdp-local අවශ්‍යයියුගල අතුරුමුහුණත වෙත xdp-remote වැඩපිළිවෙලක් ද පවරන ලදී, එය හිස් වුවද, ඔහුව උත්ථාන කරන ලදී.

මම මෙය දැනගත්තේ කෙසේද?

කර්නලයේ පැකේජයක මාර්ගය සොයා ගන්න perf සිද්ධි යාන්ත්‍රණය මඟින් එකම අතථ්‍ය යන්ත්‍රය භාවිතා කිරීමට ඉඩ සලසයි, එනම් eBPF eBPF සමඟ විසුරුවා හැරීම සඳහා භාවිතා කරයි.

නපුරෙන් යහපතක් කළ යුතුය, මන්ද එය කළ හැකි වෙනත් කිසිවක් නැත.

$ sudo perf trace --call-graph dwarf -e 'xdp:*'
   0.000 ping/123455 xdp:xdp_bulk_tx:ifindex=19 action=TX sent=0 drops=1 err=-6
                                     veth_xdp_flush_bq ([veth])
                                     veth_xdp_flush_bq ([veth])
                                     veth_poll ([veth])
                                     <...>

කේතය 6 යනු කුමක්ද?

$ errno 6
ENXIO 6 No such device or address

උත්සවය veth_xdp_flush_bq() වෙතින් දෝෂ කේතයක් ලබා ගනී veth_xdp_xmit(), එහිදී සොයන්න ENXIO සහ අදහස සොයා ගන්න.

අවම පෙරහන ප්‍රතිසාධනය කරමු (XDP_PASS) ගොනුවේ xdp_dummy.c, එය Makefile වෙත එක් කරන්න, එය බැඳ තබන්න xdp-remote:

ip netns exec remote 
    ip link set dev int xdp object dummy.o

දැන් tcpdump බලාපොරොත්තු වන දේ පෙන්වයි:

62:57:8e:70:44:64 > 26:0e:25:37:8f:96, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 13762, offset 0, flags [DF], proto ICMP (1), length 84)
    192.0.2.2 > 192.0.2.1: ICMP echo request, id 46966, seq 1, length 64
62:57:8e:70:44:64 > 26:0e:25:37:8f:96, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 13762, offset 0, flags [DF], proto ICMP (1), length 84)
    192.0.2.2 > 192.0.2.1: ICMP echo request, id 46966, seq 1, length 64

ඒ වෙනුවට ARP පමණක් පෙන්වන්නේ නම්, ඔබ පෙරහන් ඉවත් කළ යුතුය (මෙය සිදු කරයි sudo ./stand detach), යන්න දෙන්න ping, පසුව පෙරහන් සකසා නැවත උත්සාහ කරන්න. ගැටළුව වන්නේ පෙරණයයි XDP_TX ARP සහ තොගය යන දෙකටම වලංගු වේ
නාම අවකාශයන් xdp-test MAC ලිපිනය 192.0.2.1 "අමතක" කිරීමට සමත් විය, එය මෙම IP විසඳීමට නොහැකි වනු ඇත.

ගැටලුව ප්රකාශ කිරීම

අපි ප්රකාශිත කාර්යය වෙත යමු: XDP මත SYN කුකීස් යාන්ත්රණයක් ලියන්න.

SYN ගංවතුර ජනප්‍රිය DDoS ප්‍රහාරයක් ලෙස පවතී, එහි සාරය පහත පරිදි වේ. සම්බන්ධතාවයක් ස්ථාපිත වූ විට (TCP අතට අත දීම), සේවාදායකයට SYN එකක් ලැබේ, අනාගත සම්බන්ධතාවය සඳහා සම්පත් වෙන් කරයි, SYNACK පැකට්ටුවක් සමඟ ප්‍රතිචාර දක්වයි සහ ACK එකක් එනතෙක් බලා සිටී. ප්‍රහාරකයා සරලව තත්පරයකට SYN පැකට් දහස් ගණනක් එක් එක් සත්කාරක සමාගමෙන් බහු-දහසක්-ශක්තිමත් බොට්නෙට් එකකින් වංචා කළ ලිපින වලින් යවයි. පැකට්ටුව පැමිණි විගසම සම්පත් වෙන් කිරීමට සේවාදායකයට බල කෙරෙනු ඇත, නමුත් විශාල කල් ඉකුත්වීමෙන් පසුව ඒවා මුදා හරිනු ඇත; ප්රතිඵලයක් වශයෙන්, මතකය හෝ සීමාවන් අවසන් වී ඇත, නව සම්බන්ධතා පිළිගනු නොලැබේ, සහ සේවාව ලබා ගත නොහැක.

ඔබ SYN පැකට්ටුව මත පදනම්ව සම්පත් වෙන් නොකර, නමුත් SYNACK පැකට්ටුවකින් පමණක් ප්‍රතිචාර දක්වන්නේ නම්, පසුව පැමිණි ACK පැකට්ටුව සුරකිනු නොලැබූ SYN පැකට් එකක් බව සේවාදායකය තේරුම් ගන්නේ කෙසේද? සියල්ලට පසු, ප්‍රහාරකයෙකුට ව්‍යාජ ACK ජනනය කළ හැකිය. SYN කුකියේ කාරණය වන්නේ එය සංකේතනය කිරීමයි seqnum ලිපින, වරායන් සහ ලුණු වෙනස් කිරීමේ හැෂ් ලෙස සම්බන්ධතා පරාමිතීන්. ලුණු වෙනස් කිරීමට පෙර ACK පැමිණීමට සමත් වූයේ නම්, ඔබට නැවත හැෂ් ගණනය කර එය සමඟ සංසන්දනය කළ හැකිය acknum. ව්යාජය acknum ප්‍රහාරකයාට ලුණු වල රහස ඇතුළත් වන බැවින් සහ සීමිත නාලිකාවක් හේතුවෙන් එය නිරාකරණය කිරීමට කාලය නොමැති බැවිනි.

SYN කුකිය ලිනක්ස් කර්නලය තුළ දිගු කලක් ක්‍රියාත්මක කර ඇති අතර SYNs ඉතා ඉක්මනින් සහ විශාල වශයෙන් පැමිණියහොත් ස්වයංක්‍රීයව පවා සක්‍රීය කළ හැක.

TCP අතට අත දීම පිළිබඳ අධ්‍යාපනික වැඩසටහන

TCP බයිට් ප්‍රවාහයක් ලෙස දත්ත සම්ප්‍රේෂණය සපයයි, උදාහරණයක් ලෙස, HTTP ඉල්ලීම් TCP හරහා සම්ප්‍රේෂණය වේ. ධාරාව පැකට් වල කැබලිවලට සම්ප්රේෂණය වේ. සියලුම TCP පැකට් වල තාර්කික කොඩි සහ 32-bit අනුක්‍රමික අංක ඇත:

  • කොඩිවල සංයෝජනය විශේෂිත පැකේජයක කාර්යභාරය තීරණය කරයි. SYN ධජය පෙන්නුම් කරන්නේ මෙය යවන්නාගේ සම්බන්ධතාවයේ පළමු පැකට්ටුව බවයි. ACK ධජය යන්නෙන් අදහස් කරන්නේ යවන්නාට බයිටය දක්වා සියලු සම්බන්ධතා දත්ත ලැබී ඇති බවයි acknum. පැකට්ටුවක කොඩි කිහිපයක් තිබිය හැකි අතර ඒවායේ සංයෝජනයෙන් හැඳින්වේ, උදාහරණයක් ලෙස, SYNACK පැකට්ටුවක්.

  • අනුක්‍රමික අංකය (seqnum) මෙම පැකට්ටුවේ සම්ප්‍රේෂණය වන පළමු බයිටය සඳහා දත්ත ප්‍රවාහයේ ඕෆ්සෙට් නියම කරයි. උදාහරණයක් ලෙස, X බයිට් දත්ත සහිත පළමු පැකට්ටුවේ මෙම අංකය N නම්, නව දත්ත සහිත ඊළඟ පැකට්ටුවේ එය N+X වේ. සම්බන්ධතාවයේ ආරම්භයේ දී, එක් එක් පැත්ත මෙම අංකය අහඹු ලෙස තෝරා ගනී.

  • පිළිගැනීමේ අංකය (ඇක්නම්) - seqnum ලෙස සමාන ඕෆ්සෙට්, නමුත් එය සම්ප්‍රේෂණය වන බයිටයේ අංකය තීරණය නොකරයි, නමුත් ලබන්නාගේ පළමු බයිටයේ අංකය, යවන්නා නොදුටු.

සම්බන්ධතාවයේ ආරම්භයේ දී, පාර්ශවයන් එකඟ විය යුතුය seqnum и acknum. සේවාදායකයා එය සමඟ SYN පැකට්ටුවක් යවයි seqnum = X. සේවාදායකය SYNACK පැකට්ටුවක් සමඟ ප්‍රතිචාර දක්වයි, එහිදී එය වාර්තා කරයි seqnum = Y සහ හෙළිදරව් කරයි acknum = X + 1. සේවාලාභියා ACK පැකට්ටුවක් සමඟ SYNACK වෙත ප්‍රතිචාර දක්වයි, එහිදී seqnum = X + 1, acknum = Y + 1. මෙයින් පසු, සැබෑ දත්ත හුවමාරුව ආරම්භ වේ.

සම වයසේ මිතුරා පැකට්ටුව ලැබුණු බව පිළි නොගන්නේ නම්, TCP එය කල් ඉකුත් වූ පසු නැවත යවයි.

SYN කුකීස් සැමවිටම භාවිතා නොකරන්නේ ඇයි?

පළමුව, SYNACK හෝ ACK නැති වුවහොත්, එය නැවත යැවීමට ඔබට බලා සිටීමට සිදුවනු ඇත - සම්බන්ධතා සැකසුම මන්දගාමී වේ. දෙවනුව, SYN පැකේජයේ - සහ එහි පමණි! - සම්බන්ධතාවයේ තවදුරටත් ක්‍රියාකාරිත්වයට බලපාන විකල්ප ගණනාවක් සම්ප්‍රේෂණය වේ. එන SYN පැකට් මතක තබා නොගෙන, සේවාදායකයා මෙම විකල්පයන් නොසලකා හරියි; සේවාදායකයා ඒවා ඊළඟ පැකට් වලට නොයවනු ඇත. TCP මෙම නඩුවේ වැඩ කළ හැකි නමුත් අවම වශයෙන් ආරම්භක අදියරේදී සම්බන්ධතාවයේ ගුණාත්මකභාවය අඩු වනු ඇත.

පැකේජ ඉදිරිදර්ශනයකින්, XDP වැඩසටහනක් පහත දේ කළ යුතුය:

  • කුකියක් සමඟ SYNACK සමඟ SYN වෙත ප්‍රතිචාර දක්වන්න;
  • RST සමඟ ACK වෙත ප්රතිචාර දක්වන්න (විසන්ධි කරන්න);
  • ඉතිරි පැකට් ඉවතලන්න.

පැකේජ විග්‍රහ කිරීම සමඟ ඇල්ගොරිතමයේ ව්‍යාජ කේතය:

Если это не Ethernet,
    пропустить пакет.
Если это не IPv4,
    пропустить пакет.
Если адрес в таблице проверенных,               (*)
        уменьшить счетчик оставшихся проверок,
        пропустить пакет.
Если это не TCP,
    сбросить пакет.     (**)
Если это SYN,
    ответить SYN-ACK с cookie.
Если это ACK,
    если в acknum лежит не cookie,
        сбросить пакет.
    Занести в таблицу адрес с N оставшихся проверок.    (*)
    Ответить RST.   (**)
В остальных случаях сбросить пакет.

එක (*) ඔබට පද්ධතියේ තත්වය කළමනාකරණය කිරීමට අවශ්‍ය ලකුණු සලකුණු කර ඇත - පළමු අදියරේදී ඔබට ඒවා නොමැතිව කළ හැක්කේ TCP අතට අත දීමක් SYN කුකියක් උත්පාදනය කිරීම සමඟ අනුක්‍රමයක් ලෙස ක්‍රියාත්මක කිරීමෙන් පමණි.

එම ස්ථානයේදීම (**), අපට මේසයක් නොමැති අතර, අපි පැකට්ටුව මඟ හරිමු.

TCP අතට අත දීම ක්‍රියාත්මක කිරීම

පැකේජය විග්‍රහ කිරීම සහ කේතය සත්‍යාපනය කිරීම

අපට ජාල ශීර්ෂ ව්‍යුහයන් අවශ්‍ය වනු ඇත: ඊතර්නෙට් (uapi/linux/if_ether.h), IPv4 (uapi/linux/ip.h) සහ TCP (uapi/linux/tcp.h) සම්බන්ධ දෝෂ හේතුවෙන් මට දෙවැන්න සම්බන්ධ කිරීමට නොහැකි විය atomic64_t, මට අවශ්‍ය අර්ථ දැක්වීම් කේතයට පිටපත් කිරීමට සිදු විය.

කර්නලයේ ඇති eBPF සත්‍යාපකය පසුපස හඹා යෑම තහනම් කරන බැවින්, ඇත්ත වශයෙන්ම, ලූප සහ ක්‍රියාකාරී ඇමතුම් තහනම් කරන බැවින්, කියවීමේ හැකියාව සඳහා C හි උද්දීපනය කර ඇති සියලුම ශ්‍රිතයන් ඇමතුම් ස්ථානයේදී පේළිගත කළ යුතුය.

#define INTERNAL static __attribute__((always_inline))

මැක්රෝ LOG() නිකුතු ගොඩනැගීමේ මුද්‍රණය අක්‍රීය කරයි.

වැඩසටහන යනු කාර්යයන් වාහකයකි. සෑම කෙනෙකුටම අනුරූප මට්ටමේ ශීර්ෂය උද්දීපනය කර ඇති පැකට්ටුවක් ලැබේ, උදාහරණයක් ලෙස, process_ether() එය පිරවීම අපේක්ෂා කරයි ether. ක්ෂේත්‍ර විශ්ලේෂණයේ ප්‍රතිඵල මත පදනම්ව, ශ්‍රිතයට පැකට්ටුව ඉහළ මට්ටමකට ගෙන යා හැක. ශ්‍රිතයේ ප්‍රතිඵලය වන්නේ XDP ක්‍රියාවයි. දැනට, SYN සහ ACK හසුරුවන්නන් සියලු පැකට් පසු කරයි.

struct Packet {
    struct xdp_md* ctx;

    struct ethhdr* ether;
    struct iphdr* ip;
    struct tcphdr* tcp;
};

INTERNAL int process_tcp_syn(struct Packet* packet) { return XDP_PASS; }
INTERNAL int process_tcp_ack(struct Packet* packet) { return XDP_PASS; }
INTERNAL int process_tcp(struct Packet* packet) { ... }
INTERNAL int process_ip(struct Packet* packet) { ... }

INTERNAL int
process_ether(struct Packet* packet) {
    struct ethhdr* ether = packet->ether;

    LOG("Ether(proto=0x%x)", bpf_ntohs(ether->h_proto));

    if (ether->h_proto != bpf_ntohs(ETH_P_IP)) {
        return XDP_PASS;
    }

    // B
    struct iphdr* ip = (struct iphdr*)(ether + 1);
    if ((void*)(ip + 1) > (void*)packet->ctx->data_end) {
        return XDP_DROP; /* malformed packet */
    }

    packet->ip = ip;
    return process_ip(packet);
}

SEC("prog")
int xdp_main(struct xdp_md* ctx) {
    struct Packet packet;
    packet.ctx = ctx;

    // A
    struct ethhdr* ether = (struct ethhdr*)(void*)ctx->data;
    if ((void*)(ether + 1) > (void*)ctx->data_end) {
        return XDP_PASS;
    }

    packet.ether = ether;
    return process_ether(&packet);
}

A සහ B ලෙස සලකුණු කර ඇති චෙක්පත් වෙත මම ඔබේ අවධානය යොමු කරමි. ඔබ A අදහස් දක්වන්නේ නම්, වැඩසටහන ගොඩනඟනු ඇත, නමුත් පූරණය කිරීමේදී සත්‍යාපන දෝෂයක් ඇත:

Verifier analysis:

<...>
11: (7b) *(u64 *)(r10 -48) = r1
12: (71) r3 = *(u8 *)(r7 +13)
invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0)
R7 offset is outside of the packet
processed 11 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0

Error fetching program/map!

යතුරු නූල් invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): බෆරයේ ආරම්භයේ සිට දහතුන්වන බයිටය පැකට්ටුවෙන් පිටත ඇති විට ක්‍රියාත්මක කිරීමේ මාර්ග තිබේ. අප කතා කරන්නේ කුමන රේඛාව ගැනද යන්න ලැයිස්තුගත කිරීමෙන් තේරුම් ගැනීමට අපහසුය, නමුත් ප්‍රභව කේත රේඛා පෙන්වන උපදෙස් අංකයක් (12) සහ විසුරුවා හරින යන්ත්‍රයක් ඇත:

llvm-objdump -S xdp_filter.o | less

මෙම නඩුවේදී එය රේඛාව වෙත යොමු කරයි

LOG("Ether(proto=0x%x)", bpf_ntohs(ether->h_proto));

ගැටලුව බව පැහැදිලි කරයි ether. එය සෑම විටම මේ වගේ වනු ඇත.

SYN වෙත පිළිතුරු දෙන්න

මෙම අදියරේ ඉලක්කය වන්නේ ස්ථාවර සමග නිවැරදි SYNACK පැකට්ටුවක් උත්පාදනය කිරීමයි seqnum, අනාගතයේදී SYN කුකිය මඟින් ප්‍රතිස්ථාපනය වනු ඇත. සියලුම වෙනස්කම් සිදු වේ process_tcp_syn() සහ අවට ප්රදේශ.

පැකේජ සත්‍යාපනය

පුදුමයට කරුණක් නම්, මෙන්න වඩාත්ම කැපී පෙනෙන පේළිය හෝ ඒ වෙනුවට, එහි විවරණ:

/* Required to verify checksum calculation */
const void* data_end = (const void*)ctx->data_end;

කේතයේ පළමු අනුවාදය ලිවීමේදී, 5.1 කර්නලය භාවිතා කරන ලදී, සත්‍යාපනය සඳහා වෙනසක් ඇති data_end и (const void*)ctx->data_end. ලියන අවස්ථාව වන විට, කර්නලය 5.3.1 හි මෙම ගැටළුව නොතිබුණි. සම්පාදකය ක්ෂේත්‍රයකට වඩා වෙනස් ලෙස දේශීය විචල්‍යයකට ප්‍රවේශ විය හැකිය. කතාවේ සදාචාරය: බොහෝ කූඩු ඇති විට කේතය සරල කිරීම උපකාරී වේ.

ඊළඟට සත්‍යාපනය කරන්නාගේ මහිමය සඳහා සාමාන්‍ය දිග චෙක්පත් වේ; ඕ MAX_CSUM_BYTES පහත.

const u32 ip_len = ip->ihl * 4;
if ((void*)ip + ip_len > data_end) {
    return XDP_DROP; /* malformed packet */
}
if (ip_len > MAX_CSUM_BYTES) {
    return XDP_ABORTED; /* implementation limitation */
}

const u32 tcp_len = tcp->doff * 4;
if ((void*)tcp + tcp_len > (void*)ctx->data_end) {
    return XDP_DROP; /* malformed packet */
}
if (tcp_len > MAX_CSUM_BYTES) {
    return XDP_ABORTED; /* implementation limitation */
}

පැකේජය දිග හැරීම

අපි පුරවන්නෙමු seqnum и acknum, ACK සකසන්න (SYN දැනටමත් සකසා ඇත):

const u32 cookie = 42;
tcp->ack_seq = bpf_htonl(bpf_ntohl(tcp->seq) + 1);
tcp->seq = bpf_htonl(cookie);
tcp->ack = 1;

TCP ports, IP ලිපිනය සහ MAC ලිපින මාරු කරන්න. XDP වැඩසටහනෙන් සම්මත පුස්තකාලයට ප්‍රවේශ විය නොහැක memcpy() - ක්ලැන්ග් අභ්‍යන්තරය සඟවන සාර්වයකි.

const u16 temp_port = tcp->source;
tcp->source = tcp->dest;
tcp->dest = temp_port;

const u32 temp_ip = ip->saddr;
ip->saddr = ip->daddr;
ip->daddr = temp_ip;

struct ethhdr temp_ether = *ether;
memcpy(ether->h_dest, temp_ether.h_source, ETH_ALEN);
memcpy(ether->h_source, temp_ether.h_dest, ETH_ALEN);

චෙක්සම් නැවත ගණනය කිරීම

IPv4 සහ TCP පිරික්සුම් සඳහා ශීර්ෂයේ ඇති සියලුම 16-බිට් වචන එකතු කිරීම අවශ්‍ය වන අතර, ශීර්ෂවල ප්‍රමාණය ඒවාට ලියා ඇත, එනම්, සම්පාදනය කරන අවස්ථාවේ දී නොදනී. මෙය ගැටළුවක් වන්නේ සත්‍යාපිතය සාමාන්‍ය ලූපය මායිම් විචල්‍යයට මඟ නොහරින බැවිනි. නමුත් ශීර්ෂයේ ප්‍රමාණය සීමිතය: එක් එක් බයිට් 64 දක්වා. ඔබට ස්ථාවර පුනරාවර්තන සංඛ්‍යාවක් සහිත ලූපයක් සෑදිය හැකිය, එය කලින් අවසන් කළ හැකිය.

ඇති බව සටහන් කරමි RFC 1624 පැකේජවල ස්ථාවර වචන පමණක් වෙනස් කරන්නේ නම් චෙක්සම් අර්ධ වශයෙන් නැවත ගණනය කරන්නේ කෙසේද යන්න ගැන. කෙසේ වෙතත්, මෙම ක්රමය විශ්වීය නොවන අතර, ක්රියාත්මක කිරීම නඩත්තු කිරීම වඩා දුෂ්කර වනු ඇත.

චෙක්සම් ගණනය කිරීමේ කාර්යය:

#define MAX_CSUM_WORDS 32
#define MAX_CSUM_BYTES (MAX_CSUM_WORDS * 2)

INTERNAL u32
sum16(const void* data, u32 size, const void* data_end) {
    u32 s = 0;
#pragma unroll
    for (u32 i = 0; i < MAX_CSUM_WORDS; i++) {
        if (2*i >= size) {
            return s; /* normal exit */
        }
        if (data + 2*i + 1 + 1 > data_end) {
            return 0; /* should be unreachable */
        }
        s += ((const u16*)data)[i];
    }
    return s;
}

වුවද size ඇමතුම් කේතය මගින් සත්‍යාපනය කර ඇත, දෙවන පිටවීමේ කොන්දේසිය අවශ්‍ය වන අතර එමඟින් සත්‍යාපනය කරන්නාට ලූපය සම්පූර්ණ කිරීම ඔප්පු කළ හැකිය.

32-bit වචන සඳහා, සරල අනුවාදයක් ක්රියාත්මක වේ:

INTERNAL u32
sum16_32(u32 v) {
    return (v >> 16) + (v & 0xffff);
}

ඇත්ත වශයෙන්ම චෙක්සම් නැවත ගණනය කිරීම සහ පැකට්ටුව ආපසු යැවීම:

ip->check = 0;
ip->check = carry(sum16(ip, ip_len, data_end));

u32 tcp_csum = 0;
tcp_csum += sum16_32(ip->saddr);
tcp_csum += sum16_32(ip->daddr);
tcp_csum += 0x0600;
tcp_csum += tcp_len << 8;
tcp->check = 0;
tcp_csum += sum16(tcp, tcp_len, data_end);
tcp->check = carry(tcp_csum);

return XDP_TX;

උත්සවය carry() RFC 32 ට අනුව 16-bit වචන 791-bit එකතුවකින් චෙක්සම් කරයි.

TCP අතට අත දීම සත්‍යාපනය

පෙරහන නිවැරදිව සම්බන්ධයක් ස්ථාපිත කරයි netcat, ලිනක්ස් විසින් RST පැකට්ටුවක් සමඟ ප්‍රතිචාර දැක්වූ අවසාන ACK අතුරුදහන් වී ඇත, ජාල තොගයට SYN නොලැබුණු බැවින් - එය SYNACK බවට පරිවර්තනය කර ආපසු යවන ලදි - සහ OS දෘෂ්ටි කෝණයෙන්, විවෘත කිරීමට සම්බන්ධ නොවන පැකට්ටුවක් පැමිණියේය. සම්බන්ධතා.

$ sudo ip netns exec xdp-test   nc -nv 192.0.2.1 6666
192.0.2.1 6666: Connection reset by peer

සම්පූර්ණ යෙදුම් සමඟ පරීක්ෂා කිරීම සහ නිරීක්ෂණය කිරීම වැදගත් වේ tcpdump මත xdp-remote මන්ද, උදාහරණයක් ලෙස, hping3 වැරදි චෙක්සම් වලට ප්‍රතිචාර නොදක්වයි.

XDP දෘෂ්ටි කෝණයකින්, සත්‍යාපනයම සුළු දෙයකි. ගණනය කිරීමේ ඇල්ගොරිතම ප්‍රාථමික වන අතර නවීන ප්‍රහාරකයෙකුට ගොදුරු විය හැකිය. උදාහරණයක් ලෙස, ලිනක්ස් කර්නලය, ගුප්ත ලේඛන SipHash භාවිතා කරයි, නමුත් XDP සඳහා එය ක්‍රියාත්මක කිරීම පැහැදිලිවම මෙම ලිපියේ විෂය පථයෙන් ඔබ්බට ය.

බාහිර සන්නිවේදනයට අදාළ නව TODO සඳහා හඳුන්වා දී ඇත:

  • XDP වැඩසටහන ගබඩා කළ නොහැක cookie_seed (ලුණු වල රහස් කොටස) ගෝලීය විචල්‍යයක, ඔබට කර්නලය තුළ ගබඩා කිරීම අවශ්‍ය වේ, එහි අගය විශ්වාසදායක උත්පාදක යන්ත්‍රයකින් වරින් වර යාවත්කාලීන කරනු ලැබේ.

  • SYN කුකිය ACK පැකට්ටුවට ගැළපේ නම්, ඔබට පණිවිඩයක් මුද්‍රණය කිරීමට අවශ්‍ය නැත, නමුත් එයින් පැකට් යැවීම දිගටම කරගෙන යාමට සත්‍යාපිත සේවාලාභියාගේ IP මතක තබා ගන්න.

නීත්‍යානුකූල සේවාලාභී සත්‍යාපනය:

$ sudoip netns exec xdp-test   nc -nv 192.0.2.1 6666
192.0.2.1 6666: Connection reset by peer

චෙක්පත සමත් වූ බව ලඝු-සටහන් පෙන්වයි (flags=0x2 - මෙය SYN, flags=0x10 ACK වේ):

Ether(proto=0x800)
  IP(src=0x20e6e11a dst=0x20e6e11e proto=6)
    TCP(sport=50836 dport=6666 flags=0x2)
Ether(proto=0x800)
  IP(src=0xfe2cb11a dst=0xfe2cb11e proto=6)
    TCP(sport=50836 dport=6666 flags=0x10)
      cookie matches for client 20200c0

සත්‍යාපිත IP ලැයිස්තුවක් නොමැති අතර, SYN ගංවතුරෙන් ආරක්ෂාවක් නොලැබෙනු ඇත, නමුත් පහත දැක්වෙන විධානය මඟින් දියත් කරන ලද ACK ගංවතුරකට ප්‍රතිචාරය මෙන්න:

sudo ip netns exec xdp-test   hping3 --flood -A -s 1111 -p 2222 192.0.2.1

ලොග් සටහන්:

Ether(proto=0x800)
  IP(src=0x15bd11a dst=0x15bd11e proto=6)
    TCP(sport=3236 dport=2222 flags=0x10)
      cookie mismatch

නිගමනය

සමහර විට පොදුවේ eBPF සහ විශේෂයෙන් XDP සංවර්ධන වේදිකාවක් ලෙසට වඩා උසස් පරිපාලක මෙවලමක් ලෙස ඉදිරිපත් කෙරේ. ඇත්ත වශයෙන්ම, XDP යනු කර්නලය මගින් පැකට් සැකසීමට බාධා කිරීමේ මෙවලමක් වන අතර DPDK සහ අනෙකුත් කර්නල් බයිපාස් විකල්ප වැනි කර්නල් තොගයට විකල්පයක් නොවේ. අනෙක් අතට, XDP ඔබට තරමක් සංකීර්ණ තර්කනය ක්‍රියාත්මක කිරීමට ඉඩ සලසයි, එපමනක් නොව, රථවාහන සැකසීමේදී බාධාවකින් තොරව යාවත්කාලීන කිරීම පහසුය. සත්‍යාපකය විශාල ගැටළු ඇති නොකරයි; පුද්ගලිකව, පරිශීලක අවකාශ කේතයේ කොටස් සඳහා මම මෙය ප්‍රතික්ෂේප නොකරමි.

දෙවන කොටසේදී, මාතෘකාව සිත්ගන්නාසුළු නම්, අපි සත්‍යාපිත සේවාදායකයින්ගේ සහ විසන්ධි කිරීමේ වගුව සම්පූර්ණ කරන්නෙමු, කවුන්ටර ක්‍රියාත්මක කර පෙරණය කළමනාකරණය කිරීම සඳහා පරිශීලක අවකාශයේ උපයෝගීතාවයක් ලියන්නෙමු.

ආශ්රිත:

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න