Podstawę funkcjonowania każdego społeczeństwa stanowi komunikacja we wszelkich odmianach. Najważniejszą i najpopularniejszą jej formą jest mowa i związany z nią język ludzki, będący jedną z pierwszych umiejętności, które zdobywa jednostka.
Wraz z rozwojem cywilizacyjnym komunikacja ewoluowała, co objawiało się w szczególności rozwojem metod przekazywania informacji na odległość. Plemiona afrykańskie używały w tym celu sygnałów dźwiękowych wydawanych przez potężne bębny, Indianie korzystali z systemu znaków dymnych, zaś Rzymianie za pomocą umieszczonych na wzgórzach luster przesyłali impulsy świetlne. W 1838 roku został zbudowany telegraf elektryczny wykorzystujący alfabet Morse'a1), co stało się podwaliną współczesnej telekomunikacji.
Obecnie informacje przesyłane są przez nowoczesne trakty cyfrowe, które pozwalają na szybką transmisję danych na duże odległości. Systemy komputerowe, które jeszcze kilkadziesiąt lat temu z reguły pracowały w izolacji, dziś łączone są w sieci umożliwiające współdzielenie zasobów. Telekomunikacja i informatyka stały się wzajemnie zależne, co zaowocowało powstaniem teleinformatyki, czyli nauki łączącej te dziedziny wiedzy.
Tematem niniejszej pracy są lokalne sieci komputerowe oraz ich bezpieczeństwo, ze szczególnym naciskiem na problem uwierzytelniania. Program komputerowy, który powstał w jej ramach, pozwala na demonstrację słabości najpopularniejszej metody zabezpieczania tego typu sieci przed nieupoważnionym dostępem.
W celu ułatwienia czytania zostały wprowadzone konwencje typograficzne. Narzędzia, biblioteki i pakiety oprogramowania pisane są czcionką o stałej szerokości, zaś komponenty aplikacji multispoof są dodatkowo pogrubione. Czcionka o stałej szerokości jest używana także w listingach oraz sesjach powłoki systemowej. Te fragmenty, na które należy zwrócić szczególną uwagę lub stanowią komendy wpisywane przez użytkownika, są pogrubione. Zbiór oznaczeń graficznych, używany jest konsekwentnie na większości rysunków. Adresy URL, z których można pobrać wykorzystywane narzędzia podawane są w przypisach, najczęściej z krótką informacją o funkcjonalności danego programu.
Praca niniejsza powstała w dużej mierze dzięki pomocy wielu życzliwych osób, którym należą się słowa podziękowania.
W pierwszej kolejności chcę wyrazić wdzięczność dr Tomaszowi Surmaczowi za owocną współpracę.
Pragnę serdecznie podziękować moim rodzicom, Krystynie i Janowi Pokrywkom za wszelką pomoc, której nie jestem w stanie opisać, ani wyliczyć.
Za pomoc przy rozwiązywaniu problemów podczas pisania aplikacji, dziękuję Michałowi Pokrywce. Za cierpliwość, cenne dyskusje, wskazówki i pożyteczne uwagi chcę podziękować Krzysztofowi Noskowi, Przemysławowi Plata oraz moim braciom Piotrowi i Przemysławowi Pokrywkom. Chcę także wyrazić wdzięczność wszystkim osobom, tworzącym oprogramowanie, które wykorzystywałem podczas pisania niniejszej pracy oraz aplikacji multispoof.
I would like to thank especially Guy Harris from tcpdump project for help with libpcap patch inclusion, and John Bothe for initial patch code.
W tym rozdziale zostanie przedstawiona koncepcja sieci LAN, zagrożenia jakie w nich występują oraz praktyczne problemy, związane z ich wykorzystaniem przez intruzów. Główny nacisk zostanie położony na omówienie popularnego sposobu uwierzytelniania użytkowników sieci, którego słabości będą zademonstrowane praktycznie w następnych rozdziałach.
Ze względu na fakt, że tematyka sieci lokalnych to szeroki zakres dziedziny IT, jaką są sieci komputerowe, należy uściślić obszar zainteresowania tej pracy. Są nim lokalne sieci komputerowe, zbudowane z wykorzystaniem technologii Ethernet [Net99 ] lub pochodnych i wykorzystywane do płatnego świadczenia usługi dostępu do Internetu. Dotyczy to tzw. sieci osiedlowych, zarówno amatorskich (non-profit) jak i profesjonalnych. Te pierwsze są zarządzane przez osoby, które nie są zainteresowane zyskiem, zaś opłaty pobierane od korzystających z sieci są w całości przeznaczane na zwrot kosztów jej utrzymania. W przeciwieństwie do nich, sieci profesjonalne są własnością firm (nazywanych operatorami lub dostawcami usługi dostępu do Internetu), które opierają swoją działalność na przychodach uzyskiwanych z abonamentu.
Głównym powodem tego, że sieci osiedlowe istnieją i rozwijają się, jest niska cena infrastruktury ethernetowej w zakresie instalacji i utrzymania. Urządzenia wchodzące w skład takiej sieci są łatwo dostępne i tanie, w przeciwieństwie do sprzętu niezbędnego w innych rozwiązaniach szerokopasmowych, jak technologia DSL2) czy telewizja kablowa3). Na infrastrukturę osiedlowego Ethernetu składają się najczęściej tylko trzy rodzaje elementów: przełączniki sieciowe, kable miedziane lub światłowody oraz karty sieciowe w komputerach. Dostęp do Internetu zapewnia router, który w mniejszych sieciach bywa implementowany na zwykłym, niedrogim komputerze klasy PC.
Dostęp do Internetu jest udzielany użytkownikom, którzy uregulowali należności finansowe. Natomiast klienci, którzy zalegają z opłatami powinni tracić dostęp do usługi, najlepiej w dniu przekroczenia terminu płatności. Najpewniejszą metodą odcięcia użytkownika od sieci jest wyłączenie z najbliższego przełącznika kabla, który do niego prowadzi. Jest to jednak kłopotliwe, ponieważ wymaga wykonania pracy fizycznej, zaś przełączniki sieciowe często instalowane są w miejscach trudno dostępnych, jak piwnice, strychy, słupy lub mieszkania osób prywatnych. Dodatkowo, niektórzy dostawcy sieci osiedlowych zezwalają także na bezpłatny lub obciążony mniejszą opłatą dostęp do zasobów sieci lokalnej, pod warunkiem niekorzystania z Internetu.
Jak powiązać transmisje przepływające przez router operatora z człowiekiem, którego komputer je wygenerował4)?Odpowiedzią jest proces uwierzytelniania. Aby uzyskać dostęp do usługi, komputer użytkownika musi przedstawić się, wykorzystując do tego informacje uzgodnione wcześniej między jego właścicielem i operatorem sieci.
Jeśli hosty w sieci są uwierzytelnione, oznacza to, że jest możliwe ich rozróżnienie, co w efekcie pozwala na oferowanie spersonalizowanych usług przez dostawcę. Takimi usługami są na przykład możliwość wyboru przepustowości dostępu do Internetu przez klienta, blokowanie niepożądanych treści, dostęp do informacji billingowych, ogłoszenia i reklamy.
Najpopularniejsza metoda uwierzytelniania w sieciach osiedlowych wykorzystuje to, że każdy komputer posiada kartę sieciową, zaś każda karta ma przypisany przez producenta unikalny adres sprzętowy MAC (ang. Medium Access Control). Na jego podstawie serwer DHCP5), stanowiący część infrastruktury sieciowej, przydziela mu adres IP, który jest wymagany do komunikacji. Ponieważ serwery DHCP najczęściej konfigurowane są w ten sposób, że dla danego adresu MAC przydzielają zawsze ten sam adres IP, zaś użytkownicy rzadko wymieniają karty sieciowe, adres ten może być wykorzystywany do uwierzytelniania.
Najczęściej router, który zapewnia dostęp do Internetu, jest konfigurowany tak, aby w procesie uwierzytelniania brały udział oba adresy: sprzętowy oraz IP. Dzieje się tak, ponieważ ten drugi adres użytkownik może w trywialny sposób zmienić, zaś weryfikacja zgodności obu adresów pozwala na wykrycie tego typu oszustwa. Mimo tego, autorowi znane są sieci osiedlowe, które nie stosują nawet tego, podstawowego zabezpieczenia.
Niski koszt sieci Ethernet, prostota jej instalacji oraz wysoka elastyczność użytkowania są niestety okupione podatnością na wiele ataków, obniżających jej bezpieczeństwo zarówno w sensie poufności i integralności transmisji, jak i dostępności. Wydaje się, że głównymi źródłami tych problemów są protokół ARP oraz technika dynamicznego przełączania ramek.
W sieciach Ethernet opartych na popularnych, tanich przełącznikach lub koncentratorach istnieje niebezpieczeństwo podszycia się poprzez zmianę adresu. Możliwe jest to zarówno w warstwie trzeciej modelu OSI, poprzez zmianę numeru IP6), jak i w warstwie drugiej poprzez zmianę adresu MAC. W popularnych systemach operacyjnych modyfikacja tego drugiego jest równie prosta jak pierwszego. Jednak zmiana adresu MAC stanowi z pewnych względów wiedzę tajemną, dostępną tylko wybranym7). Rozpowszechniony jest natomiast pogląd, że adres MAC, tzw. adres sprzętowy jest zapisany na stałe w urządzeniu i nie ma możliwości wpływu na jego wartość poza wymianą karty sieciowej.
Adres MAC jest faktycznie zapisany w pamięci karty, ale zazwyczaj ta pamięć pozwala na zmianę jej zawartości. Prostszą metodą jest jednak programowa zmiana adresu na poziomie sterownika karty sieciowej w systemie operacyjnym. Wreszcie wysyłanie ramek ethernetowych ze sfałszowanym adresem źródłowym jest możliwe także w przestrzeni użytkownika za pomocą odpowiednich bibliotek i interfejsów udostępnianych przez jądro. Więcej informacji na temat generowania ramek z poziomu aplikacji zostało zamieszczonych w podrozdziale 2.2.
Zmiana adresu MAC na adres komputera innego użytkownika, który jest w danej chwili nieaktywny powoduje, że serwer DHCP przydziela jego adres IP i dostęp do Internetu odbywa się w cudzym imieniu. Jest to kradzież usługi, przed którą operator sieci osiedlowej powinien się zabezpieczyć.
Sieci oparte na koncentratorach są podatne na podsłuchiwanie, ponieważ urządzenia te przesyłają otrzymane ramki na wszystkie porty (rysunek 1.1). Pozwala to atakującemu na dostęp do informacji przesyłanych w obrębie segmentu sieci, do którego on należy. Narzędzia do podsłuchiwania popularnie nazywane są snifferami. Najbardziej znanym programem tego typu jest tcpdump8). Podsłuchiwanie jest techniką, która obecnie ma coraz mniejsze znaczenie, ze względu na wypieranie koncentratorów przez przełączniki. W sieciach przełączanych efekty biernego podsłuchiwania są znikome. Jednak podsłuchiwanie nadal jest wykorzystywane przez intruzów w połączeniu z innymi metodami. Więcej o tym można przeczytać w podrozdziale 2.1.
Jest to najbardziej znany typ ataku na sieci lokalne, wykorzystujący słabości protokołu ARP [Gusta i Szmit 2003]. Protokół ten jest używany do mapowania numerów IP na adresy MAC, czyli łączy warstwę trzecią z warstwą drugą, umożliwiając tym samym komunikację w sieci fizycznej. Każdy host w sieci posiada lokalną tablicę ARP. Jeśli wystąpi potrzeba wysłania danych do innego hosta o znanym adresie IP w tym samym segmencie sieci lokalnej, tablica ta jest przeglądana w celu odnalezienia odpowiadającego mu adresu MAC. W przypadku, gdy tablica nie zawiera wpisu dla poszukiwanego adresu IP, system operacyjny wysyła do wszystkich komputerów w sieci lokalnej komunikat ARP Request, z zapytaniem o adres MAC tego hosta. Jeśli w danej chwili komputer o poszukiwanym adresie IP jest obecny w sieci, to wysyła komunikat ARP Reply do hosta, który wysłał zapytanie. Odpowiedź zawiera jego adres MAC, co pozwala na uaktualnienie tablicy ARP i dalszą transmisję.
Jeśli hosty w sieci są skonfigurowane w ten sposób, że pobierają ustawienia sieciowe z serwera DHCP, to atakujący może uruchomić drugi, konkurencyjny serwer, który będzie przydzielał komputerom użytkowników inne ustawienia. Atakujący może w ten sposób wymusić na komputerach, aby przesyłały ruch internetowy do jego maszyny, zamiast do routera. Manipulując wartością maski sieciowej, może także spowodować, że nawet transmisje lokalne będą kierowane do niego. Atakujący uzyskuje wtedy pełną kontrolę nad ruchem, tak jak w przypadku ataku ARP Spoofing.
Inną możliwością jest zmiana adresu serwera DNS na adres maszyny kontrolowanej przez atakującego. Fałszywy serwer DNS natomiast będzie przekierowywał wybrany ruch na host oszusta, który znów przejmuje nad nim pełną kontrolę.
Atakujący może też selektywnie blokować hosty w sieci przez przydzielanie nieprawidłowych adresów, co skutkuje efektem odmowy usługi.
Jeśli host próbuje wysyłać pakiety IP przez router, zaś ten posiada informacje o lepszej trasie, prowadzącej przez bramę znajdującą się w tej samej sieci, to router wysyła do hosta komunikat ICMP Redirect. W komunikacie zawarta jest informacja o adresie routera, którego host powinien użyć aby wysyłane przez niego pakiety trafiły do miejsca przeznaczenia.
Komunikaty te mogą być wysyłane także przez atakującego w celu przekierowania ruchu hosta do kontrolowanej przez niego maszyny12). Maszyna ta uzyskuje pełną kontrolę nad ruchem hosta, zaś efekty są podobne jak w przypadku ataku ARP Spoofing.
Jeśli ataki zapewniające kontrolę nad transmisją nie są wykonalne, zaś celem atakującego jest uniemożliwienie komunikacji w sieci to może posunąć się do prób resetowania połączeń. Polega to na wstrzykiwaniu do sieci pakietów, które służą do awaryjnego zawieszania połączeń TCP i transmisji UDP13). W przypadku protokołu TCP są to segmenty z ustawioną flagą RST, zaś przerywanie połączeń UDP odbywa się z wykorzystaniem komunikatów ICMP Unreachable. Pakiety resetujące wymagają podstawowych informacji o połączeniu jak adresy i porty źródłowe oraz przeznaczenia, a także numery sekwencyjne dla połączeń TCP. Dlatego ten atak jest najbardziej efektywny w połączeniu z podsłuchiwaniem ruchu sieciowego. Z przechwyconego ruchu atakujący wybiera te połączenia, które chce zakończyć.
Inną metodą jest zgadywanie części danych opisujących połączenie, o którym pozostałe informacje są znane. Na przykład jeśli atakujący wie, że dany host ustanowił długotrwałą sesję z innym hostem wykorzystując protokół FTP, to generuje pakiety resetujące z wszystkimi możliwymi kombinacjami portów źródłowych i numerów sekwencyjnych14). Pozostałe dane jak adresy IP i numer portu docelowego, są znane.
Aby czytelnik mógł świadomie korzystać z programu multispoof, a także aby zrozumieć jego budowę, musi znać podstawowe technologie, wykorzystywane przez tę aplikację. W tym rozdziale zostaną przybliżone cztery najważniejsze. Zakłada się, że czytelnik posiada ogólną wiedzę na temat systemu GNU/Linux, jego administracji oraz zasad funkcjonowania lokalnych sieci komputerowych wykorzystujących protokół IP [Hunt 1997] [Bautts et al. 2005] [Russell 2001].
Podsłuchiwanie sieci LAN to proces polegający na odbieraniu wszystkich danych, które pojawiają się na interfejsie sieciowym, w formie ramek ethernetowych. Ramki odebrane przez sterownik karty sieciowej są przesyłane równolegle do programu lub programów nasłuchujących oraz do stosu sieciowego w systemie operacyjnym, dlatego proces nie zaburza normalnego funkcjonowania aplikacji korzystających z sieci. Dodatkowo, jeśli karta sieciowa znajduje się w trybie promiscuous odbierane ramki nie podlegają filtrowaniu, które standardowo odbywa się w karcie. Domyślnie bowiem, karta sieciowa pozwala tylko na odbiór ramek o adresie docelowym zgodnym z adresem MAC karty oraz ramek rozgłoszeniowych i multicastowych15). Aplikacja nasłuchująca ma dostęp do warstwy drugiej i wyższych modelu OSI, co pozwala na odbiór informacji przenoszonych nawet przez protokoły, które nie są obsługiwane przez system operacyjny.
Podsłuchiwanie sieci wykorzystywane jest głównie w analizatorach pakietów, nazywanych snifferami. Znajdują one zastosowanie przy diagnozowaniu problemów oraz pomagają poznawać protokoły sieciowe. Funkcje przechwytywania informacji wysyłanych przez inne hosty są także wykorzystywane przez komputerowych włamywaczy np. w celu poznawania haseł.
Podsłuchiwanie w trybie promiscuous umożliwia analizę ruchu całej sieci, pod warunkiem, że jest ona oparta na koncentratorach. Sieci budowane z wykorzystaniem przełączników są bardziej odporne na bierne podsłuchiwanie16), jednak zastosowanie metod aktywnych w dalszym ciągu pozwala na przechwytywanie transmisji (zostało to wyjaśnione w podrozdziale 1.3.3). Niemniej aplikacja, która powstała w ramach pracy dyplomowej, nie wymaga przechwytywania transmisji innych hostów.
Programy, które wykorzystują podsłuchiwanie sieci, często nie potrzebują wszystkich ramek, które odbiera karta. Zazwyczaj wybierają z nich tylko te, które spełniają określone kryteria. W tym celu został opracowany filtr BPF (ang. Berkeley Packet Filter). Pozwala on na wstępną selekcję danych z wykorzystaniem prostego języka17). Program w tym języku jest optymalizowany, kompilowany i ładowany do jądra18). Droga ramki sieciowej od momentu nadania, do otrzymania przez aplikację podsłuchującą jest zobrazowana na rysunku 2.1. Zanim ramka dotrze do programu, może zostać odfiltrowana na przełączniku sieciowym (1), ze względu na to, że jej adres docelowy znajduje się już w pamięci przełącznika i jest skojarzony z portem innego hosta. Jeśli ramka dotrze do karty sieciowej hosta (2), karta nie znajduje się w trybie promiscuous, zaś adres docelowy MAC ramki nie pokrywa się z adresem karty ani nie jest adresem rozgłoszeniowym, wtedy karta odrzuci ramkę. W przeciwnym razie ramka jest analizowana przez program filtra BPF (3) i tylko jeśli spełni jego warunki zostanie dopuszczona do aplikacji.
Wstrzykiwaniem określa się wysyłanie ramek ethernetowych bezpośrednio do sterownika karty sieciowej w systemie operacyjnym, czyli z pominięciem większości stosu sieciowego. Aplikacja w całości decyduje o zawartości ramki i może dowolnie określać wszystkie jej pola i dane protokołów wyższych warstw. Tak więc operacje, które nie są udostępniane przez system operacyjny, jak zmiana adresu źródłowego, wybranie docelowego adresu MAC i inne – są możliwe w trybie wstrzykiwania.
Podobną funkcjonalność oferują tzw. surowe gniazda sieciowe (ang. RAW sockets). Pozwalają one na generowanie z poziomu aplikacji dowolnych pakietów IP, które następnie są opakowywane przez jądro systemu w ramki protokołu warstwy drugiej modelu OSI [Al-Herbish 1999]. Zaletą surowych gniazd jest niezależność od medium transmisyjnego, natomiast wadą brak kontroli nad ramką.
Obie metody wysyłania danych są wykorzystywane głównie w aplikacjach do diagnozowania sieci oraz testowania i przełamywania zabezpieczeń.
Interfejs tun jest zapewnianym przez jądro wirtualnym urządzeniem sieciowym typu punkt-punkt. Podobnie interfejs tap z tą różnicą, że oferuje on wirtualną kartę ethernetową. Oba typy interfejsów są dynamiczne, tzn. mogą być tworzone w dowolnej ilości i usuwane [Krasnyansky i Thiel 2002]. Utworzenie i komunikacja z interfejsem odbywa się odpowiednio przez otworzenie pliku urządzenia19) oraz odczyt i zapis do deskryptora z poziomu aplikacji. Dane które zostaną zapisane pojawią się na interfejsie tun jako pakiet IP, zaś na interfejsie tap jako ramka ethernetowa. Pakiet bądź ramka, która zostanie wysłana przez interfejs może być odczytana z deskryptora jako ciąg bajtów.
Interfejsy tun/tap są wykorzystywane zazwyczaj w tunelowaniu. Tunelowanie polega na przesyłaniu pakietów lub ramek, po wcześniejszej enkapsulacji w pakiety specjalnych protokołów komunikacyjnych. Po obu stronach tunelu znajdują się interfejsy tun/tap, dzięki czemu użytkownik odnosi wrażenie, że komunikuje się z drugą stroną przez dedykowane połączenie fizyczne. Tunelowanie jest z reguły używane w wirtualnych sieciach prywatnych (VPN) oraz zastosowaniach eksperymentalnych20).
Rysunek 2.2 przedstawia porównanie interfejsów wirtualnych tun/tap oraz interfejsów fizycznych. Interfejsy fizyczne nadają i odbierają dane do/z odpowiedniego medium transmisyjnego za pośrednictwem właściwego sprzętu sieciowego. Natomiast interfejsy wirtualne komunikują się z aplikacjami, znajdującymi się w przestrzeni użytkownika.
NAT (ang. Network Address Translation) to proces, który odbywa się zwykle na routerze sieciowym. Polega on na dynamicznym tłumaczeniu adresów pakietów IP. Najczęściej używany jest w celu zapewnienia dostępu do Internetu sieci, która używa prywatnego zakresu adresów IP21). W tym przypadku router natujący zmienia źródłowy adres IP każdego pakietu wychodzącego do Internetu na adres publiczny routera. Każdy pakiet powracający do sieci otrzymuje adres odpowiadający komputerowi, który zainicjował transmisję. Dzięki temu cała sieć może wykorzystywać jeden publiczny adres IP22).
NAT jest wykorzystywany także podczas równoważenia obciążenia pomiędzy kilka serwerów dysponujących pojedynczym adresem IP. Router równoważący obciążenie korzystając z translacji adresów może przypisywać kolejne połączenia do różnych serwerów, np. w zależności od ich obciążenia, podmieniając docelowy adres IP połączeń na adres konkretnego serwera, który znajduje się w sieci wewnętrznej. Dzięki temu użytkownicy korzystający z usług serwerów odnoszą wrażenie, że komunikują się z jednym hostem, zaś w rzeczywistości jest ich kilka.
Zasada działania NAT została zobrazowana na rysunku 2.3. Zaawansowane implementacje NAT23) umożliwiają tworzenie bardziej złożonych translacji niż wymienionego powyżej schematu jeden do wielu. Mogą to być wiele do wielu (adresy są odwzorowywane w liczniejszą lub mniej liczną pulę), jeden do jednego (pule adresów zewnętrznych i wewnętrznych są jednakowo liczne, odwzorowania są stałe). Możliwe jest także wykonywanie translacji warunkowej w połączeniu z listą filtrów systemu firewall [Strebe i Perkins 2000] [Russell 2002b].
Aplikacja multispoof która powstała w ramach pracy dyplomowej, ma na celu praktyczną demonstrację słabości najpopularniejszej metody uwierzytelniania w sieciach osiedlowych. Program pozwala na przełamywanie zabezpieczenia usługi dostępu do Internetu, które bazuje na sprawdzaniu zgodności adresów IP i MAC komputera użytkownika z danymi przechowywanymi w bazie operatora.
Aplikacja wykorzystuje podszywanie się pod nieaktywne hosty. W tym procesie fałszowane są adresy IP i MAC wysyłanych pakietów. Cechą odróżniającą działanie aplikacji od zwykłej zmiany adresu w systemie operacyjnym jest możliwość podszywania się pod wszystkie nieaktywne komputery jednocześnie. Wykorzystanie programu pozwala osiągnąć szybkość transmisji, mogącą równać się sumie przepustowości poszczególnych hostów, których adresy są wykorzystywane przez aplikację. Koncepcję działania programu przedstawia rysunek 3.1.
Dodatkową funkcją programu jest samodzielne rozpoznawanie sieci i tworzenie listy komputerów, które będą mogły być później wykorzystane w procesie podszywania się. Aplikacja nieustannie monitoruje sieć i jeśli zauważy, że wykorzystywany w procesie podszywania się host staje się aktywny, to natychmiast przestaje używać jego adresu, aby nie powodować konfliktów.
Należy podkreślić, że aplikacja multispoof powstała w celach demonstracyjnych, zaś używanie jej bez zgody właściciela sieci jest równoznaczne z kradzieżą usługi, co jest niezgodne z prawem.
Wewnętrzna architektura aplikacji multispoof ewoluowała w trakcie jej implementacji. Początkowo aplikacja miała mieć postać jednego programu. Szybko jednak okazało się, że pojedynczy program byłby zbyt skomplikowany, dlatego część funkcji została umieszczona w osobnym programie. Liczba programów zwiększała się wraz z identyfikacją kolejnych zadań, które aplikacja miała wykonywać. Doprowadziło to do niemal całkowitej separacji do osobnych procesów zadań, które nie były ze sobą ściśle powiązane. Jednocześnie były opracowywane interfejsy, za pomocą których procesy komunikowały się ze sobą. Mają one prosty, tekstowy charakter, który jest czytelny dla człowieka. Separacja zadań i proste interfejsy to metody modularyzacji aplikacji, które wydatnie przyśpieszyły proces pisania kodu, testowania oraz znajdowania i usuwania błędów [Raymond 2003].
Każde z zadań jest realizowane przez zbiór procesów, nazwanych komponentami. Komponenty wykonują proste, jednowątkowe operacje z wykorzystaniem dwóch typów interfejsów, które zostaną omówione w podrozdziale 3.1. W podrozdziale 3.2 przybliżony zostanie komponent netdb, który uczestniczy we wszystkich trzech zadaniach. Następne podrozdziały będą dotyczyć kolejnych zadań, oraz wykonujących je komponentów. Rozdział zakończy opis skryptu multispoof, odpowiedzialnego za przygotowanie środowiska, utworzenie zadań z poszczególnych komponentów po uruchomieniu, oraz zatrzymanie ich przed zakończeniem.
Interfejsy służą do jedno- lub dwustronnej komunikacji pomiędzy komponentami aplikacji multispoof z wykorzystaniem odpowiednich protokołów. Intencją przyświecającą ich budowie była prostota, dlatego dane wymieniane z ich wykorzystaniem mają postać tekstową. Decyzja ta wpłynęła na dużą elastyczność protokołów, co znacznie ułatwiało bieżącą ich rozbudowę podczas powstawania aplikacji. Oprócz tego forma tekstowa jest czytelna dla człowieka i daje się przetwarzać przy użyciu narzędzi uniksowych (np. grep, sed, awk). Są to pożądane cechy ułatwiające proces testowania oprogramowania.
Pierwszy typ interfejsu, nazwany tekstowym protokołem ramek, jest używany w potokach między komponentami przetwarzającymi ramki sieciowe. Interfejs jest jednokierunkowy. Pozwala na wysyłanie odpowiednio zakodowanych ramek, lub ich odbieranie za pośrednictwem standardowego wejścia i wyjścia. Protokół ten ma format liniowy, każda linia zawiera jedną ramkę. Bajty ramki kodowane są heksadecymalnie, najstarszy bajt pierwszy (Big Endian). Przykładową ramkę obrazuje rysunek 3.2.
Drugi typ interfejsu, nazywany interfejsem lub protokołem netdb, służy do wykonywania zapytań do bazy adresów netdb (baza ta będzie opisana w następnym podrozdziale). Interfejs wykorzystuje lokalne gniazdo uniksowe24) i jest dwukierunkowy. Komponenty mogą wysyłać zapytania, zaś baza odsyła odpowiedzi.
Zapytania mają postać komend z parametrami rozdzielonymi białymi znakami. Odpowiedzi składają się z jednej lub więcej linii, z których ostatnia ma ustandaryzowany format, przedstawiony na rysunku 3.3. Jeśli odpowiedź składa się z więcej niż jednej linii, wszystkie oprócz ostatniej mają format specyficzny dla wydanej komendy.
Zadaniem komponentu netdb jest umożliwienie dostępu do bazy adresów oraz zmiennych innym komponentom. Baza netdb jest używana niemal przez wszystkie inne procesy, działające w ramach aplikacji multispoof, z wyjątkiem tx, rx i tapio. Z tego względu komponent netdb zostanie omówiony na początku.
Komunikacja z innymi komponentami aplikacji jest realizowana z wykorzystaniem lokalnego gniazda uniksowego, które jest tworzone po uruchomieniu programu. Korzystając z tego gniazda inne komponenty mogą wydawać komendy i odczytywać wyniki zgodnie z tekstowym protokołem netdb. Tabela 3.1 zawiera listę dostępnych komend wraz z krótkimi opisami. Wybrane komendy będą omówione szerzej w następnych podrozdziałach.
| Komenda | Parametry | Opis |
|---|---|---|
| gethost | Adres IP | Wyświetla dane hosta: adres MAC, wartości czasowe oraz znaczniki. |
| host | Adres IP, MAC | Dodaje lub modyfikuje dane hosta. Uaktualnia czas ostatniej aktywności. |
| remove | Adres IP | Usuwa dane hosta. |
| do | Akcja, Adres IP | Ustawia flagi dla hosta. Możliwe akcje: enable, disable, start-test, stop-test. |
| dump | – | Wyświetla listę adresów IP. |
| getvar | Nazwa zmiennej | Wyświetla zawartość zmiennej. |
| setvar | Nazwa zmiennej, wartość | Ustawia wartość zmiennej. |
| quit | – | Kończy połączenie z netdb. |
Program netdb jest jednowątkowym serwerem opartym na funkcji select. Architektura ta charakteryzuje się wysoką wydajnością oraz prostotą implementacji [Brecht i Ostrowski 2001]. Podczas ewaluacji różnych rozwiązań, została ona wybrana głównie ze względu na tę drugą cechę, w szczególności brak sekcji krytycznej25). Proces obsługi połączeń jest przedstawiony na rysunku 3.4.
Rozpatrywane były również inne sposoby realizacji dostępu do bazy hostów przez wiele procesów, lecz zostały odrzucone. Tablica hostów mogłaby być przechowywana w segmencie pamięci, dzielonym między komponentami, zaś synchronizacja odbywałaby się z wykorzystaniem semaforów. Zaletą tego rozwiązania jest wysoka wydajność, ponieważ operacje na pamięci są zdecydowanie szybsze niż komunikacja za pomocą gniazd lokalnych. Wadami są zwiększenie skomplikowania komponentów (potrzeba zaimplementowania synchronizacji, która sprzyja powstawaniu błędów, komplikacje związane z umieszczeniem dynamicznych struktur danych w pamięci dzielonej26)) oraz trudność testowania (konieczne byłoby napisanie osobnego programu testującego, brak możliwości monitorowania odczytów/zapisów do/z pamięci). Podobnym pomysłem jest użycie pamięci prywatnej specjalnej biblioteki. Biblioteka udostępniałaby dostęp do bazy hostów, znajdującej się w pamięci prywatnej za pomocą zestawu funkcji. Synchronizacja odbywałaby się tylko wewnątrz biblioteki, jednak pozostałe problemy są takie same jak w poprzednim rozwiązaniu.
Główne zadanie programu, czyli operacje na bazie hostów jest realizowane z wykorzystaniem tablicy haszującej, dostępnej w bibliotece glib27). Obsługa zmiennych (komendy getvar i setvar) wykorzystuje prostą tablicę struktur. Tablica ta jest statyczna, ponieważ zbiór zmiennych jest stały i zdefiniowany w kodzie.
Po uruchomieniu program rejestruje gniazdo lokalne oraz wczytuje bazę hostów z pliku cache, który mógł zostać stworzony w wyniku poprzednich uruchomień. Jest to plik tekstowy, który zawiera sekwencje komend host. Ścieżka do pliku jest podawana jako parametr. Następnie przechwytywane są funkcje obsługi sygnałów, aby program przed zakończeniem mógł zapisać bazę hostów do pliku cache. Ostatnim krokiem jest wywołanie funkcji odpowiedzialnej za nasłuchiwanie na gnieździe i obsługę połączeń.
# rx | cmac unspoof | tapio | cmac spoof | txPomiędzy elementami potoku dane przekazywane są w sposób zakodowany zgodnie z omówionym wcześniej protokołem ramek. Komunikaty diagnostyczne są wysyłane na standardowe wyjście błędów, dzięki czemu nie zaburzają potoku. Każdy komunikat jest poprzedzany nazwą komponentu, który go wygenerował. Dzięki temu użytkownik jest na bieżąco informowany o istotnych wydarzeniach i jest w stanie przypisać je do konkretnego źródła. Role poszczególnych komponentów zostaną omówione w podrozdziałach.
Para programów rx i tx zajmuje się odpowiednio podsłuchiwaniem (odbieraniem ramek) oraz ich wstrzykiwaniem do sieci.
Komponent rx odbiera ramki z wykorzystaniem biblioteki libpcap [Carstens 2002]. Jako parametry z linii komend podaje się interfejs, na którym program ma nasłuchiwać, oraz filtr BPF, określający które ramki będą odbierane. Podsłuchiwanie musi odbywać się w trybie promiscuous, ze względu na to, że aplikacja multispoof wykorzystuje wiele adresów MAC. Jeśli tryb ten byłby wyłączony, aplikacja otrzymywałaby tylko ramki, których docelowy adres MAC jest równy adresowi interfejsu sieciowego, oraz ramki rozgłoszeniowe. Oprócz trybu promiscuous, komponent rx przed rozpoczęciem podsłuchiwania aktywuje filtr kierunku transmisji, tak aby odbierane były tylko ramki, które płyną z sieci, nie zaś te, które są wysyłane przez hosta. Domyślnie bowiem, biblioteka libpcap przechwytuje ramki płynące w obydwu kierunkach28).
Podsłuchane ramki, które spełniają warunki narzucone przez filtr BPF oraz filtr kierunku, zostają wysłane przez komponent rx na standardowe wyjście, zakodowane zgodnie z tekstowym protokołem ramek.
Komponent tx zajmuje się wstrzykiwaniem ramek do sieci przez określony interfejs sieciowy. Ramki są wczytywane ze standardowego wejścia w formacie zgodnym z protokołem ramek. Wstrzykiwanie odbywa się z wykorzystaniem biblioteki libnet [Schiffman 2004]. Jeśli ramka do wstrzyknięcia jest zbyt mała (standard Ethernet wymaga, aby minimalna wielkość wynosiła 60 bajtów), komponent tx powiększa ją, dopełniając zerowymi bajtami (ang. padding). Gdyby czynność ta nie była wykonywana i tak ostatecznie zrobiłby to sterownik karty sieciowej. Jednak wtedy analiza danych płynących przez interfejs z wykorzystaniem narzędzi typu sniffer nie ujawniłaby dopełnienia, co nie zgadzałoby się ze stanem faktycznym i mogłoby wzbudzać wątpliwości u osoby, która nie jest zaznajomiona z tym faktem.
Komponenty rx i tx wspólnie pozwalają na kompletną, niskopoziomową kontrolę ruchu przychodzącego i wychodzącego przez dany interfejs. Stanowią interfejs do sieci dla innych części aplikacji multispoof.
Rozbicie funkcji podsłuchiwania sieci oraz wstrzykiwania ramek na dwa oddzielne programy, oprócz korzyści związanych z modularyzacją aplikacji, może przydać się także w przyszłości. W kolejnej wersji można stosunkowo łatwo wprowadzić obsługę pracy w sieci bezprzewodowej. Radiowe interfejsy sieciowe charakteryzują się tym, że nie jest możliwe jednoczesne odbieranie i nadawanie. Wiąże się to z tzw. efektem oślepienia, który występuje w momencie zbyt szybkiego przełączenia interfejsu z trybu nadajnika w tryb odbiornika. Konieczne jest zastosowanie dwóch oddzielnych interfejsów sieciowych29): jednego tylko do wysyłania, zaś drugiego tylko do odbierania ramek. Obecna architektura aplikacji poradzi sobie z tym wymogiem, ponieważ każdy interfejs będzie obsługiwany przez osobny komponent30).
Komponent tapio jest odpowiedzialny za utworzenie wirtualnego interfejsu tap oraz komunikację z nim. Program łączy z interfejsem standardowe wejście i wyjście, w ten sposób, że ramki wczytywane z wejścia są na niego wysyłane, zaś ramki z niego odbierane są wypisywane na standardowe wyjście. Proces ten jest zobrazowany na rysunku 3.7. Obsługa wejścia/wyjścia jest realizowana z zachowaniem tekstowego protokołu ramek. Nazwę interfejsu tap, który program ma utworzyć, podaje się jako parametr.
Komponent cmac jest programem typu filtr. Wczytuje on ramki ze standardowego wejścia, następnie jeśli spełnione zostaną kryteria akceptacji, modyfikuje je i wysyła na standardowe wyjście. Modyfikacja dotyczy zmiany adresu MAC ramki. W zależności od trybu podawanego jako parametr przy uruchomieniu, komponent podmienia adres źródłowy lub docelowy. Algorytm działania programu został przedstawiony na rysunku 3.8.
Po uruchomieniu cmac łączy się z komponentem netdb. Z każdej wejściowej ramki program wyodrębnia jej adres IP. Następnie wysyła do netdb zapytanie o ten adres (wykorzystując komendę gethost). Jeśli wpis zostanie znaleziony, to odpowiedź będzie zawierać adres MAC hosta, czas nieaktywności, czas który upłynął od ostatniego testu oraz informacje czy dany adres jest w tej chwili testowany i czy jest w stanie enabled. Komponent cmac testuje, czy uzyskane informacje spełniają opisane w tabeli 3.2 warunki zmiany adresu MAC. Jeśli test wypadnie pomyślnie adres MAC ramki zostaje zmieniony i ramka jest wypisywana na standardowe wyjście.
| Warunki | Komponent | Czynność | |||
|---|---|---|---|---|---|
| age > min_age | test_age > min_test_age | enabled | cur_test | ||
| Prawda | – | Prawda | – | cmac | Zmień MAC i wypisz ramkę |
| Prawda | – | – | Prawda | ||
| Prawda | – | Prawda | – | deta | Wypisz odpowiedź na ARP |
| Prawda | – | – | Prawda | ||
| Prawda | Prawda | – | – | conncheck | Wykonaj test połączenia |
| Prawda | – | Prawda | – | natman | Uwzględnij wpis w LB |
# rx | deta | tx
# scanarp | tx
Komponent scanarp ma za zadanie periodyczne wysyłanie zapytań ARP Request do wszystkich hostów, których adresy są zarejestrowane w bazie netdb. Zapytania tego rodzaju są wysyłane, aby stwierdzić które z zarejestrowanych hostów są w danej chwili aktywne, bowiem działające komputery odpowiadają komunikatem ARP Reply31). Algorytm działania programu został przedstawiony na rysunku 3.10. Wysyłanie ramek w sieć jest realizowane za pośrednictwem komponentu tx, z wykorzystaniem protokołu ramek. Komponent pobiera listę hostów z bazy za pomocą komendy dump. Należy podkreślić, że aktywność sieciowa komponentu scanarp ogranicza się wyłącznie do wysyłania pakietów ARP Request. Odbieraniem odpowiedzi ARP Reply zajmuje się opisany dalej komponent deta.
Komponent deta wykonuje dwa zadania, które ze względu na to, że muszą być wykonywane sekwencyjnie zostały zaimplementowane w jednym programie. Są to: wykrywanie aktywności hostów w sieci oraz odpowiadanie na zapytania ARP. Komponent nasłuchuje na fizycznym interfejsie sieciowym (za pośrednictwem programu rx), wyodrębnia adresy IP z przychodzących ramek, a następnie uaktualnia wpisy w bazie netdb. Jeśli z sieci przyjdzie zapytanie ARP Request, wtedy w zależności od zawartości bazy netdb może być udzielona odpowiedź i wysłana w sieć za pośrednictwem tx. Algorytm komponentu deta został przedstawiony na rysunku 3.11.
Komponent ma architekturę typu filtr. Na wejściu pojawiają się ramki, które program przetwarza, uaktualniając bazę netdb. Na wyjście komponent wypisuje ramki ARP Reply. Po odebraniu ramki, deta sprawdza jaki protokół ona niesie. Jeśli jest to protokół IP, to wyodrębniany jest źródłowy adres IP. Jeśli natomiast jest to pakiet ARP, to wyodrębniany jest adres IP komputera, który nadał ten pakiet (może to być zapytanie z sieci, bądź odpowiedź na zapytanie wysłane przez komponent scanarp). W obu przypadkach sprowadza się to do ustalenia adresu IP nadawcy, jednak dla każdego protokołu dana ta zapisana jest w nieco innym miejscu nagłówka (rysunek 3.12).
Gdy źródłowy adres IP jest już znany, komponent sprawdza, czy host ten znajduje się na czarnej liście. Lista ta jest pobierana przy starcie programu ze zmiennej banned komponentu netdb. Składa się ona z adresów, które są bezużyteczne w procesie podszywania się, natomiast pojawiają się w sieci. Zmienna jest definiowana w skrypcie multispoof (który będzie omówiony w podrozdziale 3.6) i zawiera takie adresy, jak 0.0.0.032), 255.255.255.255 oraz adres domyślnej bramy33). Jeśli adres nie należy do czarnej listy komponent wykonuje komendę host na bazie netdb (patrz podrozdział 3.2, w szczególności tabela 3.1). Jako parametry do komendy zostają podane adres IP oraz źródłowy adres MAC ramki. Jeśli w bazie nie ma jeszcze wpisu dla tego hosta, jest on tworzony. Jeśli już jest, to czas, który upłynął od ostatniej aktywności, jest zerowany. Dzięki temu inne komponenty nie zaczną lub zaprzestaną wykorzystywać adres tego hosta, ponieważ stał się on aktywny. Jeśli ramki z tego hosta przestaną przychodzić, to po pewnym czasie inne komponenty z powrotem rozpoczną korzystanie z jego adresu.
Jeżeli przychodząca ramka niesie w sobie pakiet ARP Request, to następnym krokiem jest ustalenie, czy należy wysłać odpowiedź ARP. Odpowiedź ARP powinna być wysłana tylko wtedy jeśli adres, którego dotyczy zapytanie ARP, jest aktualnie w użyciu przez inne komponenty. W przeciwnym wypadku, tzn. jeśli fizyczny host o takim adresie jest aktywny, odpowiedź ARP mogłaby spowodować problemy w sieci34). Dlatego przed wysłaniem odpowiedzi program deta wykonuje zapytanie do bazy netdb, tym razem korzystając z komendy gethost. Jeśli host wystarczająco długo nie był aktywny oraz jeśli ma flagę enabled (patrz zestawienie warunków w tabeli 3.2 oraz opis komponentu conncheck w podrozdziale 3.5.1) to ramka z odpowiedzią ARP jest tworzona i wypisywana na standardowe wyjście.
Ostatnie zadanie aplikacji to typowanie nieaktywnych hostów które będą wykorzystywane w procesie zmiany adresów. Polega to na testowaniu łączności oraz przeładowywaniu reguł NAT odpowiedzialnych za równoważenie obciążenia. W procesach tych uczestniczą trzy komponenty, spośród których dwa nie zostały jeszcze omówione: conncheck i natman. Na rysunku 3.13 przedstawiono schemat tej części aplikacji, z uwzględnieniem połączeń między komponentami.
Komponent conncheck decyduje które adresy z bazy netdb mogą być wykorzystywane w procesie podszywania się. Może się bowiem zdarzyć, że host znajdujący się w bazie netdb nie ma połączenia z Internetem (np. jego adres został zablokowany na routerze). Podszywanie się pod host, który nie ma łączności z siecią globalną mija się z celem aplikacji multispoof. Aby temu zapobiec program wybiera nieaktywne hosty i co pewien czas wykonuje dla każdego z nich test połączenia korzystając ze skryptu access-test. Adres hosta, który podlega testowaniu, jak i inne informacje są przekazywane do skryptu przez zmienne środowiskowe (tabela 3.3). Skrypt zwraca kod zakończenia równy 0, jeśli połączenie z Internetem zostało poprawnie zweryfikowane. Jeśli skrypt nie zdołał pozytywnie przetestować połączenia, to zwraca 1. Wersja aplikacji multispoof, która jest dołączona do tego opracowania, zawiera skrypt wykorzystujący program nmap35). Kod skryptu przedstawiony jest na listingu poniżej.
#!/bin/sh
HOST="www.mbank.com.pl"
PORT="443"
echo "access-test: (debug) checking $_IP started"
RESULT=1
nmap -sT -P0 -n -p $PORT $HOST 2> /dev/null | \
egrep "^$PORT" | grep -q "open" && RESULT=0
echo "access-test: (debug) checking $_IP finished (result: $RESULT)"
exit $RESULT
Po wywołaniu skryptu, program nmap wysyła segment TCP SYN na port 443 hosta o adresie www.mbank.com.pl. Jeśli otrzyma w odpowiedzi segment SYN ACK, wypisuje na standardowe wyjście stosowny komunikat. Komunikat jest przetwarzany przez narzędzie grep, które zwraca odpowiednią wartość logiczną, wykorzystywaną dalej przez skrypt do ustawienia zmiennej RESULT. Ostatnim krokiem jest zwrócenie wartości tej zmiennej. Metoda oparta na programie nmap została wybrana ze względu na to, że program ten generuje ruch sieciowy o stosunkowo niskim natężeniu. Cała transmisja składa się z jednego lub kilku zapytań DNS oraz rozpoczęcia połączenia TCP. Pakiety są małe i jest ich niewiele36).
| Zmienna | Przykładowa zawartość (czasy w sekundach) | Opis |
|---|---|---|
| _IP | 156.17.40.16 | Adres IP hosta. |
| _MAC | 00:e0:7d:dc:62:8c | Adres MAC hosta. |
| _AGE | 1337 | Czas nieaktywności hosta. |
| _TEST_AGE | 6858 | Czas, który upłynął od ostatniego testu. |
| _ENABLED | 1 | Stan flagi enabled w chwili testu. |
| _MIN_AGE | 300 | Minimalny czas nieaktywności hosta. |
| _MIN_TEST_AGE | 3600 | Minimalny czas między testami. |
| _NF_CHAIN | multispoof-test | Łańcuch dla tymczasowych reguł iptables. |
Testowanie połączenia z Internetem zostało zorganizowane w powyższy sposób, aby użytkownik miał możliwość łatwego modyfikowania tego elementu i dostrajania go do sieci w której jest uruchamiana aplikacja multispoof. Także w tym celu do skryptu są przekazywane zmienne środowiskowe. W tej wersji skryptu bowiem nie są one wykorzystywane.
Aby przetestować połączenie z Internetem konkretnego hosta, komponent conncheck przed uruchomieniem skryptu access-test musi załadować do jądra regułę NAT37), która spowoduje, że dane wysyłane i odbierane przez skrypt będą wykorzystywały adres IP testowanego hosta. Odbywające się aktualnie transmisje użytkownika aplikacji multispoof nie powinny zostać zakłócone, dlatego reguła musi dotyczyć tylko transmisji wykonywanych przez skrypt i programy przez niego uruchamiane. Aby spełnić ten warunek wykorzystywany jest moduł owner. Moduł ten pozwala na wyodrębnienie transmisji konkretnego procesu (wykorzystując jego PID) lub ich zbioru (za pomocą numeru SID - session ID38)). Ponieważ wszystkie komponenty aplikacji multispoof są wywoływane przez jeden skrypt (opisany w podrozdziale 3.6), numer SID każdego procesu jest taki sam. Skrypt access-test jest jedyną częścią aplikacji, która wykonuje transmisje sieciowe, dlatego wykorzystanie w regule tego numeru nie zakłóci pracy programu. Jeśli numerem SID będzie 42, transmisje mają wykorzystywać interfejs tap0, zaś adres źródłowy ma być podmieniany na 156.17.40.16, to wywołanie programu iptables będzie miało poniższą formę:
# iptables -t nat -A POSTROUTING -o tap0 \
-m owner --sid-owner 42 -j SNAT --to-source 156.17.40.16
W rzeczywistości, aplikacja multispoof wykorzystuje dodatkowe łańcuchy iptables. Jest to opisane dokładniej w podrozdziale 3.6.
Przed uruchomieniem skryptu access-test, oprócz załadowania reguły NAT, conncheck wywołuje na bazie adresów netdb komendę do start-test (zobacz tabela 3.1). Komenda ta ustawia flagę, która informuje inne komponenty, że dany host jest aktualnie testowany. Dzięki temu np. komponent cmac zmienia i przesyła ramki nawet dla hostów, które nie są w stanie enabled (zachowanie poszczególnych komponentów w zależności od stanu flag jest przedstawione w tabeli 3.2). Dopiero po tym wywoływany jest skrypt testujący. Następnie w zależności od wyniku testu, stan hosta jest za pomocą komendy do zmieniany na enabled lub disabled. Zostaje jeszcze usunięcie znacznika testowania oraz reguły NAT, po czym komponent przechodzi do testowania następnego adresu. Algorytm działania programu jest przedstawiony na rysunku 3.14.
Komponent natman jest odpowiedzialny za utrzymywanie aktualności reguł NAT wykorzystywanych do równoważenia obciążenia. Program periodycznie pobiera listę hostów z bazy netdb i na jej podstawie buduje listę hostów, które są w stanie enabled i były nieaktywne przez wystarczającą długi czas. Tak przygotowana lista jest porównywana z listą z poprzedniej iteracji. Jeśli listy różnią się, to znaczy, że w bazie pojawiły się nowe hosty, które można wykorzystać, lub dotychczas nieaktywne komputery stały się aktywne. W obu przypadkach komponent przeładowuje listę reguł NAT, aby uwzględnić zmiany. Rysunek 3.15 przedstawia algorytm działania programu natman.
Równoważenie obciążenia to proces realizowany przez podsystem Netfilter jądra Linuksa, rozdzielający połączenia sieciowe i przypisujący je do poszczególnych adresów, które w danej chwili są wykorzystywane. Dzięki temu użytkownik może wygenerować ruch, którego natężenie wielokrotnie przekracza limit dla pojedynczego hosta.
Aby lepiej zrozumieć, na czym polega równoważenie obciążenia, należy prześledzić drogę pojedynczego pakietu. Pakiet, który przychodzi na interfejs wirtualny tap, jest porównywany z tablicą nawiązanych połączeń conntrack. Z każdym połączeniem związany jest adres IP. Jeśli pakiet należy do nawiązanego połączenia, to jego adres źródłowy zostanie zmieniony na ten, który jest zapisany w tablicy conntrack. Jeśli zaś pakiet nie należy do żadnego z istniejących połączeń, tzn. jest pierwszym pakietem połączenia (np. jest to pakiet TCP z ustawioną opcją SYN39)), to adres, jaki zostanie mu przypisany, jest wybierany z puli dostępnych odpowiednim algorytmem rozkładania obciążenia. W obecnej wersji wykorzystywany jest algorytm round robin40). Polega on na tym, że każde nowe połączenie dostaje kolejny adres IP modulo liczba dostępnych adresów. Tzn. jeśli dostępnych jest 10 adresów, to pierwsze połączenie dostanie pierwszy adres, drugie drugi itd., zaś połączenie jedenaste otrzyma adres pierwszy. Jest to najprostsza metoda równoważenia obciążenia, nie uwzględniająca stopnia wykorzystania poszczególnych adresów. W kolejnych wersjach aplikacji multispoof mogą pojawić się inne metody.
# iptables -t nat -A POSTROUTING -o tap0 \
-m nth --every 4 --packet 0 \
-j SNAT --to-source 156.17.40.16
# iptables -t nat -A POSTROUTING -o tap0 \
-m nth --every 4 --packet 1 \
-j SNAT --to-source 156.17.40.17
# iptables -t nat -A POSTROUTING -o tap0 \
-m nth --every 4 --packet 2 \
-j SNAT --to-source 156.17.40.18
# iptables -t nat -A POSTROUTING -o tap0 \
-m nth --every 4 --packet 3 \
-j SNAT --to-source 156.17.40.19
Dla czytelności w powyższym przykładzie reguły umieszczane
są bezpośrednio we wbudowanym łańcuchu POSTROUTING.
Aplikacja multispoof wykorzystuje dedykowany łańcuch, w celu
bardziej elastycznego zarządzania regułami.
Tabela nat na której operują reguły posiada cechę,
która nie jest spotykana w innych tabelach
– mianowicie trafiają do niej tylko te pakiety,
które inicjują połączenia43).
Pozostałe pakiety ulegają
translacji automatycznie, w zależności od tego do jakiego
połączenia należą. Funkcja ta jest zapewniana przez moduł
śledzenia połączeń conntrack podsystemu Netfilter i może być
wymuszona także
dla innych tabel z wykorzystaniem filtra state.
Śledzenie połączeń ulegających translacji jest fundamentalnych mechanizmem, dzięki któremu transmisja może odbywać się prawidłowo. W przeciwnym wypadku, tzn. gdyby mechanizm ten został zdezaktywowany, translacja dotyczyłaby pojedynczych pakietów a nie połączeń. Doprowadziłoby to do sytuacji, w której poszczególne pakiety jednego połączenia miałyby różne źródłowe adresy IP, co uniemożliwia właściwą identyfikację połączenia przez host, znajdujący się po jego drugiej stronie. Adres IP bowiem jest jedną z danych, które identyfikują połączenie44) i przez czas jego trwania muszą pozostać niezmienne.
Ideę procesu rozkładania obciążenia została przedstawiona na rysunku 3.16. Pakiety zobrazowane są na nim jako różnokolorowe kółka. Kolor ich wypełnienia określa połączenie do którego przynależy dany pakiet. Środkowy okrąg określa miejsce, w którym przeprowadzany jest NAT według tabeli conntrack, która łączy połączenia z adresami IP. Na rysunku prawie wszystkie połączenia są już nawiązane i mają przypisane adresy IP. Pakiety oznaczone czerwonymi kółkami rozpoczynają połączenie, któremu adres IP zostanie przypisany zgodnie z algorytmem round robin.
Skrypt multispoof stanowi tę część aplikacji, która jest odpowiedzialna za uruchamianie jej poszczególnych zadań. Chociaż zarówno skrypt, jak i pozostałe komponenty, są plikami wykonywalnymi, po instalacji całej aplikacji tylko skrypt staje się dostępny dla użytkownika w standardowej ścieżce dostępu PATH. Pozostałe komponenty są umieszczane w osobnym katalogu, nie uwzględnionym w ścieżce. Dzieje się tak, ponieważ działając samodzielnie, komponenty nie spełniają użytecznych zadań, zaś udostępnianie nieprzydatnych programów w systemie jest pozbawione sensu.
Skrypt został zaprogramowany w języku Bourne shell. Język ten został wybrany ze względu na to, że uruchamianie podprocesów jest w nim maksymalnie uproszczone. To samo dotyczy komunikacji międzyprocesowej z wykorzystaniem potoków. Oba te mechanizmy są intensywnie wykorzystywane w aplikacji multispoof. Język shell stanowi framework, czyli niejako środowisko, w którym wykonują się poszczególne komponenty aplikacji [Raymond 2003].