Ostrzegam – wpis raczej techniczny 😉
Jak działa traceroute (na Windows – tracert) wie każdy szanujący się student informatyki. Do hosta docelowego wysyłane są pakiety z początkowo małymi, później coraz to większymi liczbami TTL. Ponieważ TTL zmniejsza się o 1 z każdym przeskokiem do kolejnego routera to wiadomo, że osiągnie ostatecznie wartość 0. Router na którym to nastąpi zwraca do hosta źródłowego informację o przekroczeniu czasu. Host źródłowy wypisuje na ekranie kolejne adresy, które zwróciły taką informację i powstaje nam całkiem ładna trasa. Pakiet z TTL-em równym 1 pozwala nam wykryć najbliższy router, z numerem 2 kolejny i tak aż dojdziemy do celu.
Wiadomo jednak, że, tak jak kij, każdy router ma co najmniej dwa końce – są to interfejsy sieciowe. traceroute pozwala nam wykryć jedynie jeden koniec każdego routera – interfejs „po naszej stronie”. Zerknijmy na poniższy komiks:
traceroute uruchomiony na komputerze pozwoli poznać adres IP interfejsów eth0 i eth2. Niestety, interfejsy eth1 i eth3 pozostają ukryte. A raczej pozostawały – do dzisiaj!
Program newtrace pozwala na śledzenie trasy pakietu, uwzględniając wszystkie interfejsy sieciowe przez które on przechodzi. Innymi słowy, dzięki niemu otrzymamy elegancką listę routerów, zaś każdy z nich będzie miał przyporządkowane dwa adresy: interfejs wejściowy (w powyższym wypadku eth0 i eth2) i wyjściowy (na diagramie – eth1 i eth3).
Jak to działa? Przez zgadywanie. Zerknijmy raz jeszcze na diagram i załóżmy, że interesuje nas adres interfejsu eth1. Wiemy 2 rzeczy:
- interfejs ten fizycznie znajduje się na routerze 1,
- interfejs jest w tej samej podsieci, co interfejs eth2.
Ponieważ znamy adres interfejsu eth2, możemy określić listę adresów IP znajdujących się w tej samej podsieci. A raczej moglibyśmy, gdybyśmy znali również maskę. Z praktyki wynika jednak, że takie między-routerowe połączenia to bardzo małe podsieci o maskach na przykład /30 lub /29.
Załóżmy więc, że lista jest określona. Nie pozostaje nic innego, jak wysyłać żądania echo request do każdego z adresów. Kluczową rzeczą jest tu TTL – ustawiamy go na taką samą wartość, jak dla pakietu, który dotarł wcześniej do eth0 (czyli w naszym przykładzie: 1). Dzięki temu, jeśli pakiet dotrze do testowanego adresu IP zyskujemy pewność, że jest on przypisany do routera 1. A skoro jest przypisany do routera 1 i znajduje się w tej samej podsieci co eth2, to jest to eth1. â–¡
Pozostaje jeszcze sytuacja, w której przetestowaliśmy hipotetyczne podsieci o masce /30, /29, a nawet /28 i dochodzimy do jakiejś ogromnej podsieci, zawierającej setki lub więcej adresów, które trzeba przetestować. Można to robić, jeśli nam zależy. W implementacji powyższego algorytmu stosuję jednak ograniczenie – jeśli szukany adres nie znajdzie się w podsieciach o maskach większych lub równych /28, to proces szukania jest przerywany. Wartość tę można modyfikować parametrem -m podanym z linii komend.
Ponieważ program robi różne dziwne rzeczy na gniazdach, wymaga uruchomienia jako root. Źródła na githubie, można ściągnąć paczkę. Całość oczywiście w Ruby.
UPDATE 22 X 2009
Dodałem jeszcze trzy końcowe testy, wszystkie sprawdzają, czy eth0 i domniemany eth1 są na tym samym routerze:
- newtrace sprawdza, czy do domniemanego eth1 nie dochodzi przypadkiem pakiet z niższym TTL-em,
- sprawdza też, czy w odpowiedziach echo reply ustawiona jest ta sama wartość TTL-a (różne systemy mogą ją sobie różnie ustawiać),
- sprawdza w końcu (i to jest test ostateczny ;))czy identyfikatory pakietu IP odpowiedzi echo reply z eth0 i domniemanego eth1 są podobne (czy nie różnią się o więcej niż 10). Jeśli tak, to istnieje bardzo duże prawdopodobieństwo, że eth0 i eth1 są na tej samej maszynie. Jedynym wyjątkiem jest sytuacja, w której interfejsy są jednak na różnych maszynach, ale żadna z nich nie ustawiają pola identyfikatora (równe jest 0).
Fajny art, szkoda tylko, że mój router TP-LINK nie obsługuje komendy traceroute 🙂