/ Linux Reviews / Networking / Kształtowanie Ruchu i Zaawansowany Routing HOWTO - en - pl


Rozdział 12. Zaawansowane filtry i (re-)klasyfikowanie pakietów

Jak już wyjaśniono powyżej, filtry potrzebne są do klasyfikowania pakietów do podkolejek. Wywoływane są z kolejek z klasami.

Poniżej niekompletna lista klasyfikatorów:

fw

Podejmuje decyzję na podstawie tego, jak firewall oznaczył pakiet. Użycie go może być prostsze, niż uczenie się całej składni tc. Zajrzyj do rozdziału o kolejkowaniu.

u32

Podejmuje decyzję na podstawie pól w pakiecie (np. źródłowego adresu IP itd.).

route

Podejmuje decyzję na podstawie trasy, którą pakiet będzie routowany.

rsvp, rsvp6

Kieruje pakiety na trasy określone przez standard RSVP. Użyteczne tylko jeśli kontrolujesz sieć na całej trasie pakiety - Internet nie respektuje RSVP.

tcindex

Używane w kolejce DSMARK, zajrzyj do odpowiedniej sekcji.

Zauważ, że generalnie jest wiele sposobów na który możesz sklasyfikować pakiet i w zasadzie to twoje preferencje decydują o tym, który system wykorzystać.

Klasyfikatory ogólnie rzecz biorąc, akceptują parę podstawowych argumentów. Wymieniono je tutaj dla wygody:

protocol

Protokół, który ten klasyfikator zaakceptuje - w zasadzie będziesz akceptował ruch IP. Wymagane.

parent

Oznaczenie, do którego ten klasyfikator będzie podpięty. Musi być już zdefiniowane dla istniejącej klasy. Wymagane.

prio

Priorytet klasyfikatora. Niższy numer będzie sprawdzany szybciej.

handle

Uchwyt oznacza różne rzeczy dla różnych filtrów.

Wszystkie następne sekcje zakładają, że próbujesz kształtować ruch skierowany do HostA. Zakłada się, że klasę-korzeń skonfigurowano na 1: i że wyselekcjonowany ruch chcesz wysyłać do 1:1.

12.1. Klasyfikator u32

Klasyfikator U32 jest w obecnej implementacji najbardziej zaawansowanym z dostępnych filtrów. W całości zbudowany w oparciu o tablice `mieszające', zapewniające dużą wydajność nawet w przypadku dużej liczby reguł.

W swojej najprostszej postaci, filtr U32 jest listą rekordów, z których każdy składa się z dwóch pól: selektora i akcji. Selektor, opisany poniżej, jest porównywany do aktualnie przetwarzanego pakietu IP dopóki nie dojdzie do pierwszej zgodności. Wtedy wykonywana jest skojarzona z pasującym selektorem akcja. Najprostszym typem akcji byłoby skierowanie pakietu do zdefiniowanej klasy CBQ.

Linia poleceń programu tc filter używanego do konfigurowania filtrowania, składa się z trzech części: określenia filtra, selektora i akcji. Określenie filtra można opisać jako:

tc filter add dev IF [ protocol PROTO ]
                     [ (preference|priority) PRIO ]
                     [ parent CBQ ]

Pole protocol opisuje protokół, w stosunku do którego filtr będzie sprawdzany. Rozważamy tylko przypadek protokołu ip. Pole preference (priority można używać zamiennie) określa priorytet aktualnie definiowanego filtra. Jest to o tyle ważne, że możesz posiadać kilka filtrów (list reguł) z różnymi priorytetami. Każda lista będzie sprawdzana w kolejności w jakiej dodawano reguły, następnie przetwarzana będzie lista z mniejszym priorytetem (wyższym numerem preferencji). W końcu pole parent określa górne drzewo CBQ (np. 1:0) do którego powinien dołączyć się filtr.

Opcje opisane wyżej dotyczą wszystkich filtrów, nie tylko U32.

12.1.1. Selektor U32

Selektor U32 zawiera definicję wzorca, który zostanie sprawdzony z przetwarzanym pakietem. Dokładniej, definiuje które bity mają pasować z nagłówka pakietu - ale jest to bardzo potężne narzędzie. Spójrzmy na następujący przykład, wzięty wprost z rzeczywistego, całkiem skomplikowanego filtra:

# tc filter add dev eth0 protocol ip parent 1:0 pref 10 u32 \
  match u32 00100000 00ff0000 at 0 flowid 1:10

Na razie zostawmy pierwszą linię w spokoju - wszystkie parametry opisują tablice mieszające filtra. Skupmy się na linii selektora, zawierającej słowo match. Selektor wybiera nagłówki IP, których drugi bajt jest równy 0x10 (0010). Jak łatwo zgadnąć, numer 00ff jest maską testu, mówiącą filtrowi które bajty dokładnie dopasować. Wynosi 0xff, więc bajt ma być równy dokładnie 0x10. Słowo kluczowe at oznacza, że test rozpoczynany jest od określonego przesunięcia (w bajtach) -- w tym przypadku w stosunku do początku pakietu. Tłumacząc to na ludzki język, pakiet będzie pasował do filtra, jeśli pole ToS będzie miało ustawione bity `niska zwłoka'. Zanalizujmy następną regułę:

