Piszemy ochronę przed atakami DDoS na XDP. Część nuklearna
Technologia eXpress Data Path (XDP) umożliwia losowe przetwarzanie ruchu na interfejsach systemu Linux, zanim pakiety trafią do stosu sieciowego jądra. Zastosowanie XDP - ochrona przed atakami DDoS (CloudFlare), złożone filtry, zbieranie statystyk (Netflix). Programy XDP są wykonywane przez maszynę wirtualną eBPF, więc mają ograniczenia zarówno w kodzie, jak i dostępnych funkcjach jądra w zależności od typu filtra.
Artykuł ma na celu uzupełnienie braków licznych materiałów na temat XDP. Po pierwsze, udostępniają gotowy kod, który od razu omija funkcje XDP: jest przygotowany do weryfikacji lub jest zbyt prosty, aby sprawiać problemy. Kiedy następnie próbujesz napisać kod od zera, nie masz pojęcia, co zrobić z typowymi błędami. Po drugie, nie omówiono sposobów lokalnego testowania XDP bez maszyny wirtualnej i sprzętu, mimo że wiążą się one z pewnymi pułapkami. Tekst przeznaczony jest dla programistów znających sieci i Linuksa zainteresowanych XDP i eBPF.
W tej części zrozumiemy szczegółowo jak jest zbudowany filtr XDP i jak go przetestować, następnie napiszemy prostą wersję dobrze znanego mechanizmu plików cookie SYN na poziomie przetwarzania pakietów. Nie będziemy jeszcze tworzyć „białej listy”.
zweryfikowani klienci, prowadź liczniki i zarządzaj filtrem - wystarczy logów.
Będziemy pisać w C – nie jest to modne, ale praktyczne. Cały kod jest dostępny na GitHubie poprzez link na końcu i jest podzielony na zatwierdzenia zgodnie z etapami opisanymi w artykule.
Zrzeczenie się. W trakcie tego artykułu opracuję mini-rozwiązanie zapobiegające atakom DDoS, ponieważ jest to realistyczne zadanie dla XDP i mojej dziedziny specjalizacji. Jednak głównym celem jest zrozumienie technologii, nie jest to przewodnik po tworzeniu gotowych zabezpieczeń. Kod tutoriala nie jest zoptymalizowany i pomija pewne niuanse.
Krótki przegląd XDP
Zarysuję tylko najważniejsze punkty, aby nie powielać dokumentacji i istniejących artykułów.
Zatem kod filtra jest ładowany do jądra. Przychodzące pakiety są przekazywane do filtra. W rezultacie filtr musi podjąć decyzję: przekazać pakiet do jądra (XDP_PASS), upuść pakiet (XDP_DROP) lub odeślij go (XDP_TX). Filtr może zmienić pakiet, jest to szczególnie prawdziwe w przypadku XDP_TX. Można także przerwać program (XDP_ABORTED) i zresetuj pakiet, ale jest to analogiczne assert(0) - do debugowania.
Maszyna wirtualna eBPF (rozszerzony filtr pakietów Berkley) została celowo uproszczona, aby jądro mogło sprawdzić, czy kod nie zapętla się i nie uszkadza pamięci innych osób. Łączne ograniczenia i kontrole:
Pętle (do tyłu) są zabronione.
Istnieje stos danych, ale nie ma funkcji (wszystkie funkcje C muszą być wstawione).
Dostęp do pamięci poza stosem i buforem pakietów jest zabroniony.
Rozmiar kodu jest ograniczony, ale w praktyce nie ma to większego znaczenia.
Dozwolone są tylko wywołania specjalnych funkcji jądra (pomocników eBPF).
Projektowanie i instalacja filtra wygląda następująco:
Kod źródłowy (np kernel.c) jest kompilowany do obiektu (kernel.o) dla architektury maszyny wirtualnej eBPF. Od października 2019 r. kompilacja do eBPF jest obsługiwana przez Clang i obiecana w GCC 10.1.
Jeśli ten kod obiektowy zawiera wywołania struktur jądra (na przykład tabel i liczników), ich identyfikatory są zastępowane zerami, co oznacza, że taki kod nie może zostać wykonany. Przed załadowaniem do jądra należy zastąpić te zera identyfikatorami konkretnych obiektów utworzonych poprzez wywołania jądra (połącz kod). Możesz to zrobić za pomocą zewnętrznych narzędzi lub możesz napisać program, który połączy i załaduje określony filtr.
Jądro sprawdza załadowany program. Sprawdzany jest brak cykli oraz nieprzekroczenie granic pakietów i stosów. Jeżeli weryfikator nie jest w stanie udowodnić, że kod jest poprawny, program zostaje odrzucony – trzeba umieć go zadowolić.
Po pomyślnej weryfikacji jądro kompiluje kod obiektowy architektury eBPF do kodu maszynowego architektury systemu (just-in-time).
Program podłącza się do interfejsu i rozpoczyna przetwarzanie pakietów.
Ponieważ XDP działa w jądrze, debugowanie odbywa się przy użyciu dzienników śledzenia, a w rzeczywistości pakietów, które program filtruje lub generuje. Jednak eBPF dba o to, aby pobrany kod był bezpieczny dla systemu, dzięki czemu możesz eksperymentować z XDP bezpośrednio na lokalnym systemie Linux.
Przygotowanie środowiska
montaż
Clang nie może bezpośrednio wygenerować kodu obiektowego dla architektury eBPF, dlatego proces składa się z dwóch etapów:
Skompiluj kod C do kodu bajtowego LLVM (clang -emit-llvm).
Konwertuj kod bajtowy na kod obiektowy eBPF (llc -march=bpf -filetype=obj).
Podczas pisania filtra przyda się kilka plików z funkcjami pomocniczymi i makrami z testów jądra. Ważne jest, aby były zgodne z wersją jądra (KVER). Pobierz je do helpers/:
KDIR zawiera ścieżkę do nagłówków jądra, ARCH - architektura systemu. Ścieżki i narzędzia mogą się nieznacznie różnić w zależności od dystrybucji.
Przykład różnic dla Debiana 10 (jądro 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 połącz katalog z nagłówkami pomocniczymi i kilkoma katalogami z nagłówkami jądra. Symbol __KERNEL__ oznacza, że nagłówki UAPI (userspace API) są zdefiniowane dla kodu jądra, ponieważ filtr jest wykonywany w jądrze.
Ochronę stosu można wyłączyć (-fno-stack-protector), ponieważ weryfikator kodu eBPF nadal sprawdza naruszenia stosu poza granicami. Warto od razu włączyć optymalizacje, bo wielkość kodu bajtowego eBPF jest ograniczona.
Zacznijmy od filtra, który przepuszcza wszystkie pakiety i nic nie robi:
Zespół make zbiera xdp_filter.o. Gdzie teraz spróbować?
Stanowisko badawcze
Stanowisko musi zawierać dwa interfejsy: na którym będzie stał filtr oraz z którego będą wysyłane pakiety. Muszą to być pełnoprawne urządzenia linuksowe z własnymi adresami IP, aby sprawdzić, jak zwykłe aplikacje współpracują z naszym filtrem.
Odpowiednie są dla nas urządzenia typu veth (wirtualny Ethernet): jest to para wirtualnych interfejsów sieciowych „połączonych” bezpośrednio ze sobą. Możesz je utworzyć w ten sposób (w tej sekcji wszystkie polecenia ip przeprowadzane są od root):
ip link add xdp-remote type veth peer name xdp-local
Tutaj xdp-remote и xdp-local — nazwy urządzeń. NA xdp-local (192.0.2.1/24) zostanie podłączony filtr z xdp-remote (192.0.2.2/24) ruch przychodzący będzie wysyłany. Istnieje jednak problem: interfejsy znajdują się na tej samej maszynie, a Linux nie będzie przesyłał ruchu do jednego z nich przez drugi. Można to rozwiązać za pomocą trudnych zasad iptables, ale będą musieli zmienić pakiety, co jest niewygodne przy debugowaniu. Lepiej jest używać sieciowych przestrzeni nazw (zwanych dalej netns).
Sieciowa przestrzeń nazw zawiera zestaw interfejsów, tablic routingu i reguł NetFilter, które są odizolowane od podobnych obiektów w innych sieciach. Każdy proces działa w przestrzeni nazw i ma dostęp tylko do obiektów tej sieci. Domyślnie system ma jedną sieciową przestrzeń nazw dla wszystkich obiektów, więc możesz pracować w Linuksie i nie znać się na netns.
Utwórzmy nową przestrzeń nazw xdp-test i przenieś go tam xdp-remote.
ip netns add xdp-test
ip link set dev xdp-remote netns xdp-test
Następnie rozpoczyna się proces xdp-test, nie „zobaczę” xdp-local (domyślnie pozostanie w netns) i przy wysyłaniu pakietu do 192.0.2.1 przejdzie przez niego xdp-remoteponieważ jest to jedyny interfejs w sieci 192.0.2.0/24 dostępny dla tego procesu. Działa to również w odwrotnym kierunku.
Podczas poruszania się pomiędzy sieciami interfejs ulega awarii i traci swój adres. Aby skonfigurować interfejs w netns, musisz uruchomić ip ... w tej przestrzeni nazw poleceń 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
Jak widać, nie różni się to od ustawienia xdp-local w domyślnej przestrzeni nazw:
ip address add 192.0.2.1/24 dev xdp-local
ip link set xdp-local up
Jeśli biegniesz tcpdump -tnevi xdp-local, możesz zobaczyć, które pakiety zostały wysłane z xdp-test, są dostarczane do tego interfejsu:
ip netns exec xdp-test ping 192.0.2.1
Wygodne jest uruchomienie powłoki xdp-test. W repozytorium znajduje się skrypt automatyzujący pracę ze stoiskiem, np. za pomocą komendy możesz skonfigurować stoisko sudo ./stand up i usuń go sudo ./stand down.
Rysunek kalkowy
Filtr jest powiązany z urządzeniem w następujący sposób:
ip -force link set dev xdp-local xdp object xdp_filter.o verbose
klucz -force potrzebne do połączenia nowego programu, jeśli inny jest już połączony. „Brak wiadomości to dobra wiadomość” nie dotyczy tego polecenia, w każdym razie wniosek jest obszerny. wskazać verbose opcjonalne, ale wraz z nim pojawia się raport z pracy weryfikatora kodu z listą montażu:
Verifier analysis:
0: (b7) r0 = 2
1: (95) exit
Odłącz program od interfejsu:
ip link set dev xdp-local xdp off
W skrypcie są to polecenia sudo ./stand attach и sudo ./stand detach.
Możesz się o tym upewnić, dołączając filtr ping nadal działa, ale czy program działa? Dodajmy logi. Funkcjonować bpf_trace_printk() podobny do printf(), ale obsługuje tylko trzy argumenty inne niż wzorzec i ograniczoną listę specyfikatorów. Makro bpf_printk() upraszcza rozmowę.
Z tego powodu wyniki debugowania znacznie zawyżają wynikowy kod.
Wysyłanie pakietów XDP
Zmieńmy filtr: pozwólmy mu odsyłać wszystkie przychodzące pakiety. Jest to nieprawidłowe z punktu widzenia sieci, ponieważ konieczna byłaby zmiana adresów w nagłówkach, ale teraz praca jest w zasadzie ważna.
Biegnij tcpdump na xdp-remote. Powinien pokazywać identyczne wychodzące i przychodzące żądanie echa ICMP i przestać wyświetlać odpowiedź echa ICMP. Ale tego nie widać. Okazuje się, że do pracy XDP_TX w programie pt xdp-localmusido interfejsu pary xdp-remote przydzielono mu także program, nawet jeśli był pusty, i został wychowany.
Skąd to wiedziałem?
Śledź ścieżkę pakietu w jądrze Mechanizm zdarzeń perf pozwala, nawiasem mówiąc, na użycie tej samej maszyny wirtualnej, czyli eBPF służy do deasemblacji z eBPF.
Ze zła trzeba zrobić dobro, bo nie ma innego wyjścia.
Jeśli zamiast tego pokazane są tylko ARP, musisz usunąć filtry (to robi sudo ./stand detach), odpuść ping, a następnie ustaw filtry i spróbuj ponownie. Problemem jest filtr XDP_TX ważne zarówno na ARP, jak i na stosie
przestrzenie nazw xdp-test udało się „zapomnieć” adresu MAC 192.0.2.1, nie będzie w stanie rozpoznać tego adresu IP.
Stwierdzenie problemu
Przejdźmy do postawionego zadania: napisz mechanizm cookies SYN na XDP.
SYN Flood pozostaje popularnym atakiem DDoS, którego istota jest następująca. Po nawiązaniu połączenia (uzgadnianie TCP) serwer odbiera komunikat SYN, przydziela zasoby dla przyszłego połączenia, odpowiada pakietem SYNACK i czeka na potwierdzenie. Osoba atakująca po prostu wysyła tysiące pakietów SYN na sekundę ze sfałszowanych adresów z każdego hosta w wielotysięcznym botnecie. Serwer jest zmuszony do przydzielenia zasobów natychmiast po nadejściu pakietu, ale zwalnia je po dużym czasie oczekiwania, w wyniku czego następuje wyczerpanie pamięci lub limitów, nowe połączenia nie są akceptowane, a usługa jest niedostępna.
Jeśli nie przydzielasz zasobów na podstawie pakietu SYN, a jedynie odpowiadasz pakietem SYNACK, jak serwer może zrozumieć, że pakiet ACK, który przybył później, odnosi się do pakietu SYN, który nie został zapisany? W końcu osoba atakująca może również wygenerować fałszywe potwierdzenia. Celem pliku cookie SYN jest jego zakodowanie seqnum parametry połączenia w postaci skrótu adresów, portów i zmieniającej się soli. Jeśli potwierdzenie dotarło przed zmianą soli, możesz ponownie obliczyć skrót i porównać go z nim acknum. Kuźnia acknum atakujący nie może, ponieważ sól zawiera sekret i nie będzie miał czasu na jego przejrzenie ze względu na ograniczony kanał.
Plik cookie SYN jest od dawna zaimplementowany w jądrze Linuksa i może nawet zostać automatycznie włączony, jeśli pliki SYN dotrą zbyt szybko i masowo.
Program edukacyjny na temat uzgadniania protokołu TCP
Protokół TCP zapewnia transmisję danych w postaci strumienia bajtów, na przykład żądania HTTP są przesyłane przez protokół TCP. Strumień przesyłany jest fragmentami w pakietach. Wszystkie pakiety TCP mają flagi logiczne i 32-bitowe numery sekwencyjne:
Kombinacja flag określa rolę konkretnego pakietu. Flaga SYN wskazuje, że jest to pierwszy pakiet nadawcy w połączeniu. Flaga ACK oznacza, że nadawca otrzymał wszystkie dane połączenia aż do bajtu acknum. Pakiet może mieć kilka flag i jest wywoływany poprzez ich kombinację, na przykład pakiet SYNACK.
Numer sekwencyjny (seqnum) określa przesunięcie w strumieniu danych dla pierwszego bajtu przesyłanego w tym pakiecie. Przykładowo, jeśli w pierwszym pakiecie zawierającym X bajtów danych liczba ta wynosiła N, w kolejnym pakiecie z nowymi danymi będzie to N+X. Na początku połączenia każda ze stron losowo wybiera ten numer.
Numer potwierdzenia (acknum) - to samo przesunięcie co seqnum, ale nie określa numeru przesyłanego bajtu, ale numer pierwszego bajtu od odbiorcy, którego nadawca nie widział.
Na początku połączenia strony muszą się zgodzić seqnum и acknum. Klient wysyła ze swoim pakietem SYN seqnum = X. Serwer odpowiada pakietem SYNACK, w którym go zapisuje seqnum = Y i eksponuje acknum = X + 1. Klient odpowiada na SYNACK pakietem ACK, gdzie seqnum = X + 1, acknum = Y + 1. Następnie rozpoczyna się właściwy transfer danych.
Jeśli partner nie potwierdzi odbioru pakietu, protokół TCP wyśle go ponownie po upływie limitu czasu.
Dlaczego pliki cookie SYN nie zawsze są używane?
Po pierwsze, jeśli utracono SYNACK lub ACK, trzeba będzie poczekać na ponowne wysłanie - konfiguracja połączenia ulegnie spowolnieniu. Po drugie, w pakiecie SYN – i tylko w nim! — przesyłanych jest szereg opcji, które wpływają na dalsze działanie połączenia. Nie zapamiętując przychodzących pakietów SYN, serwer ignoruje te opcje; klient nie wyśle ich w kolejnych pakietach. TCP może w tym przypadku zadziałać, ale przynajmniej na początkowym etapie jakość połączenia spadnie.
Z perspektywy pakietów program XDP musi wykonywać następujące czynności:
odpowiedz SYN za pomocą SYNACK i pliku cookie;
odpowiedz na ACK za pomocą RST (rozłącz);
odrzuć pozostałe pakiety.
Pseudokod algorytmu wraz z parsowaniem pakietów:
Если это не Ethernet,
пропустить пакет.
Если это не IPv4,
пропустить пакет.
Если адрес в таблице проверенных, (*)
уменьшить счетчик оставшихся проверок,
пропустить пакет.
Если это не TCP,
сбросить пакет. (**)
Если это SYN,
ответить SYN-ACK с cookie.
Если это ACK,
если в acknum лежит не cookie,
сбросить пакет.
Занести в таблицу адрес с N оставшихся проверок. (*)
Ответить RST. (**)
В остальных случаях сбросить пакет.
Jeden (*) zaznaczone są punkty, w których należy zarządzać stanem systemu - na pierwszym etapie można się bez nich obejść, po prostu implementując uzgadnianie TCP z generowaniem ciasteczka SYN jako kolejnego numeru.
Na miejscu (**), chociaż nie mamy tabeli, pominiemy pakiet.
Implementacja uzgadniania TCP
Parsowanie pakietu i weryfikacja kodu
Będziemy potrzebować struktur nagłówków sieci: Ethernet (uapi/linux/if_ether.h), IPv4 (uapi/linux/ip.h) i TCP (uapi/linux/tcp.h). Tego ostatniego nie udało mi się połączyć ze względu na błędy związane z atomic64_t, musiałem skopiować niezbędne definicje do kodu.
Wszystkie funkcje wyróżnione w C ze względu na czytelność muszą być wstawione w momencie wywołania, ponieważ weryfikator eBPF w jądrze zabrania wycofywania się, czyli w rzeczywistości pętli i wywołań funkcji.
Makro LOG() wyłącza drukowanie w kompilacji wydania.
Program jest przenośnikiem funkcji. Każdy otrzymuje pakiet, w którym podświetlony jest nagłówek odpowiedniego poziomu, na przykład process_ether() oczekuje, że zostanie wypełniony ether. Na podstawie wyników analizy pola funkcja może przekazać pakiet na wyższy poziom. Wynikiem funkcji jest akcja XDP. Na razie procedury obsługi SYN i ACK przekazują wszystkie pakiety.
Kluczowy ciąg invalid access to packet, off=13 size=1, R7(id=0,off=0,r=0): Istnieją ścieżki wykonania, gdy trzynasty bajt od początku bufora znajduje się na zewnątrz pakietu. Z zestawienia trudno zrozumieć, o której linii mówimy, ale jest tam numer instrukcji (12) i dezasembler pokazujący linie kodu źródłowego:
co jasno pokazuje, że problem istnieje ether. Zawsze tak będzie.
Odpowiedź dla SYN
Celem na tym etapie jest wygenerowanie prawidłowego pakietu SYNACK ze stałym seqnum, który w przyszłości zostanie zastąpiony plikiem cookie SYN. Wszystkie zmiany zachodzą w process_tcp_syn() i okolic.
Weryfikacja pakietu
Co dziwne, oto najbardziej niezwykły wiersz, a raczej komentarz do niego:
Podczas pisania pierwszej wersji kodu wykorzystano jądro 5.1, dla którego weryfikatora istniała różnica pomiędzy data_end и (const void*)ctx->data_end. W chwili pisania tego tekstu w jądrze 5.3.1 nie występował ten problem. Możliwe, że kompilator uzyskiwał dostęp do zmiennej lokalnej inaczej niż do pola. Morał z tej historii: uproszczenie kodu może pomóc, gdy występuje dużo zagnieżdżeń.
Następnie przeprowadzane są rutynowe kontrole długości na chwałę weryfikatora; O MAX_CSUM_BYTES poniżej.
Zamień porty TCP, adresy IP i adresy MAC. Biblioteka standardowa nie jest dostępna z poziomu programu XDP, więc memcpy() — makro, które ukrywa cechy Clanga.
Sumy kontrolne IPv4 i TCP wymagają dodania wszystkich 16-bitowych słów w nagłówkach i zapisywany jest w nich rozmiar nagłówków, to znaczy nieznany w czasie kompilacji. Stanowi to problem, ponieważ weryfikator nie pominie normalnej pętli prowadzącej do zmiennej granicznej. Ale rozmiar nagłówków jest ograniczony: do 64 bajtów każdy. Możesz utworzyć pętlę ze stałą liczbą iteracji, która może zakończyć się wcześniej.
Zaznaczam, że jest RFC 1624 o tym, jak częściowo przeliczyć sumę kontrolną, jeśli zmienione zostaną tylko stałe słowa pakietów. Metoda ta nie jest jednak uniwersalna i jej wdrożenie byłoby trudniejsze w utrzymaniu.
Funkcja obliczania sumy kontrolnej:
#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;
}
Chociaż size weryfikowane przez kod wywołujący, konieczny jest drugi warunek wyjścia, aby weryfikator mógł udowodnić zakończenie pętli.
W przypadku słów 32-bitowych zaimplementowano prostszą wersję:
INTERNAL u32
sum16_32(u32 v) {
return (v >> 16) + (v & 0xffff);
}
Właściwie przeliczam sumy kontrolne i wysyłam pakiet z powrotem:
Funkcja carry() tworzy sumę kontrolną z 32-bitowej sumy 16-bitowych słów, zgodnie z RFC 791.
Weryfikacja uzgadniania TCP
Filtr poprawnie nawiązuje połączenie z netcat, brakuje końcowego ACK, na który Linux odpowiedział pakietem RST, ponieważ stos sieciowy nie otrzymał SYN - został przekonwertowany na SYNACK i odesłany - a z punktu widzenia systemu operacyjnego przybył pakiet niezwiązany z otwarciem znajomości.
$ sudo ip netns exec xdp-test nc -nv 192.0.2.1 6666
192.0.2.1 6666: Connection reset by peer
Ważne jest, aby sprawdzić pełnoprawne aplikacje i obserwować tcpdump na xdp-remote ponieważ na przykład hping3 nie reaguje na nieprawidłowe sumy kontrolne.
plik cookie SYN
Z punktu widzenia XDP sama weryfikacja jest banalna. Algorytm obliczeniowy jest prymitywny i prawdopodobnie podatny na ataki wyrafinowanego atakującego. Na przykład jądro Linuksa wykorzystuje kryptograficzny SipHash, ale jego implementacja dla XDP wyraźnie wykracza poza zakres tego artykułu.
Wprowadzono dla nowych TODO związanych z komunikacją zewnętrzną:
Program XDP nie może zapisać cookie_seed (tajna część soli) w zmiennej globalnej, potrzebujesz pamięci w jądrze, której wartość będzie okresowo aktualizowana z niezawodnego generatora.
Jeżeli w pakiecie ACK pasuje plik cookie SYN, nie musisz drukować komunikatu, ale zapamiętaj adres IP zweryfikowanego klienta, aby móc dalej przekazywać od niego pakiety.
Co prawda nie ma listy zweryfikowanych adresów IP, ale przed samym powodzią SYN nie będzie ochrony, ale oto reakcja na powódź ACK uruchomioną następującym poleceniem:
sudo ip netns exec xdp-test hping3 --flood -A -s 1111 -p 2222 192.0.2.1
Czasami eBPF w ogóle, a XDP w szczególności przedstawiane są bardziej jako zaawansowane narzędzie administratora niż platforma programistyczna. Rzeczywiście, XDP jest narzędziem do zakłócania przetwarzania pakietów przez jądro, a nie alternatywą dla stosu jądra, jak DPDK i inne opcje obejścia jądra. Z drugiej strony XDP pozwala na implementację dość złożonej logiki, którą ponadto można łatwo aktualizować bez przerywania przetwarzania ruchu. Weryfikator nie stwarza dużych problemów, osobiście nie odmówiłbym tego w przypadku części kodu przestrzeni użytkownika.
W drugiej części, jeśli temat będzie ciekawy, uzupełnimy tabelę zweryfikowanych klientów i rozłączeń, zaimplementujemy liczniki oraz napiszemy narzędzie przestrzeni użytkownika do zarządzania filtrem.