Powrót do strony głównej

ICMP-tunel w jądrze Linux: enkapsulacja TCP/UDP

Artykuł szczegółowo omawia implementację ICMP-tunelu w jądrze Linux, enkapsulującego ruch TCP/UDP w żądania ICMP-echo. Omówiono hooki Netfilter, pracę ze sk_buff, tasklety i wstrzykiwanie pakietów do loopback.

Zanurzenie w jądrze: jak TCP/UDP ukrywa się w ICMP-echo
Advertisement 728x90

# Implementacja tunelu ICMP w jądrze Linuksa: enkapsulacja TCP/UDP w żądania echo

Tunel ICMP na poziomie jądra Linuksa pozwala na enkapsulację ruchu TCP/UDP wewnątrz pakietów ICMP typu Echo Request, omijając standardowe filtry sieciowe. Taki podejście jest przydatne do badań stosu sieciowego, testowania przechwytywania pakietów oraz zrozumienia działania Netfilter. W artykule omawiana jest architektura modułu jądra realizującego translację ruchu za pomocą haków NF_INET_POST_ROUTING i NF_INET_LOCAL_IN z wykorzystaniem taskletów do asynchronicznego wysyłania.

Architektura tunelu ICMP w jądrze Linuksa

Moduł składa się z trzech kluczowych komponentów: dwóch haków Netfilter oraz taskleta do wysyłania pakietów. Hak NF_INET_POST_ROUTING przechwytuje wychodzące pakiety TCP/UDP przed ich wysłaniem do sieci, przekształca je w żądania echo ICMP i przekazuje sterowanie do taskleta. Drugi hak — NF_INET_LOCAL_IN — przechwytuje przychodzące pakiety ICMP, wyciąga oryginalny ruch i kieruje go do interfejsu loopback w celu dostarczenia aplikacjom. Tasklet zapewnia opóźnioną wysyłkę pakietów za pomocą dev_queue_xmit, minimalizując blokady w kontekście przerwania.

Rejestracja haków odbywa się z priorytetem NF_IP_PRI_FIRST, aby zagwarantować pierwszą obsługę. Jest to kluczowe, ponieważ ingerencja innych modułów przed naszym może zakłócić integralność enkapsulacji lub dekapsulacji. Do zarządzania pamięcią używana jest struktura sk_buff — podstawowa struktura stosu sieciowego Linuksa, wymagająca ostrożnego rezerwowania nagłówków i poprawnego zwalniania za pomocą kfree_skb w przypadku błędów.

Google AdInline article slot

Szczegółowa analiza output_hook i create_packet_output

Funkcja output_hook jest wywoływana dla każdego wychodzącego pakietu. Deleguje tworzenie powłoki ICMP funkcji create_packet_output, która:

  • Sprawdza, czy protokół to TCP lub UDP — jeśli nie, zwraca NULL, a pakiet kontynuuje swoją trasę bez zmian.
  • Pobiera adres MAC odbiorcy za pomocą __ipv4_neigh_lookup, co jest niezbędne do utworzenia nagłówka Ethernet.
  • Liniaryzuje sk_buff wywołaniem skb_linearize, ponieważ dalsze operacje kopiowania danych wymagają ciągłego bufora.
  • Określa typ protokołu transportowego (0 dla UDP, 1 dla TCP), długość nagłówka i rozmiar ładunku.
  • Alokuje nowy sk_buff z uwzględnieniem zarezerwowanej przestrzeni na nagłówki (LL_RESERVED_SPACE) oraz danych ogonowych (needed_tailroom).
  • Krok po kroku tworzy nagłówki: Ethernet, IPv4, ICMP, kopiując nagłówek transportowy i dane do ciała ICMP.
  • Oblicza sumy kontrolne dla IP i ICMP za pomocą ip_fast_csum i ip_compute_csum.
  • Zwraca gotowy pakiet do wysłania.

Kluczowy element — wykorzystanie pola icmp->un.echo.id do przekazywania informacji służbowych o typie oryginalnego protokołu i identyfikatorze strumienia. Dzięki temu strona odbierająca może poprawnie odtworzyć oryginalny pakiet bez dodatkowych metadanych poza strukturą ICMP.

Obsługa przychodzących pakietów i routowanie loopback

Po stronie odbierającej hak input_hook analizuje każdy przychodzący pakiet ICMP. Jeśli pasuje do formatu tunelu (Echo Request z znanym wzorcem w polu ID), moduł:

Google AdInline article slot
  • Wyciąga nagłówek transportowy i dane z ciała ICMP.
  • Tworzy nowy sk_buff, symulujący przychodzący pakiet TCP/UDP.
  • Ustawia urządzenie docelowe na interfejs loopback (dev_set_name(skb, "lo")).
  • Zmienia adresy MAC na localhost i wywołuje netif_rx_ni() w celu wstrzyknięcia pakietu do stosu sieciowego.

To zmusza jądro do przetworzenia pakietu tak, jakby przyszedł z zewnątrz, ale przez interfejs lo. Aplikacje otrzymują dane bez zmian, nieświadome enkapsulacji. Ważne, że nie używany jest NF_STOLEN — pakiet nie jest „kradziony", lecz zastępowany, dlatego po udanym wstrzyknięciu zwracany jest NF_ACCEPT.

Krytyczne szczegóły techniczne i ograniczenia

Implementacja napotyka szereg ograniczeń technicznych:

  • Fragmentacja: Pakiety ICMP mogą być fragmentowane na trasie, ale obecna implementacja nie obsługuje fragmentów — zakłada MTU wystarczające do pełnej enkapsulacji.
  • Bezpieczeństwo: Brak szyfrowania lub uwierzytelniania czyni tunel podatnym na fałszowanie i ataki MITM.
  • Wydajność: Każdy pakiet wymaga alokacji nowego sk_buff, kopiowania danych i obliczania sum kontrolnych — co obciąża CPU.
  • Tylko IPv4: Moduł nie wspiera IPv6, ponieważ używa ip_hdr i __ipv4_neigh_lookup.
  • Zależność od MAC: Wymaga wpisu ARP dla docelowego IP, w przeciwnym razie pakiet jest odrzucany.

Pomimo ograniczeń, projekt doskonale nadaje się do celów edukacyjnych: obejmuje pracę z Netfilter, zarządzanie pamięcią jądra, tworzenie nagłówków sieciowych i interakcje między warstwami modelu OSI w czasie rzeczywistym.

Google AdInline article slot

Co ważne

  • Tunel ICMP enkapsuluje TCP/UDP w żądania Echo, umożliwiając ominięcie niektórych filtrów sieciowych.
  • Używane są haki Netfilter z maksymalnym priorytetem do przechwytywania ruchu przed/po routingu.
  • Tasklety zapewniają asynchroniczną wysyłkę, nie blokując kontekstu przerwania.
  • Po stronie odbierającej pakiety wstrzykiwane są do loopback dla przezroczystego dostarczenia aplikacjom.
  • Implementacja jest edukacyjna — nie nadaje się do produkcji z powodu braku zabezpieczeń i obsługi fragmentów.

— Editorial Team

Advertisement 728x90

Czytaj dalej