# tc filter add dev eth0 protocol ip parent 1:0 pref 10 u32 \
  match u32 00000016 0000ffff at nexthdr+0 flowid 1:10

Opcja nexthdr oznacza następny nagłówek zahermetyzowany w pakiecie IP, tzn. nagłówek wyższego protokołu. Test rozpocznie się od początku następnego nagłówka i dotyczyć będzie drugiego, 32-bitowego słowa w nagłówku. W protokołach TCP i UDP pole to zawiera port przeznaczenia. Numer podawany jest w formacie big-endian, tzn. starsze bity pierwsze, więc czytamy to jako 0x16 czyli 22 decymalnie - port usługi SSH jeśli byłoby to TCP. Jak możesz zgadnąć, test jest bez sensu jeśli nie ma kontekstu i omówimy to później.

Jeśli zrozumiałeś wszystko co było wcześniej, łatwo możesz zrozumieć następujący selektor: match c0a80100 ffffff00 at 16. Chodzi o trzy-bajtowy test, począwszy od 17-tego bajtu licząc od startu nagłówka IP. Test pasuje dla pakietów, których docelowym adresem jest sieć 192.168.1.0/24. Po zanalizowaniu przykładów, możemy podsumować to, czego się nauczyliśmy.

12.1.2. Selektory ogólne

Selektory ogóle definiują wzór, maskę i przesunięcie (offset), które stosowane będą w stosunku do zawartości pakietu. Używając ich, można sprawdzić praktycznie dowolny bit w nagłówku IP, lub nagłówku wyższej warstwy. Są jednak trochę trudniejsze do spisania i odczytania, niż selektory specyficzne opisane niżej. Ich ogólna składnia wygląda tak:

match [ u32 | u16 | u8 ] WZÓR MASKA [ at PRZESUNIĘCIE | nexthdr+PRZESUNIĘCIE]

Jedno ze słów kluczowych - u32, u16 lub u8 określa długość wzorca w bitach. Następnie powinny pojawić się `wzór' (ang. "pattern") i `maska', w długości zadeklarowanej wcześniej. Przesunięcie określane jest w bajtach. Jeśli podano dodatkowo nexthdr+, przesunięcie jest relatywne w stosunku do początku nagłówka wyższej warstwy.

Trochę przykładów:

# tc filter add dev ppp14 parent 1:0 prio 10 u32 \
     match u8 64 0xff at 8 \
     flowid 1:4

Pakiet będzie pasował do tej reguły, jeśli jego czas życia (TTL) jest równy 64. TTL to pole zaczynające się za 8-mym bajtem nagłówka IP.

Reguła dotyczy wszystkich pakietów TCP z ustawioną flagą ACK:

# tc filter add dev ppp14 parent 1:0 prio 10 u32 \
     match ip protocol 6 0xff \
     match u8 0x10 0xff at nexthdr+13 \
     flowid 1:3 

Użyj tego selektora do wyboru pakietów z ustawioną flagą ACK krótszych niż 64 bajty.

# tc filter add dev ppp14 parent 1:0 protocol ip prio 10 u32 \
            match ip protocol 6 0xff \
            match u8 0x05 0x0f at 0 \
            match u16 0x0000 0xffc0 at 2 \
            match u8 0x10 0xff at 33 \
            flowid 1:3

Ta reguła dotyczy pakietów TCP z ustawioną flagą ACK i nie zawierających żadnych danych. Możemy zobaczyć tu przykład dwóch selektorów. Wynikiem finalnym będzie logiczna operacja AND na rezultatach ich obu. Jeśli przyjrzymy się nagłówkowi IP, widzimy, że bit ACK jest drugim w kolejności, najstarszym bitem (0x10), w 14-tym bajcie nagłówka TCP (at nexthdr+13). Jeśli chodzi o drugi selektor, jeśli chcielibyśmy sobie utrudnić życie, moglibyśmy napisać match u8 0x06 0xff at 9 zamiast używać selektora specyficznego w postaci protocol tcp. 0x06 to numer protokołu TCP a wartość ta zapisana jest w 10-tym bajcie nagłówka IP. Z drugiej strony w tym przykładzie nie możemy użyć żadnego specyficznego selektora dla pierwszego testu, ponieważ nie ma takiego selektora dla bitu ACK nagłówka TCP.

Filtr poniżej to zmodyfikowana wersja wcześniejszego. Różnica polega na tym, że nie sprawdza on długości nagłówka. Dlaczego? Ponieważ powyższy filtr działa tylko na systemach 32-bitowych.

tc filter add dev ppp14 parent 1:0 protocol ip prio 10 u32 \
     match ip protocol 6 0xff \
     match u8 0x10 0xff at nexthdr+13 \
     match u16 0x0000 0xffc0 at 2 \
     flowid 1:3

12.1.3. Selektory specyficzne

Poniższa tabela zawiera listę wszystkich selektorów specyficznych, które autor znalazł w źródłach programu tc. Mogą ułatwić ci życie i zwiększyć czytelność twojej konfiguracji.

FIXME: Tabela znajduje się w osobnym pliku - `selector.html'

FIXME: I nadal tylko po Polsku :-(

FIXME: Trzeba ją zsgmlizować

Trochę przykładów:

# tc filter add dev ppp0 parent 1:0 prio 10 u32 \
     match ip tos 0x10 0xff \
     flowid 1:4

FIXME: test `tcp dport' nie działa tak jak opisano to poniżej:

Powyższa reguła będzie pasować do pakietów z polem ToS ustawionym na wartość 0x10. Zaczyna się ono w drugim bajcie pakiety i ma wielkość jednego bajtu, więc moglibyśmy napisać to za pomocą generalnego selektora: match u8 0x10 0xff at 1. Tkwi tu pewna podpowiedź - selektory specyficzne są zawsze tłumaczone na ogólne i w takiej formie zapisywane w pamięci jądra. Prowadzi to do konkluzji, że selektory tcp i udp są dokładnie takie same i dlatego nie możesz użyć pojedyńczej komendy match tcp dport 53 0xffff by wskazać pakiety TCP wysłane do określonego portu - pasować będą również pakiety UDP wysyłane do tego portu. Musisz pamiętać, żeby podać protokół na koniec poniższej reguły:

# tc filter add dev ppp0 parent 1:0 prio 10 u32 \
        match tcp dport 53 0xffff \
        match ip protocol 0x6 0xff \
        flowid 1:2


/ Linux Reviews / Networking / Kształtowanie Ruchu i Zaawansowany Routing HOWTO