Kształtowanie Ruchu i Zaawansowany Routing HOWTO
BertHubert
Netherlabs BV
bert.hubert%netherlabs.nl
Thomas Graf (Autor sekcji)
tgraf%suug.ch
Gregory Maxwell (Autor sekcji)
Remco van Mook (Autor sekcji)
remco%virtu.nl
Martijn van Oosterhout (Autor sekcji)
kleptog%cupid.suninternet.com
Paul B Schroeder (Autor sekcji)
paulsch%us.ibm.com
Jasper Spaans (Autor sekcji)
jasper%spaans.ds9a.nl
Pedro Larroy (Autor sekcji)
piotr%omega.resa.es
Polskie tłumaczenie: Łukasz Bromirski
lbromirski%mr0vka.eu.org
Oryginalna wersja: 1.35
Oryginalna data: 2003/07/26 19:57:49
Wydanie DocBook
Bardzo praktyczne podejście do iproute2,
kontroli ruchu oraz po części do netfilter.
Dedykacja
Dokument ten dedykowany jest całemu mnóstwu ludzi i jest moją próbą
dania czegoś w zamian. By wymienić zaledwie parę osób:
Rusty Russell
Aleksiej N. Kuzniecow
dobrzy ludzie z Google
Załoga Casema Internet
Wprowadzenie
Witam, Szanowny Czytelniku.
Ten dokument ma nadzieję rozjaśnić trochę zagadnienia routingu w
Linuksie 2.2/2.4. Większość użytkowników nie zdaje sobie nawet sprawy, że
posługuje się narzędziami, które potrafią naprawdę spektakularne rzeczy.
Komendy takie jak route czy ifconfig są
zaledwie namiastkami rozbudowanej i potężnej infrastrukturę iproute2.
Mam nadzieję, że to HOWTO będzie tak czytelne jak te napisane przez
Rusty Russell'a z zespołu netfilter.
Możesz zawsze skontaktować się z nami, pisząc na adres
zespołu HOWTO. Prosimy jednak
byś rozważył wysłanie postu na listę pocztową (zajrzyj do odpowiedniej sekcji)
jeśli masz pytania nie dotyczące bezpośrednio tego HOWTO. Nie stanowimy
darmowego helpdesku, ale zwykle odpowiadamy na pytania zadawane na liście.
Zanim zgubisz się czytając ten dokument, a wszystko co chcesz robić to
kształtowanie ruchu, pomiń wszystko i przejdź bezpośrednio do rozdziału
by zapoznać się z
CBQ.init.
Disclaimer & Licencja
Dokument ten rozpowszechniany jest w nadziei, że będzie użyteczny,
ale BEZ ŻADNEJ GWARANCJI; nawet bez implikowanej gwarancji RĘKOJMI lub
PRZYDATNOŚCI DO KONKRETNEGO ZASTOSOWANIA.
Krótko mówiąc, jeśli twoja sieć STM-64 padnie albo posłuży do rozesłania
pornografii do najbardziej cenionych klientów - to nie była nasza wina.
Przykro nam.
Wszystkie prawa zastrzeżone (c) 2001 przez bert hubert, Gregory Maxwell,
Martijn van Oosterhout, Remco can Mook, Paul B. Schroeder i inni. Materiał ten
może być dystrybuowany tylko na zasadach określonych w Open Publication License,
v1.0 lub późniejszej (ostatnia wersja jest obecnie dostępna pod adresem
http://www.opencontent.org/openpub/).
Namawiamy do darmowego kopiowania i dystrybuowania (sprzedawania lub
rozdawania) tego dokumentu w dowolnym formacie. Wymagamy jednak by poprawki
i/lub komentarze przekazywać do koordynatora dokumentu.
Wymagamy również, żeby w przypadku publikacji tego HOWTO w wersji drukowanej,
autorzy otrzymali próbki na potrzeby recenzji
:-).
Wymagana wiedza
Tak jak wskazuje tytuł, to Zaawansowane
HOWTO. O ile nie
oznacza to w żadnym przypadku wiedzy z dziedziny technologii rakietowych,
zakładamy że posiadasz pewną wiedzę.
Poniżej trochę odwołań, które mogą pomóc w nauczeniu się czegoś:
Zagadnienia sieciowe HOWTO, Rusty Russell'a
Bardzo ładne wprowadzenie, wyjaśniające co to jest sieć i jak
łączy się z innymi sieciami.
Sieć Linuksa (poprzednio Net-3 HOWTO)
Doskonała rzecz, choć bardzo szczegółowa. Uczy wielu rzeczy, które
są już skonfigurowane jeśli możesz połączyć się z Internetem.
Powininno znajdować się w /usr/doc/HOWTO/NET3-4-HOWTO.txt,
ale można je również znaleźć pod adresem
online.
Co Linux może zrobić dla Ciebie
Krótka lista rzeczy, które można uzyskać:
kształtować pasmo sieciowe (ang. bandwidth) dla określonych komputerów
kształtować pasmo sieciowe do określonych komputerów
pomóc ci sprawiedliwie dzielić twoje pasmo sieciowe
bronić sieć przed atakami typu DoS
bronić Internet przed twoimi klientami
wykorzystywać wiele serwerów jak jeden, by uzyskać równoważenie
obciążenia i zwiększoną dostępność
ograniczyć dostęp do twoich komputerów
ograniczyć dostęp twoich użytkowników do innych komputerów
prowadzić routing w oparciu o identyfikator użytkownika (tak!),
adres MAC, źródłowy adres IP, port, typ usługi, czas dnia i zawartość
Obecnie niewiele osób używa tych zaawansowanych możliwości. Dzieje się tak
z wielu powodów. O ile dokumentacja jest bardzo szczegółowa, nie jest zbyt
przyjazna czy zrozumiała. A kształtowanie ruchu jest prawie w ogóle
nieudokumentowane.
Notatki gospodyni
Warto zaznaczyć parę rzeczy dotyczących tego dokumentu. Mimo, że jestem autorem
większości teksu, nie chcę by tak zostało. Jestem wielkim zwolennikiem ruchu
Open Source, więc zachęcam do nadsyłania przemyśleń, uaktualnień, poprawek i tak
dalej. Nie zwlekajcie z informowaniem mnie o literówkach lub po prostu błędach.
Jeśli mój Angielski jest trochę drewniany, proszę zwrócić uwagę, że nie jest to
mój język ojczysty. Zapraszam do nadsyłania sugestii.
Jeśli uważasz, że masz lepsze kwalifikacje by zajmować się którąś sekcją, lub
myślisz że mógłbyś napisać a potem zajmować się nowymi sekcjami, zapraszam do
zrobienia tego. Źródło tego dokumentu dostępne jest przez CVS w formacie SGML.
Namawiam do dołączenia się do projektu.
By wam pomóc, znajdziecie tu wiele uwag FIXME. Poprawki są zawsze mile widziane!
Za każdym razem gdy znajdziesz notatkę FIXME, powinieneś wiedzieć, że wchodzisz na
nieznane terytorium. Nie chodzi o to, że wszędzie będą błędy, ale należy być uważnym.
Jeśli udało Ci się coś potwierdzić lub wręcz przeciwnie - wskazać błąd, proszę, daj
nam znać byśmy mogli popracować nad fragmentem zawierającym notkę FIXME.
W tym HOWTO pozwolę sobię na pewną swobodę. Na przykład, zakładam że posiadasz
10Mbit-owe połączenie z Internetem, mimo że nie jest to zbyt popularna konfiguracja.
Dostęp, CVS i wysyłanie uaktualnień
To HOWTO znajduje się pod tym adresem.
Na potrzeby projektu utrzymujemy serwer CVS z anonimowym dostępem z całego świata.
Jest to przydatne z wielu powodów. Uaktalnienie twojej kopii do najnowszej wersji
czy też wysłanie nam poprawek nie stanowi dzięki takiemu rozwiązaniu żadnego
problemu.
Co więcej, system ten umożliwia wielu autorom na pracę nad tekstem źródłowym
niezależnie.
$ export CVSROOT=:pserver:anon@outpost.ds9a.nl:/var/cvsroot
$ cvs login
CVS password: [wprowadź 'cvs' (bez apostrofów)]
$ cvs co 2.4routing
cvs server: Updating 2.4routing
U 2.4routing/lartc.db
Jeśli zauważysz błąd, lub chciałbyś coś dodać, popraw to na swojej lokalnej
kopii, następnie uruchom cvs -z3 diff -uBb i wyślij rezultat
pod adres howto%ds9a.nl - łatwiej będzie nam się nim zająć.
Dziękujemy! Przy okazji, upewnij się że edytowałeś plik .db - pozostałe są
z niego generowane.
Razem z dokumentem źródłowym dostępny jest również plik Makefile, który powinien
pomóc Ci wygenerować dokumenty w formacie postscript, dvi, pdf, html i czystym
tekście. Być może będziesz musiał zainstalować docbook,
docbook-utils, ghostscript oraz
tetex by otrzymać wszystkie formaty.
Nie edytuj pliku 2.4routing.sgml! Zawiera starszą wersję tego HOWTO. Obecny
plik zawierający HOWTO to lartc.db.
Lista pocztowa
Autorzy otrzymują rosnącą liczbę poczty dotyczącej tego HOWTO. Z uwagi na interes
ogółu, zdecydowaliśmy o stworzeniu listy pocztowej, na której ludzie mogą dyskutować
między sobą o zagadnieniach zaawansowanego routingu i kształtowania pasma. Możesz
zapisać się na tą listę pod
tym adresem.
Należy zwrócić uwagę, że autorzy są bardzo powściągliwi jeśli chodzi o odpowiadanie
na pytania nie zadane na liście. Chcielibyśmy ją archiwizować i utrzymywać jako swego
rodzaju bazę wiedzy. Jeśli masz pytanie, proszę przeszukaj archiwum, a następnie
wyślij post na listę.
Układ tego dokumentu
Zaczniemy robić interesujące rzeczy praktycznie zaraz, co oznacza, że na początku
wiele rzeczy możesz uznać za słabo lub wcale nie wytłumaczone. Przeczytaj je zakładając,
że wszystko stanie się jasne potem.
Routing i filtrowanie to dwie różne rzeczy. Filtrowanie zostało bardzo dobrze
udokumentowane w HOWTO Rusty'ego, które dostępne są pod adresem:
Rusty's Remarkably Unreliable Guides
My skupimy się głównie na pokazaniu co możliwe jest przy połączeniu infrastruktury
netfilter i iproute2.
Wprowadzenie do iproute2
Dlaczego iproute2?
Większość dystrybucji Linuksa, i większość UNIXów, używa szacownych komend
arp, ifconfig i route.
O ile narzędzia te działają, powodują trochę nieoczekiwanych rezultatów od
wersji Linuksa 2.2 w górę. Na przykład, tunele GRE są integralną częścią
routingu a wymagają oddzielnych narzędzi.
Jeśli chodzi o iproute2, tunele są integralną
częścią zestawu.
Kernele Linuksa od wersji 2.2 zawierają kompletnie przeprojektowany podsystem
sieciowy. Wydajność nowego kodu i zestaw jego możliwości powoduje, że Linuks nie
ma zbyt wielu konkurentów na arenie systemów operacyjnych. Tak naprawdę, nowy
kod routujący, filtrujący i klasyfikujący jest potężniejszy niż ten dostarczany
w większości dedykowanych routerów, ścian ogniowych i produktów zajmujących się
kształtowaniem pasma.
W trakcie rozwijania nowych koncepcji sieciowych, ludzie znajdowali zawsze
sposoby by dołożyć je do istniejących szkieletów już stworzonych systemów
operacyjnych. To ciągłe dodawanie kolejnych warstw doprowadziło do tego, że kod
sieciowy może czasami ciekawie się zachowywać lub wyglądać, tak jak to ma
miejsce w przypadku większości ludzkich języków. W przeszłości, Linux emulował
obsługę większości zagadnień sieciowych w sposób zgody z SunOS, który sam nie
jest zbyt idealny.
Nowy szkielet umożliwia jasne wyrażanie potrzeb i pragnień niedostępnych
wcześniej w Linuksie.
Przewodnik po iproute2
Linuks posiada bardzo wyrafinowany system kształtowania pasma, nazywany
Traffic Control. System ten udostępnia wiele metod klasyfikowania, priorytetowania,
współdzielenia i ograniczania zarówno ruchu wychodzącego jak i
przychodzącego.
Zaczniemy od krótkiej wycieczki po możliwościach iproute2.
Wymagania wstępne
Powinieneś upewnić się, że wszystkie narzędzia z przestrzeni użytkownika są
zainstalowane. Paczka nazywa się 'iproute' zarówno w przypadku RedHat'a jak
i Debiana, można ją znaleźć pod adresem
ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss??????.tar.gz".
Możesz również spróbować pobrać i użyć najnowszą wersję, znajdującą się
pod tym adresem
Niektóre części iproute wymagają byś włączył pewne opcje w kernelu. Warto również
zauważyć, że wszystkie wydania RedHat'a do i łącznie z wersją 6.2 dostarczane
są bez większością opcji odpowiedzialnych za kontrolę ruchu.
RedHat 7.2 ma domyślnie włączone wszystko.
Upewnij się również, że w konfiguracji jądra zaznaczyłeś obsługę netlink,
jeśli będziesz musiał przekompilować swój kernel. Jest on wymagany
przez iproute2.
Badanie obecnej konfiguracji
Może to być pewnym zaskoczeniem, ale iproute2 jest już skonfigurowane!
Obecne komendy ifconfig i route używają
zaawansowanych wywołań systemowych, ale w większości z domyślnymi i bardzo
bezpiecznymi (tzn. nudnymi) ustawieniami.
Głównym narzędziem jest program ip, poprosimy go o
wyświetlenie interfejsów.
ip pokazuje nam połączenia
[ahu@home ahu]$ ip link list
1: lo: <LOOPBACK,UP> mtu 3924 qdisc noqueue
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: dummy: <BROADCAST,NOARP> mtu 1500 qdisc noop
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
3: eth0: <BROADCAST,MULTICAST,PROMISC,UP> mtu 1400 qdisc pfifo_fast qlen 100
link/ether 48:54:e8:2a:47:16 brd ff:ff:ff:ff:ff:ff
4: eth1: <BROADCAST,MULTICAST,PROMISC,UP> mtu 1500 qdisc pfifo_fast qlen 100
link/ether 00:e0:4c:39:24:78 brd ff:ff:ff:ff:ff:ff
3764: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP> mtu 1492 qdisc pfifo_fast qlen 10
link/ppp
Twój ekran wynikowy może się trochę różnić, ale powyższy wydruk pochodzi z
mojego domowego routera NAT. Wytłumaczę tylko część, jako że nie wszystko
jest bezpośrednio związane.
Na początek widzimy interfejs loopback. O ile twój komputer może i powinien
pracować bez niego, radziłbym tego nie próbować. Rozmiar MTU (ang. Maximum
Transfer Unit - Maksymalnej Jednostki Transmisji) wynosi 3924 oktety i nie
spodziewamy się go kolejkować. Ma to sens, ponieważ interfejs ten jest tylko
fantazją twojego kernela.
Pominę interfejs dummy, może on nie być obecny na twoim komputerze. Następnie
mamy dwa fizyczne interfejsy, jeden po stronie modemu kablowego i drugi
podłączony do mojego domowego segmentu ethernetowego. Dalej widzimy
interfejs ppp0.
Zauważ brak adresów IP. iproute nie używa koncepcji łączenia 'połączeń' z
'adresami IP'. Po wprowadzeniem aliasów IP, koncepcja 'tego konkretnego'
adresu IP stała się jakby mniej ważna.
Pokazano natomiast adresy MAC, identyfikatory sprzętowe naszych
interfejsów ethernetowych.
ip pokazuje nam nasze adresy IP
[ahu@home ahu]$ ip address show
1: lo: <LOOPBACK,UP> mtu 3924 qdisc noqueue
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 brd 127.255.255.255 scope host lo
2: dummy: <BROADCAST,NOARP> mtu 1500 qdisc noop
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
3: eth0: <BROADCAST,MULTICAST,PROMISC,UP> mtu 1400 qdisc pfifo_fast qlen 100
link/ether 48:54:e8:2a:47:16 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.1/8 brd 10.255.255.255 scope global eth0
4: eth1: <BROADCAST,MULTICAST,PROMISC,UP> mtu 1500 qdisc pfifo_fast qlen 100
link/ether 00:e0:4c:39:24:78 brd ff:ff:ff:ff:ff:ff
3764: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP> mtu 1492 qdisc pfifo_fast qlen 10
link/ppp
inet 212.64.94.251 peer 212.64.94.1/32 scope global ppp0
Tutaj mamy więcej informacji. Pokazano wszystkie nasze adresy, łącznie
ze wskazaniem do których interfejsów należą. 'inet' oznacza Internet
(IPv4). Istnieje wiele innych rodzin adresów, ale w tym momencie zupełnie
nas nie obchodzą.
Przyjrzyjmy się bliżej eth0. Twierdzi, że związany jest z internetowym adresem
'10.0.0.1/8'. Co to oznacza? Człon /8 określa ilość bitów, które należą do
Adresu Sieci. Są 32 bity, mamy więc 24 bity na określenie części swojej sieci.
Pierwsze 8 bitów z 10.0.0.1 odpowiada 10.0.0.0, naszemu Adresowi Sieciowemu,
naszą maską jest więc 255.0.0.0.
Pozostałe bity należą do przestrzeni adresowej tego interfejsu, więc
10.250.3.13 jest bezpośrednio osiągalny przez eth0, tak samo jak na
przykład 10.0.0.1.
Z ppp0 jest dokładnie tak samo, mimo że różnią się numerki. Jego adres to
212.64.94.251 bez maski podsieci. Oznacza to, że jest to połączenie punkt-punkt
i każdy adres, z wyjątkiem 212.64.94.251 jest zdalny. Jest jednak trochę więcej
informacji. Wiemy, że po drugiej stronie połączenia też jest jeden adres -
212.64.94.1. Dodatek /32 oznacza po prostu, że nie ma 'bitów sieci'.
Bardzo ważne żebyś zrozumiał opisywane wyżej zagadnienia. Zajrzyj do
wspomnianej wcześniej dokumentacji, jeśli masz problemy.
Możesz również zauważyć 'qdisc', co oznacza Dyscyplinę Kolejkowania
(ang. Queueing Discipline). Znaczenie tej funkcji stanie się jasne później.
ip pokazuje nam trasy routingu
Cóż, wiemy jak znaleźć adresy 10.x.y.z i jesteśmy w stanie dotrzeć do
212.64.94.1. To jednak nie wystarcza, musimy mieć jeszcze instrukcje
jak dotrzeć do pozostałej części świata. Internet dostępny jest przez nasze
połączenie PPP i wygląda na to, że to 212.64.94.1 będzie rozsyłał nasze
pakiety po świecie, oraz zbierał i dostarczał odpowiedzi.
[ahu@home ahu]$ ip route show
212.64.94.1 dev ppp0 proto kernel scope link src 212.64.94.251
10.0.0.0/8 dev eth0 proto kernel scope link src 10.0.0.1
127.0.0.0/8 dev lo scope link
default via 212.64.94.1 dev ppp0
Wydruk jest samoopisujący się. Pierwsze 4 linie wprost informują
o tym, co już zostało wydrukowane po użyciu komendy
ip address show, ostatnia linia określa, że reszta
adresów będzie osiągalna przez adres 212.64.94.1 - domyślną bramkę.
Wiemy, że to bramka po słowie via, które oznacza, że wysyłamy pod ten
adres pakiety a on bierze na siebie resztę.
Dla porównania, poniżej wydruk ze standardowej komendy route:
[ahu@home ahu]$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use
Iface
212.64.94.1 0.0.0.0 255.255.255.255 UH 0 0 0 ppp0
10.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 eth0
127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo
0.0.0.0 212.64.94.1 0.0.0.0 UG 0 0 0 ppp0
ARP
ARP, to Protokół Rozwiązywania Adresów (ang. Address Resolution Protocol),
opisany w RFC 826.
ARP używany jest w komputerach podłączonych do sieci do rozwiązywania
adresów sieciowych/lokalizacji innych komputerów również podłączonych do tej sieci.
Komputery w Internecie identyfikuje się generalnie po ich nazwach, które rozwiązywane
są na adresy IP. W ten właśnie sposób komputer w sieci foo.com może komunikować
się z inną maszyną z sieci bar.net. Adresy IP nie mówią jednak nic o fizycznej
lokalizacji komputera. Wtedy właśnie pojawia się ARP.
Spójrzmy na bardzo prosty przykład. Załóżmy, że mam sieć złożoną z kilku komputerów.
Dwa z komputerów w tej sieci, to foo z adresem 10.0.0.1 i bar> z adresem 10.0.0.2.
foo chce wykonać ping do bar, by sprawdzić czy bar pracuje, ale nie wie przecież
gdzie znajduje się bar. Chcąc wykonać ping, musi zatem najpierw wysłać zapytanie
ARP.
Zapytanie to podobne jest do wykrzyczenia 'bar (10.0.0.2)! Gdzie jesteś?'.
W rezultacie wszystkie komputery w sieci usłyszą zapytanie, ale tylko bar
(10.0.0.2) odpowie. Odpowiedź ARP zostanie skierowana bezpośrednio do foo i
będzie czymś w rodzaju 'foo (10.0.0.1), jestem pod 00:60:94:E9:08:12'. Po tej
prostej wymianie, której użyto by znaleźć kolegę w sieci, foo będzie w stanie
komunikować się z bar dopóki zapomni (lub pamięć podręczna arp wygaśnie)
gdzie jest bar> (na maszynach Uniksowych standardowo po 15 minutach).
A teraz spójrzmy jak to działa. Możesz obejrzeć tabelę sąsiedztwa arp w ten sposób:
[root@espa041 /home/src/iputils]# ip neigh show
9.3.76.42 dev eth0 lladdr 00:60:08:3f:e9:f9 nud reachable
9.3.76.1 dev eth0 lladdr 00:06:29:21:73:c8 nud reachable
Jak widać, mój komputer espa041 (9.3.76.41) wie gdzie znaleźć espa042
(9.3.76.42) i espagate (9.3.76.1). Spróbujmy teraz dodać inny komputer
do pamięci podręcznej arp.
[root@espa041 /home/paulsch/.gnome-desktop]# ping -c 1 espa043
PING espa043.austin.ibm.com (9.3.76.43) from 9.3.76.41 : 56(84) bytes of data.
64 bytes from 9.3.76.43: icmp_seq=0 ttl=255 time=0.9 ms
--- espa043.austin.ibm.com ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.9/0.9/0.9 ms
[root@espa041 /home/src/iputils]# ip neigh show
9.3.76.43 dev eth0 lladdr 00:06:29:21:80:20 nud reachable
9.3.76.42 dev eth0 lladdr 00:60:08:3f:e9:f9 nud reachable
9.3.76.1 dev eth0 lladdr 00:06:29:21:73:c8 nud reachable
W wyniku działań espa041, próbującego znaleźć espa043, adres tego ostatniego
został dodany do pamięci podręcznej arp. Dopóki ten wpis nie wygaśnie (w
rezultacie braku komunikacji pomiędzy obydwoma komputerami), espa041 wie
gdzie znaleźć espa043 i nie ma potrzeby rozsyłania zapytań ARP.
Teraz wykasujmy espa043 z pamięci podręcznej arp:
[root@espa041 /home/src/iputils]# ip neigh delete 9.3.76.43 dev eth0
[root@espa041 /home/src/iputils]# ip neigh show
9.3.76.43 dev eth0 nud failed
9.3.76.42 dev eth0 lladdr 00:60:08:3f:e9:f9 nud reachable
9.3.76.1 dev eth0 lladdr 00:06:29:21:73:c8 nud stale
espa041 zapomniał gdzie znaleźć espa043 i będzie musiał wysłać kolejne
zapytanie ARP jeśli będzie potrzebował skontaktować się z espa043.
Możesz również zauważyć, że stan wpisu przy espagate (9.3.76.1) został
zmieniony na 'stale' (niepewny, stary). Oznacza to tylko tyle, że pokazywana
lokalizacja jest prawdziwa, ale będzie musiała być potwierdzona przed
nawiązaniem jakiegokolwiek połączenia do tego komputera.
Reguły - baza danych polityki routingu
Jeśli posiadasz duży ruter, możesz zaspokajać potrzeby różnych ludzi, którzy
chcą być obsługiwani w różny sposób. Pozwala na to właśnie baza danych polityki
routingu, dostarczając możliwości utrzymywania wielu zestawów tabel routingu.
Jeśli chcesz użyć tej opcji, upewnij się że twój kernel skompilowano z użyciem
opcji "IP: advanced router" oraz "IP: policy routing".
Kiedy kernel musi podjąć decyzję o routingu, sprawdza z której tabeli ma
skorzystać. Domyślnie, są trzy takie tabele. Stare narzędzie 'route' modyfikuje
główną i lokalną, dokładnie tak, jak domyślnie zachowuje się nowe narzędzie
ip.
Domyślne reguły:
[ahu@home ahu]$ ip rule list
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
Polecenie listuje priorytety wszystkich reguł. Widać, że wszystkie wpisy dotyczą
wszystkich pakietów ( 'from all' ). Widzieliśmy już 'główną' (ang. 'main') tabelę
wcześniej, można ją wylistować przez użycie polecenia
ip route ls, ale 'lokalna' (ang. 'local') i 'domyślna'
(ang. 'default') są nowe.
Jeśli chcemy robić wymyślne rzeczy, musimy wygenerować reguły, które
wskazywać będą do różnych tabel routingu - innych niż podstawowe, wspólne
dla całego systemu.
Po dokładny opis tego co kernel robi gdy jest więcej pasujących reguł,
odsyłam do dokumentacji ip-cref Aleksieja.
Prosty routing na podstawie źródła (ang. source routing)
Wróćmy do prawdziwego przykładu. Mam 2 (dokładniej 3, w momencie gdy je
zwracałem) modemy kablowe połączone do linuksowego routera NAT (wykonującego
translację adresów sieciowych). Ludzie którzy wokół żyją, płacą mi za
używanie Internetu. Powiedzmy, że jeden z nich odwiedza tylko hotmail i
chce płacić mniej. Jeśli chodzi o mnie jest to w porządku, ale będą
używać starszego modemu.
'Szybki' modem kablowy znany jest jako 212.64.94.251 i jest łączem PPP do
212.64.94.1. 'Wolny' modem ma różne adresy - z uwagi na ten przykład skupimy
się na 212.64.78.148 i jest podłączony do 195.96.98.253.
Tabela lokalna:
[ahu@home ahu]$ ip route list table local
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
local 10.0.0.1 dev eth0 proto kernel scope host src 10.0.0.1
broadcast 10.0.0.0 dev eth0 proto kernel scope link src 10.0.0.1
local 212.64.94.251 dev ppp0 proto kernel scope host src 212.64.94.251
broadcast 10.255.255.255 dev eth0 proto kernel scope link src 10.0.0.1
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
local 212.64.78.148 dev ppp2 proto kernel scope host src 212.64.78.148
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
Widać wiele oczywistych rzeczy, ale gdzieś należy je podać. Cóż, znalazły
się tutaj. Tabela domyślna jest pusta.
Zajrzyjmy do tabeli głównej:
[ahu@home ahu]$ ip route list table main
195.96.98.253 dev ppp2 proto kernel scope link src 212.64.78.148
212.64.94.1 dev ppp0 proto kernel scope link src 212.64.94.251
10.0.0.0/8 dev eth0 proto kernel scope link src 10.0.0.1
127.0.0.0/8 dev lo scope link
default via 212.64.94.1 dev ppp0
Generujemy teraz nową regułę, którą nazwiemy `John', tak jak nasz
hipotetyczny kolega. Możemy oczywiście operować czystymi numerkami, ale
łatwiej jest dodać nasze tabele do pliku
/etc/iproute2/rt_tables.
# echo 200 John >> /etc/iproute2/rt_tables
# ip rule add from 10.0.0.10 table John
# ip rule ls
0: from all lookup local
32765: from 10.0.0.10 lookup John
32766: from all lookup main
32767: from all lookup default
Teraz pozostało tylko wygenerować tabelę Johna i wyczyścić pamięć podręczną
trasowania:
# ip route add default via 195.96.98.253 dev ppp2 table John
# ip route flush cache
I to wszystko. Pozostawiamy jako ćwiczenie dla czytelnika, zaimplementowanie
tego w skrypcie ip-up.
Routing dla wielu łącz/do wielu dostawców usług
Często spotyka się konfiugrację taką jak poniższa - w której mamy dwóch
dostawców Internetu dla sieci lokalnej (lub czasami nawet pojedyńczej
maszyny).
________
+------------+ /
| | |
+-------------+ Dostawca 1 +-------
__ | | | /
___/ \_ +------+-------+ +------------+ |
_/ \__ | if1 | /
/ \ | | |
| Sieć lokalna -----+ Router | | Internet
\_ __/ | Linuksowy | |
\__ __/ | if2 | \
\__/ +------+-------+ +------------+ |
| | | \
+-------------+ Dostawca 2 +-------
| | |
+------------+ \________
Zwykle w takiej konfiguracji pojawiają się dwa pytania.
Dostęp rozłączny (ang. split access)
Pierwsze to jak routować odpowiedzi na pakiety przychodzące od powiedzmy
dostawcy pierwszego, z powrotem tą samą drogą (nie wykorzystując drugiego
łącza).
Zdefiniujmy parę nazw symbolicznych. Niech $IF1 oznacza
pierwszy interfejs (if1 na rysunku powyżej) a $IF2
drugi interfejs. Następnie niech $IP1 będzie adresem IP
interfejsu $IF1 a $IP2 adresem IP
skojarzonym z interfejsem $IF2. Następnie, niech
$P1 oznacza adres IP pierwszego dostawcy a
$P2 drugiego. Na koniec niech $P1_NET
będzie siecią IP w której znajduje się $P1, a
$P2_NET odpowiednio siecią IP w której jest
$P2.
Należy stworzyć dwa dodatkowe wpisy w tabeli routingu, powiedzmy
T1 i T2. Dodaje się je do
/etc/iproute2/rt_tables. Następnie należy dodać
odpowiednio routing w sposób jak poniżej:
ip route add $P1_NET dev $IF1 src $IP1 table T1
ip route add default via $P1 table T1
ip route add $P2_NET dev $IF2 src $IP2 table T2
ip route add default via $P2 table T2
Nic spektakularnego, tworzymy trasy do bramy i dodajemy trasę domyślną
przez tą bramę - tak jakbyśmy mieli do czynienia z pojedyńczym
dostawcą, z tym wyjątkiem, że mamy osobne tablice dla każdego dostawcy.
Zauważ, że wystarczy samo wpisanie trasy - ponieważ mówi jak znaleźć
dowolny host w danej sieci, obejmując również bramę tak jak w przykładzie
powyżej.
Teraz należy skonfigurować główną tabelę routingu. Dobrym pomysłem jest
kierować ruch do bezpośredniego sąsiada przez interfejs, którym ten
sąsiad jest podłączony. Zwróć uwagę na argumenty 'src' - zapewniają
że wybrany zostanie poprawny wychodzący adres IP.
ip route add $P1_NET dev $IF1 src $IP1
ip route add $P2_NET dev $IF2 src $IP2
Następnie należy dodać trasę domyślną:
ip route add default via $P1
A na koniec skonfigurować tabele routingu. To one wybierają która
tablica zostanie wybrana. Chcemy się upewnić, że wykonujemy routing
interfejsem, który ma odpowiedni źródłowy adres IP:
ip rule add from $IP1 table T1
ip rule add from $IP2 table T2
Powyższy zestaw poleceń powoduje, że wszystkie odpowiedzi na ruch
przechodzący przez dany interfejs, zostaną wysłane tym właśnie
interfejsem.
Czytelnik Rod Roark zauważył: Jeśli $P0_NET to lokalna sieć a $IF0 to jej interfejs,
warto dodać dodatkowe wpisy:
ip route add $P0_NET dev $IF0 table T1
ip route add $P2_NET dev $IF2 table T1
ip route add 127.0.0.0/8 dev lo table T1
ip route add $P0_NET dev $IF0 table T2
ip route add $P1_NET dev $IF1 table T2
ip route add 127.0.0.0/8 dev lo table T2
'
Jest to oczywiście bardzo prosta konfiguracja. Będzie działała prawidłowo
dla wszystkich procesów działających na routerze i dla wszystkich
połączeń z sieci lokalnej (jeśli włączono translację adresów).
Jeśli translacji nie włączono, to albo dostałeś osobne publiczne
przestrzenie adresowe od obu dostawców, albo będziesz chciał robić
translację adresów dla jednego z dostawców. W obu przypadkach musisz
dodać reguły wybierające przez którego dostawcę routować ruch
na podstawie adresów IP maszyn w sieci lokalnej (inicjujących ten ruch).
Rozkładanie obciążenia (ang. load balancing)
Drugie pytanie brzmi: jak rozłożyć obciążenie wychodzące na obu
dostawców. Odpowiedzią jest: nie jest to specjalnie trudne, jeśli i
tak masz już sytuację opisaną w punkcie powyżej.
Zamiast wybierać jednego z dostawców jako trasę domyślną, musisz
wskazać obu. Domyślnie jądro będzie rozkładało ruch wychodzący
pomiędzy dwie trasy domyślne. Konfiguruje się to w ten sposób:
ip route add default scope global nexthop via $P1 dev $IF1 weight 1 \
nexthop via $P2 dev $IF2 weight 1
Zapewni to opisaną funkcjonalność. Argumentem weight
można dokładnie dostosować metrykę danego dostawcy, efektywnie
zwiększając lub zmniejszając ilość ruchu przesyłanego przez niego
na rzecz drugiego dostawcy.
Zwróć jednak uwagę, że równoważenie obciążenia nie będzie doskonałe,
a co więcej bazuje na trasach - które przechowywane są w pamięci
podręcznej. Innymi słowy, trasy do najczęściej odwiedzanych stron
będą prowadziły zawsze przez tego samego dostawcę.
I jeszcze jedno - jeśli naprawdę chcesz coś takiego zastosować,
prawdopodobnie powinieneś rzucić okiem na łatki Juliana Anastazowa,
znajdujące się pod
adresem jego strony,
Powinny one ułatwić ci trochę konfigurację takiego podziału ruchu.
Tunele - GRE i inne
W Linuksie dostępne są trzy rodzaje tuneli. Mamy tunelowanie IP w IP,
tunelowanie GRE i tunele żyjące poza jądrem (na przykład PPTP).
Tunelowanie IP w IP
Ten rodzaj tunelowania jest dostępny w Linuksie już od bardzo dawna.
Wymaga dwóch modułów kernela: ipip.o oraz
new_tunnel.o.
Powiedzmy że masz 3 sieci: Wewnętrzne A i B i pośrednią C (na przykład
Internet). Mamy więc sieć A:
network 10.0.1.0
netmask 255.255.255.0
router 10.0.1.1
W sieci C router ma adres 172.16.17.18.
Oraz sieć B:
network 10.0.2.0
netmask 255.255.255.0
router 10.0.2.1
W sieci C router ma adres 172.19.20.21.
Jeśli chodzi o sieć C, zakładamy że przekazuje pakiety od A do B i odwrotnie.
Można do tego używać nawet Internetu.
Oto co trzeba zrobić:
Po pierwsze, upewnij się że zainstalowano moduły:
insmod ipip.o
insmod new_tunnel.o
Teraz, na routerze sieci A wykonaj:
ifconfig tunl0 10.0.1.1 pointopoint 172.19.20.21
route add -net 10.0.2.0 netmask 255.255.255.0 dev tunl0
A na routerze sieci B:
ifconfig tunl0 10.0.2.1 pointopoint 172.16.17.18
route add -net 10.0.1.0 netmask 255.255.255.0 dev tunl0
A gdy skończyłeś używać tunelu, wykonaj:
ifconfig tunl0 down
Presto, koniec. Nie możesz jednak przekazywać pakietów rozgłoszeniowych
(ang. broadcasts) i ruchu IPv6 przez tunel IP-w-IP. Można tylko łączyć dwie
sieci IPv4, które normalnie nie mogłyby ze sobą rozmawiać - to
wszystko. Jeśli chodzi o zgodność w dół, kod znalazł się w jądrze
w okolicach wersji 1.3 - jest już obecny zatem jakiś czas. Natomiast
jeśli chodzi o inne systemy - ten rodzaj tunelowania nie działa z innymi
systemami czy routerami - przynajmniej na tyle na ile wiem.
Jest bardzo prosty, ale działa. Używaj jeśli musisz, w przeciwnym razie
sięgnij po tunele GRE.
Tunelowanie GRE
Protokół tunelujący GRE został pierwotnie stworzony przez Cisco i jest w
stanie zrealizować trochę więcej niż tunelowanie IP-w-IP. Na przykład, możesz
również transportować ruch multicastowy i IPv6 przez tunel GRE.
W Linuksie, będziesz potrzebował modułu ip_gre.o.
Tunelowanie IPv4
Najpierw zajmijmy się tunelowaniem IPv4.
Powiedzmy że masz 3 sieci: Wewnętrzne A i B oraz pośrednią C
(lub, powiedzmy Internet).
Mamy więc sieć A:
network 10.0.1.0
netmask 255.255.255.0
router 10.0.1.1
Router ma adres 172.16.17.18 w sieci C. Nazwijmy ją neta
(dobra, strasznie oryginalne).
...sieć B:
network 10.0.2.0
netmask 255.255.255.0
router 10.0.2.1
Router ma adres 172.19.20.21 w sieci C. Nazwijmy ją netb
(nadal mało oryginalne).
Natomiast jeśli chodzi o sieć C, zakładamy że przekazuje pakiety od A do B i
odwrotnie. Jak i dlaczego nas nie interesuje.
Na routerze w sieci A wykonamy:
ip tunnel add netb mode gre remote 172.19.20.21 local 172.16.17.18 ttl 255
ip link set netb up
ip addr add 10.0.1.1 dev netb
ip route add 10.0.2.0/24 dev netb
Omówmy to w paru zdaniach. W linii 1 dodaliśmy urządzenie tunelujące i nazwaliśmy
je netb (co jest raczej oczywiste, ponieważ to tam ma
prowadzić). Co więcej, określiliśmy, że używamy protokołu GRE (mode gre),
zdalny adres to 172.19.20.21 (router po drugiej stronie), nasze tunelowane
pakiety powinny pochodzić z 172.16.17.18 (dzięki temu możesz mieć wiele
interfejsów w sieci C i określić wprost z którego mają być wysyłane pakiety),
oraz, że pole TTL pakietów powinno być ustawiane na 255 (ttl 255).
Druga linia uaktywnia urządzenie.
W trzeciej linii ustaliliśmy adres nowego urządzenia netb
na 10.0.1.1. Dla małych sieci jest to w zasadzie w porządku, ale jeśli rozpoczynasz
poważne kopanie (WIELE tuneli), powinieneś rozważyć użycie innego zakresu adresów
IP dla interfejsów tunelujących (w naszym przykładzie, mógłbyś użyć 10.0.3.0).
W czwartej linii ustawiamy trasę dla sieci B. Zauważ inną notację w masce sieciowej.
Jeśli nie jest ci ona znana, oto jak działa: zapisujesz maskę sieciową w formie
binarnej i liczysz wszystkie jedynki. Jeśli nie wiesz jak to zrobić, zapamiętaj
że 255.0.0.0 to /8, 255.255.0.0 to /16 a 255.255.255.0 to /24. A 255.255.254.0 to
/23, gdybyś się zastanawiał.
Ale koniec tego, zacznijmy z routerem w sieci B.
ip tunnel add neta mode gre remote 172.16.17.18 local 172.19.20.21 ttl 255
ip link set neta up
ip addr add 10.0.2.1 dev neta
ip route add 10.0.1.0/24 dev neta
A jeśli zechciałbyś usunąć tunel na routerze A:
ip link set netb down
ip tunnel del netb
Oczywiście, możesz zastąpić netb przez neta dla routera B.
Tunelowanie IPv6
Zajrzyj do sekcji 6, by zapoznać się z krótkim wprowadzeniem do protokołu IPv6 i
formacie zapisu adresów.
Do roboty z tunelami.
Zakładamy, że masz następującą sieć IPv6 i chcesz podłączyć się do 6bone
lub kolegi.
Network 3ffe:406:5:1:5:a:2:1/96
Twój adres IPv4 to 172.16.17.18 a router IPv4 6bone ma adres 172.22.23.24.
ip tunnel add sixbone mode sit remote 172.22.23.24 local 172.16.17.18 ttl 255
ip link set sixbone up
ip addr add 3ffe:406:5:1:5:a:2:1/96 dev sixbone
ip route add 3ffe::/15 dev sixbone
Omówmy to. W pierwszej linii stworzyliśmy tunel nazwany sixbone.
Nadaliśmy mu tryb pracy sit (co oznacza tunelowanie IPv6 w IPv4) oraz wskazaliśmy gdzie ma
być skierowany (remote) i gdzie się zaczynać (local). TTL ustawione jest na maksymalną
wartość 255. Następnie, podnieśliśmy interfejs (up). Na koniec dodaliśmy nasz własny
adres sieciowy i ustawiliśmy trasę na 3ffe::/15 (co jest obecnie adresem całej
6bone) w tunelu.
Tunele GRE są obecnie preferowanym rodzajem tunelowania. Są standardowe i przyjęte
również poza społecznością linuksową, a w związku z tym są Dobrą Rzeczą.
Tunele w przestrzeni użytkownika
Istnieją dziesiątki implementacji tunelowania poza kernelem. Najbardziej
znane są oczywiście PPP i PPTP, ale jest ich dużo więcej (niektóre firmowe,
niektóre bezpieczne, inne nie używają nawet IP) i są zdecydowanie poza
tematem tego HOWTO.
Tunelowanie IPv6 z Cisco i/lub 6bone
Autorstwa Marco Davids <marco%sara.nl>
UWAGA do koordynatora:
Na tyle ile się orientuje tunelowanie IPv6-IPv4 nie jest tak naprawdę tunelowaniem
GRE. Można tunelować IPv6 przez IPv4 w urządzeniach które tworzą tunel GRE
(GRE tuneluje WSZYSTKO w IPv4), ale urządzenie używane w tym rozwiązaniu tuneluje
tylko IPv6 przez IPv4 i w związku z tym to co innego.
Tunelowanie IPv6
To kolejne zastosowanie dla możliwości tunelowania Linuksa. Jest bardzo popularne
u pierwszych użytkowników IPv6, lub pionierów - jak wolicie. Ten praktyczny przykład
z pewnością nie opisuje jedynego możliwego rozwiązania tunelowania IPv6. Jest to
jednak metoda używana często przy tunelowaniu Linuksów i Cisco używających IPv6,
a z doświadczenia wynika, że w ten właśnie sposób realizuje to większość ludzi.
Dziesięć do jednego, że dotyczy to również ciebie ;-).
Trochę o adresach IPv6:
Adresy IPv6 są, w porównaniu do IPv4 bardzo duże: 128 bitów zamiast 32. Daje nam to
czego potrzebujemy: bardzo, bardzo dużo adresów IP:
340,282,266,920,938,463,463,374,607,431,768,211,465 jeśli chodzi o ścisłość.
Oprócz tego, IPv6 (lub IPng, co oznacza IP Next Generation) ma zapewnić mniejsze
tablice routingu na ruterach szkieletowych, prostszą konfigurację sprzętu, lepsze
bezpieczeństwo na poziomie IP i lepsze wsparcie dla QoS.
Przykład: 2002:836b:9820:0000:0000:0000:836b:9886
Zapisanie adresu IPv6 może być dosyć kłopotliwe. By życie było prostsze,
stworzono pewne reguły:
Nie używaj wiodących zer. Tak jak w IPv4.
Używaj dwukropków do oddzielania każdych 16 bitów, lub dwóch bajtów.
Jeśli masz dużo kolejnych zer, możesz zapisać je jako :: - ale tylko raz i
tylko dla wielokrotności 16 bitów.
Adres 2002:836b:9820:0000:0000:0000:836b:9886 może być więc zapisany jako
2002:836b:9820::836b:9886, co jest zdecydowanie przyjaźniejsze.
Inny przykład: 3ffe:0000:0000:0000:0000:0020:34A1:F32C może być zapisane
jako 3ffe::20:34A1:F32C, co jest dużo krótsze.
IPv6 ma zastąpić obecnie używany IPv4. Ponieważ jest to relatywnie nowa
technologia, nie ma jeszcze światowej natywnej sieci IPv6. By można było
przenosić się płynnie, wprowadzono 6bone.
Sieci używające IPv6 połączone są pomiędzy sobą przez hermetyzację
protokołu IPv6 w ramki IPv4 i wysyłanie tak spreparowanych pakietów
przez istniejącą infrastrukturę IPv4 z jednej sieci IPv6 do innej.
Miejsce styku obu sieci jest dokładnie miejscem, w którym używamy tuneli.
By móc używać IPv6 musimy mieć kernel, który obsługuje ten protokół.
Jest wiele bardzo dobrych dokumentów jak dojść do takiego stanu. Wszystko
sprowadza się jednak do paru kroków:
Zdobądź którąś z nowszych dystrybucji Linuksa z odpowiednią wersją
biblioteki glibc.
Zdobądź nowe źródła kernela.
Jeśli wszystko jest gotowe, to możesz skompilować nowy kernel z obsługą IPv6:
Przejdź do /usr/src/linux i napisz:
make menuconfig
Wybierz "Networking Options"
Wybierz "The IPv6 protocol", "IPv6: enable EUI-64 token format" i
"IPv6: disable provider based addresses"
PODPOWIEDŹ: Nie konfiguruj tych opcji jako znajdujących się w modułach.
Bardzo często takie rozwiązanie po prostu nie działa.
Innymi słowy, wkompiluj IPv6 w kernel. Możesz następnie zapisać
swoją konfigurację tak jak zwykle i skompilować kernel.
PODPOWIEDŹ: Zanim zaczniesz to robić, zastanów się nad modyfikacją pliku
Makefile:
EXTRAVERSION = -x ; --> ; EXTRAVERSION = -x-IPv6
Napisano bardzo dużo dobrej dokumentacji dotyczącej kompilowania i instalowania
jądra, ale ten dokument jest o czym innym. Jeśli w tym momencie wpadłeś w jakieś
problemy, poszukaj czegoś na ten temat w innych dokumentach.
Plik /usr/src/linux/README może być dobrym początkiem. Gdy
uda ci się kompilacja i uruchomiłeś ponownie swój komputer z nowym kernelem,
możesz sprawdzić przez '/sbin/ifconfig -a' czy pojawiło się nowe urządzenie
'sit0-device'. SIT oznacza Proste Przejście do Internetu
(ang. Simple Internet Transition). Możesz sobie pogratulować - jesteś o jeden
krok bliżej do IP Nowej Generacji ;-).
Teraz drugi krok. Chcesz połączyć twoj komputer lub być może całą sieć LAN do
innej sieci IPv6. Może to być właśnie "6bone", którą stworzono właśnie w tym celu.
Załóżmy, że masz następującą sieć IPv6: 3ffe:604:6:8::/64 i że
chcesz połączyć się do 6bone lub kolegi. Zauważ notację /64, która
działa dokładnie tak samo jak w zwykłym adresie IP.
Masz adres IPv4 145.100.24.181 a router 6bone ma adres 145.100.1.5.
# ip tunnel add sixbone mode sit remote 145.100.1.5 [local 145.100.24.181 ttl 255]
# ip link set sixbone up
# ip addr add 3FFE:604:6:7::2/126 dev sixbone
# ip route add 3ffe::0/16 dev sixbone
Omówmy to. W pierwszej linii tworzymy tunel nazwany sixbone.
Później ustawiamy go w tryb sit, mówimy gdzie ma być skierowany (remote)
i gdzie się zaczynać (local). TTL ustawione jest na wartość maksymalną - 255.
Następnie podnosimy nasze urządzenie (up). Potem dodajemy adres naszej sieci i
ustawiamy trasę dla 3ffe::/15 (które stanowi obecnie całe 6bone) przez tunel.
Jeśli ta konkretna maszyna na której wpisujesz te komendy jest twoją
bramką do IPv6, rozważ dodanie następujących linii:
# echo 1 >/proc/sys/net/ipv6/conf/all/forwarding
# /usr/local/sbin/radvd
Drugi program, radvd, jest podobnie jak zebra demonem rozgłaszającym routera i
zapewnia wsparcie dla opcji autokonfiguracyjnych IPv6. Poszukaj go ulubioną
wyszukiwarką, jeśli chciałbyś go używać. Możesz sprawdzić rzeczy takie jak np.:
# /sbin/ip -f inet6 addr
Jeśli radvd pracuje na bramce IPv6 a twój Linux jest w lokalnym LANie,
będziesz mógł cieszyć się autokonfiguracją IPv6:
# /sbin/ip -f inet6 addr
1: lo: <LOOPBACK,UP> mtu 3924 qdisc noqueue inet6 ::1/128 scope host
3: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 100
inet6 3ffe:604:6:8:5054:4cff:fe01:e3d6/64 scope global dynamic
valid_lft forever preferred_lft 604646sec inet6 fe80::5054:4cff:fe01:e3d6/10
scope link
Powinieneś teraz skonfigurować swojego binda na obsługę adresów IPv6.
Rekordowi typu A w IPv4 odpowiada w IPv6 AAAA. Natomiast wpisowi
in-addr.arpa odpowiada teraz ip6.int. Jest bardzo dużo informacji dostępnej
na ten temat.
Dostępne są stale rosnące ilości aplikacji obsługujących IPv6, łącznie
z bezpieczną powłoką (ssh), telnetem, inetd, przeglądarką Mozilla,
serwerem WWW Apache i innymi. Ale ponownie - zakres aplikacji wspierających
IPv6 wykracza daleko poza ten dokument ;-).
W konfiguracji routera Cisco należy wpisać coś takiego:
!
interface Tunnel1
description tunel IPv6
no ip address
no ip directed-broadcast
ipv6 address 3FFE:604:6:7::1/126
tunnel source Serial0
tunnel destination 145.100.24.181
tunnel mode ipv6ip
!
ipv6 route 3FFE:604:6:8::/64 Tunnel1
Jeśli nie masz do swojej dyspozycji Cisco, popytaj innych użytkowników
IPv6 w Internecie. Być może będą chcieli skonfigurować swoje Cisco
z twoim tunelem, zwykle w ramach przyjaznego interfejsu WWW. Szukaj
ciągu znaków "ipv6 tunnel broker" w ulubionej wyszukiwarce.
IPsec: bezpieczne IP przez Internet
W Linuksie dostępne są dwie implementacje IPsec. Dla kerneli 2.2 i 2.4 istnieje
FreeS/WAN, który był pierwszym kompletnym rozwiązaniem. Oficjalna strona
znajduje się pod tym adresem,
natomiast nieoficjalna pod tym.
FreeS/WAN tradycyjnie nie był włączony do źródeł jądra z paru powodów.
Zwykle wymienia się 'polityczne' - związane z Amerykanami pracującymi nad
kodem odpowiedzialnym za szyfrowanie. Co więcej, niezbyt dobrze integrował
się z jądrem i w związku z tym nie był dobrym kandydatem.
Dodatkowo wiele
niezależnych
osób
wyrażało się niezbyt pochlebnie o jakości kodu. Do konfiguracja FreeS/WAN dostępne
jest natomiast
dużo
rozmaitej dokumentacji.
Od wersji 2.5.47 dostępna jest natywna implementacja IPsec. Została napisana przez
Aleksieja Kuzniecowa i Dave Millera, a jej konstrukcja inspirowana była pracą grupy
USAGI IPv6. Jednocześnie w tej wersji dołączono kod Jamesa Morrisa - CryptoAPI.
Ten dokument opisuje tylko wersje 2.5+ IPsec. Dla jąder serii 2.4 zalecany jest
obecnie FreeS/WAN, ale zwróć uwagę że jego konfiguracja różni się od natywnej
implementacji IPsec. Dostępne są obecnie
łatki
umożliwiające współpracę kodu FreeS/WAN z natywną implementacją IPsec.
Od wersji 2.5.49, implementacja IPsec działa bez żadnych dodatkowych łatek.
Narzędzia działające w przestrzeni użytkownika dostępne są
tutaj - i są
aktywnie rozwijane.
Podczas kompilacji jądra, upewnij się że włączyłeś 'PF_KEY', 'AH', 'ESP' oraz
wszystko w CryptoAPI! Natomiast cel 'TCP_MSS' z netfilter aktualnie nie działa i
powinieneś go wyłączyć.
Autor tego rozdziału jest zupełnym początkującym jeśli chodzi o IPsec. Jeśli
znalazłeś błędy, proszę napisz do Berta Huberta ahu%ds9a.nl.
Na początek, pokażemy jak ręcznie skonfigurować bezpieczny kanał komunikacyjny
pomiędzy dwoma hostami. Większość tego procesu można zautomatyzować, ale zrobimy
to ręcznie by zapoznać się z tym, co dzieje się 'pod maską'.
Możesz pominąć tą sekcję, jeśli interesujesz się tylko automatyczną wymianą
kluczy, ale weź pod uwagę że lepiej wiedzieć o tym procesie coś więcej.
Wprowadzenie do Ręcznej Wymiany Kluczy
IPsec to skomplikowany zestaw protokołów. Bardzo dużo materiału dostępnego jest
online, natomiast to HOWTO skupi się tylko na uruchomieniu podstawowej
funkcjonalności.
Wiele konfiguracji używających iptables odrzuca pakiety IPsec! By je
przepuszczać dodaj: 'iptables -A xxx -p 50 -j ACCEPT' and 'iptables -A xxx -p 51 -j ACCEPT'
IPsec oferuje bezpieczną wersję IP. Bezpieczeństwo rozumiane jest tutaj
jako dwie różne rzeczy: szyfrowanie i uwierzytelnianie. Naiwna wersja
bezpieczeństwa oferuje tylko szyfrowanie, ale bardzo łatwo można pokazać,
że to nie wystarczy - możesz komunikować się w sposób szyfrowany, ale
nie masz gwarancji że to co oferujesz drugiej stronie jest tym,
czym spodziewasz się że będzie.
IPsec wspiera 'Encapsulated Security Payload' (ESP) który służy do
szyfrowania oraz 'Authentication Header' (AH) dla uwierzytelniania
zdalnego partnera. Możesz użyć obu z nich, lub zdecydować się na
zastosowanie tylko jednego.
Zarówno ESP i AH opierają się o tzw. związki bezpieczeństwa
(ang. security association
, SA). SA składają się
ze wskazania źródła ruchu, miejsca docelowego dla ruchu oraz
instrukcji jak przesyłany ruch potraktować. Przykładowa SA
uwierzytelniająca pokazana jest poniżej:
add 10.0.0.11 10.0.0.216 ah 15700 -A hmac-md5 "1234567890123456";
Wpis ten oznacza 'ruch z 10.0.0.11 do 10.0.0.216 wymagający
zastosowania AH, należy podpisać używając algorytmu HMAC-MD5 z kluczem
1234567890123456'. Instrukcja ta posiada przydzielony indeks
parametrów bezpieczeństwa (ang. Security Parameter Index
,
SPI) 15700. Interesującą cechą SA jest to, że są symetryczne. Obie
strony muszą posiadać dokładnie te same SA - nie są one automatycznie
kopiowane do partnera. Co więcej, pojedyńczy wpis SA opisuje ruch
tylko w jednym kierunku. Aby obsłużyć ruch powrotny, należy stworzyć
dwie SA.
Przykładowe SA ESP:
add 10.0.0.11 10.0.0.216 esp 15701 -E 3des-cbc "123456789012123456789012";
Ten z kolei wpis oznacza 'ruch z 10.0.0.11 do 10.0.0.216 wymagający
szyfrowania należy szyfrować algorytmem 3DES-CBC z kluczem
123456789012123456789012'. SPI dla wpisu to 15701.
Udało nam się stworzyć SA opisujące różne możliwe instrukcje, ale
nie wskazaliśmy w żadnym momencie w którym momencie należy tych
instrukcji użyć. Tak naprawdę, można stworzyć wiele dokładnie
takich samych SA różniących się tylko numerami SPI. Aby wykonać
faktycznie szyfrowanie, należy dodatkowo zdefiniować regułę. Może
ona na przykład mówić 'użyj IPsec jeśli jest dostępny' lub
'odrzucaj ruch chyba że otrzymamy IPsec'.
Typowa, przykładowa Reguła Bezpieczeństwa (ang. Security
Policy
, SP) wyglądać może tak:
spdadd 10.0.0.216 10.0.0.11 any -P out ipsec
esp/transport//require
ah/transport//require;
Jeśli została wpisana na hoście 10.0.0.216, oznacza dokładnie tyle,
że cały ruch wychodzący do 10.0.0.11 ma być szyfrowany i opakowany
w nagłówek AH. Zauważ że nie wskazaliśmy które SA mają być zastosowane,
ma to sprawdzić kernel.
Innymi słowy, SP opisuje CO chcemy uzyskać, a SA JAK chcemy to
zrobić.
Wychodzące pakiety otrzymują etykiety z SA SPI, tak by host
otrzymujący ruch mógł sprawdzić swoje wpisy i wykonać odpowiednie
operacje odszyfrowując ruch.
Poniżej bardzo prosty przykład konfiguracji, dla połączenia 10.0.0.216
z 10.0.0.11 z użyciem uwierzytelniania i szyfrowania. Weź pod uwagę
że ruch z powrotem odbywać się będzie bez szyfrowania i taka
konfiguracja nie powinna być stosowana.
Na hoście 10.0.0.216:
#!/sbin/setkey -f
add 10.0.0.216 10.0.0.11 ah 24500 -A hmac-md5 "1234567890123456";
add 10.0.0.216 10.0.0.11 esp 24501 -E 3des-cbc "123456789012123456789012";
spdadd 10.0.0.216 10.0.0.11 any -P out ipsec
esp/transport//require
ah/transport//require;
Na hoście 10.0.0.11 te same SA, bez SP:
#!/sbin/setkey -f
add 10.0.0.216 10.0.0.11 ah 24500 -A hmac-md5 "1234567890123456";
add 10.0.0.216 10.0.0.11 esp 24501 -E 3des-cbc "123456789012123456789012";
W powyższej konfiguracji (pliki można wykonać jeśli 'setkey' znajduje
się w katalogu /sbin) polecenie 'ping 10.0.0.11' wykonane na hoście
10.0.0.216 wyglądać powinno tak, jeśli podsłuchamy je programem
tcpdump:
22:37:52 10.0.0.216 > 10.0.0.11: AH(spi=0x00005fb4,seq=0xa): ESP(spi=0x00005fb5,seq=0xa) (DF)
22:37:52 10.0.0.11 > 10.0.0.216: icmp: echo reply
Zauważ, że odpowiedź na ping z 10.0.0.11 jest faktycznie widoczna
nieszyfrowana. Natomiast sam ping widziany jest przez tcpdump jako
transmisja IPsec (używająca AH i ESP).
Należy zwrócić uwagę na parę rzeczy. Konfiguracja powyżej pokazywana
jest w wielu przykładach dotyczących IPsec i jest bardzo niebezpieczna.
Problem polega na tym, że 10.0.0.11 nie szyfruje ruchu powrotnego
oraz na tym, że 10.0.0.11 nie odrzuca ruchu niezaszyfrowanego
lub nieuwierzytelnionego.
Dowolny użytkownik sieci może wysłać sfałszowany ruch do 10.0.0.11
a ten go przyjmie. Aby zapobiec temu problemowi, potrzebujemy
SP na hoście 10.0.0.11 która wygląda tak:
#!/sbin/setkey -f
spdadd 10.0.0.216 10.0.0.11 any -P IN ipsec
esp/transport//require
ah/transport//require;
To polecenie powoduje, że cały ruch z 10.0.0.216 musi posiadać
prawidłowe ESP i AH.
Pierwszy problem (nieszyfrowanie ruchu powrotnego) rozwiążemy
uzupełniając konfigurację. Na 10.0.0.216:
#!/sbin/setkey -f
flush;
spdflush;
# AH
add 10.0.0.11 10.0.0.216 ah 15700 -A hmac-md5 "1234567890123456";
add 10.0.0.216 10.0.0.11 ah 24500 -A hmac-md5 "1234567890123456";
# ESP
add 10.0.0.11 10.0.0.216 esp 15701 -E 3des-cbc "123456789012123456789012";
add 10.0.0.216 10.0.0.11 esp 24501 -E 3des-cbc "123456789012123456789012";
spdadd 10.0.0.216 10.0.0.11 any -P out ipsec
esp/transport//require
ah/transport//require;
spdadd 10.0.0.11 10.0.0.216 any -P in ipsec
esp/transport//require
ah/transport//require;
I na 10.0.0.11:
#!/sbin/setkey -f
flush;
spdflush;
# AH
add 10.0.0.11 10.0.0.216 ah 15700 -A hmac-md5 "1234567890123456";
add 10.0.0.216 10.0.0.11 ah 24500 -A hmac-md5 "1234567890123456";
# ESP
add 10.0.0.11 10.0.0.216 esp 15701 -E 3des-cbc "123456789012123456789012";
add 10.0.0.216 10.0.0.11 esp 24501 -E 3des-cbc "123456789012123456789012";
spdadd 10.0.0.11 10.0.0.216 any -P out ipsec
esp/transport//require
ah/transport//require;
spdadd 10.0.0.216 10.0.0.11 any -P in ipsec
esp/transport//require
ah/transport//require;
Zauważ, że użyliśmy w przykładzie identycznych kluczy do obu
kierunków ruchu - nie jest to oczywiście wymagane.
Aby obejrzeć konfigurację, którą przed chwilą stworzyłeś
wykonaj polecenie setkey -D, która pokazuje
SA lub polecenie setkey -DP pokazująca
skonfigurowane reguły.
Automatyczna wymiana kluczy
W poprzedniej sekcji, szyfrowanie odbywało się za pomocą prostych
kluczy. Innymi słowy, aby pozostać bezpiecznym, musiałbyś
wymieniać konfigurację przez zestawiony uprzednio bezpieczny
kanał. Jeśli musielibyśmy skonfigurować zdalnego hosta przez telnet,
dowolny użytkownik mógłby podsłuchać klucze i konfiguracja
nie byłaby bezpieczna.
Co więcej, ponieważ klucz jest współdzielony - nie jest już wcale tajny.
Zdalny partner nie jest w stanie zrobić wiele znając go, ale mając
wielu partnerów musimy zadbać by z każdym rozmawiać za pomocą różnych
kluczy. Wymaga to dużej ilości kluczy - przy 10 partnerach musimy
znać przynajmniej 50 różnych kluczy.
Poza problemami związanymi z kluczem symetrycznym, mamy jeszcze
problem zmiany klucza. Jeśli osoba postronna podsłucha odpowiednio
dużo ruchu, może być w stanie odzyskać klucz i odczytać nasze
transmisje. Zapobiega się temu zmieniając regularnie klucz, ale
należy to oczywiście zautomatyzować.
Inny problem związany z manualnym zarządzaniem kluczami jest
dokładne ustalenie z partnerem parametrów połączenia - algorytmów
szyfrowania i/lub uwierzytelniania. Wygodniej jest móc określić
regułę w postaci 'Możemy używać 3DESa i Blowfish z kluczami o
przynajmniej takiej a takiej długości'.
Aby rozwiązać te problemy, IPsec wprowadził standard wymiany
kluczy w Internecie (ang. Internet Key Exchange
, IKE).
Umożliwia on automatyczną wymianę losowo generowanych kluczy,
wykorzystującą technologię szyfrowania asymetrycznego zgodnie
z wynegocjowanymi z partnerem parametrami.
Implementacja IPsec Linuksa 2.5 działa z demonem 'racoon' pochodzącym
z projektu KAME. Od 9 listopada wersja oparta o racoon znajduje
się w dystrybucji iptools Aleksieja, aczkolwiek żeby ją skompilować
będziesz musiał usunąć #include <net/route.h> w dwóch plikach.
Możesz również ściągnąć
wersję prekompilowaną.
IKE wymaga dostępu z Internetu do portu 500/udp, upewnij się
że iptables nie blokują go.
Teoria
Tak jak wyjaśniałem wcześniej, automatyczna zmiana kluczy może wykonać
za nas masę pracy. Dokładniej rzecz biorąc, tworzy SA "w locie".
Nie powoduje jednak pojawienia się reguł bezpieczeństwa i w zasadzie
tak powinno być.
Żeby skorzystać z IKE, skonfiguruj regułę ale nie wskazuj SA.
Kernel w momencie odkrycia reguły IPsec bez SA powiadomi demon IKE,
który z kolei postara się odpowiednie SA wynegocjować.
Powtórzmy to jeszcze raz: SP opisuje CO chcemy uzyskać, a SA JAK
chcemy to zrobić. Zastosowanie demona IKE automatycznie wymieniającego
klucze umożliwia nam ograniczenie się tylko do wskazania, CO
chcemy uzyskać.
Przykład
Racoon w wersji KAME dostarczany jest z całą masą opcji, z których
większość ma bardzo dobre ustawienia domyślne więc nie będziemy ich
modyfikować. Tak jak opisałem powyżej, musimy zdefiniować reguły
bezpieczeństwa (SP) a nie SA. Pozostawimy ich negocjację demonowi
IKE.
W tym przykładzie, 10.0.0.11 i 10.0.0.216 ponownie chcą zestawić
kanał komunikacyjny, ale tym razem z pomocą demona racoon. Dla
zachowania przejrzystości konfiguracji użyjemy współdzielonych
kluczy (ang. pre-shared keys
). Zastosowanie do
uwierzytelnienia partnerów certyfikatów X.509 opisano w osobnym
rozdziale, zajrzyj do .
Użyjemy prawie domyślnej konfiguracji, identycznej na obu hostach:
path pre_shared_key "/usr/local/etc/racoon/psk.txt";
remote anonymous
{
exchange_mode aggressive,main;
doi ipsec_doi;
situation identity_only;
my_identifier address;
lifetime time 2 min; # sec,min,hour
initial_contact on;
proposal_check obey; # obey, strict or claim
proposal {
encryption_algorithm 3des;
hash_algorithm sha1;
authentication_method pre_shared_key;
dh_group 2 ;
}
}
sainfo anonymous
{
pfs_group 1;
lifetime time 2 min;
encryption_algorithm 3des ;
authentication_algorithm hmac_sha1;
compression_algorithm deflate ;
}
Wiele ustawień - myślę że można usunąć więcej by zbliżyć się
do domyślnej konfiguracji. Parę rzeczy wartych zwrócenia uwagi -
stworzyliśmy dwie sekcje anonimowe pasujące dla wszystkich partnerów
zdalnych co ułatwia znakomicie konfigurację. Nie musimy definiować
wszystkiego per-host, chyba że bardzo chcemy.
Co więcej, konfiguracja została wykonana w ten sposób, że
identyfikowani jesteśmy na podstawie adresu IP
('my_identifier address') i deklarujemy, że jesteśmy w stanie używać
algorytmów 3DES, SHA-1 oraz, że będziemy używać współdzielonego
klucza zlokalizowanego w pliku psk.txt.
W rzeczonym pliku psk.txt wpisujemy po jednej
linicje, która różnić się będzie na obu hostach. Na 10.0.0.11
będzie to:
10.0.0.216 password2
a na 10.0.0.216:
10.0.0.11 password2
Upewnij się że właścicielem tych plików jest root i uprawnienia
do nich ustawiono na 0600 - w innym przypadku racoon nie będzie
chciał ich użyć. Jeśli jeszcze tego nie zauważyłeś, zwróć uwagę
że te dwa pliki są swoimi lustrzanymi odbiciami.
Teraz jesteśmy w stanie skonfigurować żądaną SP, która jest
bardzo prosta. Na hoście 10.0.0.216:
#!/sbin/setkey -f
flush;
spdflush;
spdadd 10.0.0.216 10.0.0.11 any -P out ipsec
esp/transport//require;
spdadd 10.0.0.11 10.0.0.216 any -P in ipsec
esp/transport//require;
I na 10.0.0.11:
#!/sbin/setkey -f
flush;
spdflush;
spdadd 10.0.0.11 10.0.0.216 any -P out ipsec
esp/transport//require;
spdadd 10.0.0.216 10.0.0.11 any -P in ipsec
esp/transport//require;
Tu również widać, że SP są swoimi lustrzanymi odbiciami.
W tym momencie jesteśmy gotowi do uruchomienia racoon! Jeśli
już działa, zainicjowanie ruchu z 10.0.0.11 do 10.0.0.216 lub
odwrotnie (np. za pomocą telnetu) spowoduje rozpoczęcie przez
racoon negocjacji:
12:18:44: INFO: isakmp.c:1689:isakmp_post_acquire(): IPsec-SA
request for 10.0.0.11 queued due to no phase1 found.
12:18:44: INFO: isakmp.c:794:isakmp_ph1begin_i(): initiate new
phase 1 negotiation: 10.0.0.216[500]<=>10.0.0.11[500]
12:18:44: INFO: isakmp.c:799:isakmp_ph1begin_i(): begin Aggressive mode.
12:18:44: INFO: vendorid.c:128:check_vendorid(): received Vendor ID:
KAME/racoon
12:18:44: NOTIFY: oakley.c:2037:oakley_skeyid(): couldn't find
the proper pskey, try to get one by the peer's address.
12:18:44: INFO: isakmp.c:2417:log_ph1established(): ISAKMP-SA
established 10.0.0.216[500]-10.0.0.11[500] spi:044d25dede78a4d1:ff01e5b4804f0680
12:18:45: INFO: isakmp.c:938:isakmp_ph2begin_i(): initiate new phase 2
negotiation: 10.0.0.216[0]<=>10.0.0.11[0]
12:18:45: INFO: pfkey.c:1106:pk_recvupdate(): IPsec-SA established:
ESP/Transport 10.0.0.11->10.0.0.216 spi=44556347(0x2a7e03b)
12:18:45: INFO: pfkey.c:1318:pk_recvadd(): IPsec-SA established:
ESP/Transport 10.0.0.216->10.0.0.11 spi=15863890(0xf21052)
Jeśli w tym momencie wykonamy polecenie `setkey -D', które pokazuje
nam nasze SA, powinny wyglądać mniej więcej tak:
10.0.0.216 10.0.0.11
esp mode=transport spi=224162611(0x0d5c7333) reqid=0(0x00000000)
E: 3des-cbc 5d421c1b d33b2a9f 4e9055e3 857db9fc 211d9c95 ebaead04
A: hmac-sha1 c5537d66 f3c5d869 bd736ae2 08d22133 27f7aa99
seq=0x00000000 replay=4 flags=0x00000000 state=mature
created: Nov 11 12:28:45 2002 current: Nov 11 12:29:16 2002
diff: 31(s) hard: 600(s) soft: 480(s)
last: Nov 11 12:29:12 2002 hard: 0(s) soft: 0(s)
current: 304(bytes) hard: 0(bytes) soft: 0(bytes)
allocated: 3 hard: 0 soft: 0
sadb_seq=1 pid=17112 refcnt=0
10.0.0.11 10.0.0.216
esp mode=transport spi=165123736(0x09d79698) reqid=0(0x00000000)
E: 3des-cbc d7af8466 acd4f14c 872c5443 ec45a719 d4b3fde1 8d239d6a
A: hmac-sha1 41ccc388 4568ac49 19e4e024 628e240c 141ffe2f
seq=0x00000000 replay=4 flags=0x00000000 state=mature
created: Nov 11 12:28:45 2002 current: Nov 11 12:29:16 2002
diff: 31(s) hard: 600(s) soft: 480(s)
last: hard: 0(s) soft: 0(s)
current: 231(bytes) hard: 0(bytes) soft: 0(bytes)
allocated: 2 hard: 0 soft: 0
sadb_seq=0 pid=17112 refcnt=0
Powinny być również widoczne reguły bezpieczeństwa, które
skonfigurowaliśmy sami:
10.0.0.11[any] 10.0.0.216[any] tcp
in ipsec
esp/transport//require
created:Nov 11 12:28:28 2002 lastused:Nov 11 12:29:12 2002
lifetime:0(s) validtime:0(s)
spid=3616 seq=5 pid=17134
refcnt=3
10.0.0.216[any] 10.0.0.11[any] tcp
out ipsec
esp/transport//require
created:Nov 11 12:28:28 2002 lastused:Nov 11 12:28:44 2002
lifetime:0(s) validtime:0(s)
spid=3609 seq=4 pid=17134
refcnt=3
Problemy i znane usterki
Jeśli coś poszło nie tak, sprawdź czy wszystkie pliki konfiguracyjne
należą do roota i tylko przez niego mogą zostać przeczytane.
Aby uruchomić demon racoon na pierwszym planie użyj opcji `-F'.
By zmusić go do przeczytania innego pliku konfiguracyjnego niż
domyślnego, użyj opcji `-f'. Aby obejrzeć dokładne informacje o
wszystkim co demon robi, dodaj do pliku racoon.conf
linijkę zawierającą `log debug;'.
Automatyczna wymiana kluczy przy użyciu certyfikatów X.509
Wspominałem wcześniej, że zastosowanie współdzielonych kluczy nie
jest najwygodniejsze, ponieważ nie są zbyt łatwe do bezpiecznego
współdzielenia - a gdy już są współdzielone, przestają być
sekretem. Na szczęście w tym momencie technologie wykorzystujące
kryptografię asymetryczną wchodzą do gry i rozwiązują problem.
Jeśli każdy z partnerów IPsec stworzy klucz prywatny i publiczny,
możemy zestawić bezpieczny kanał komunikacyjny pozwalając
obu stronom opublikować swoje klucze publiczne i odpowiednio
skonfigurować reguły bezpieczeństwa.
Stworzenie klucza jest relatywnie łatwe, aczkolwiek wymaga trochę
pracy. Poniższy opis opiera się o zastosowanie do tego celu
narzędzia openssl.
Tworzenie certyfikatu X.509 dla twojego hosta
OpenSSL dysponuje bogatą infrastrukturą związaną z operacjami
na kluczach, podpisanych lub niepodpisanych przez autorytety/instytucje
certyfikujące (ang. certificate authorities
). Na
razie zajmiemy się domyślnie generowanymi kluczami bez użycia
instytucji certyfikującej.
Najpierw stworzymy `prośbę o certyfikat' dla naszego hosta, nazwanego
`laptop':
$ openssl req -new -nodes -newkey rsa:1024 -sha1 -keyform PEM -keyout \
laptop.private -outform PEM -out request.pem
Polecenie spowoduje konieczność odpowiedzi na parę pytań:
Country Name (2 letter code) [AU]:NL
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:Delft
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Linux Advanced
Routing & Traffic Control
Organizational Unit Name (eg, section) []:laptop
Common Name (eg, YOUR name) []:bert hubert
Email Address []:ahu@ds9a.nl
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Od ciebie zależy ile z informacji podasz i w jaki sposób je podasz.
Może to zależeć od twoich oczekiwań związanych z bezpieczeństwem.
W powyższym przykładzie podaliśmy większość informacji.
Teraz sami `podpiszemy' swoją prośbę:
$ openssl x509 -req -in request.pem -signkey laptop.private -out \
laptop.public
Signature ok
subject=/C=NL/L=Delft/O=Linux Advanced Routing & Traffic \
Control/OU=laptop/CN=bert hubert/Email=ahu@ds9a.nl
Getting Private key
Plik request.pem można teraz usunąć.
Powtórz tą operację dla wszystkich hostów które potrzebować będą
klucza. Możesz oczywiście dystrybuować plik .public,
ale plik .private trzymaj z daleka od wszystkich
w tajemnicy.
Konfiguracja i uruchomienie
Po wygenerowaniu kluczy należy poinformować racoon by ich użył.
Wracamy w tym momencie do naszej poprzedniej konfiguracji pomiędzy
dwoma hostami - 10.0.0.11 ('upstairs') i 10.0.0.216 ('laptop').
Do pliku racoon.conf na 10.0.0.11 dodaj:
path certificate "/usr/local/etc/racoon/certs";
remote 10.0.0.216
{
exchange_mode aggressive,main;
my_identifier asn1dn;
peers_identifier asn1dn;
certificate_type x509 "upstairs.public" "upstairs.private";
peers_certfile "laptop.public";
proposal {
encryption_algorithm 3des;
hash_algorithm sha1;
authentication_method rsasig;
dh_group 2 ;
}
}
Taka konfiguracja spowoduje, że racoon poszuka kluczy w katalogu
/usr/local/etc/racoon/certs/. Konfiguracja
zawiera również elementy specyficzne dla zdalnego hosta 10.0.0.216.
Linijka asn1dn informuje racoon, że identyfikator obu
stron należy pobrać z kluczy publicznych. Będzie to ciąg znaków
`subject=/C=NL/L=Delft/O=Linux Advanced Routing & Traffic
Control/OU=laptop/CN=bert hubert/Email=ahu@ds9a.nl'.
Linijka certificate_type wskazuje lokalny klucz
prywatny i publiczny. Natomiast linijka peers_certfile
wskazuje demonowi racoon plik z kluczem publicznym zdalnego partnera -
i jest to plik laptop.public.
Sekcja proposal pozostaje w niezmienionej formie
w stosunku do tego co widzieliśmy wcześniej za wyjątkiem opcji
authentication_method którą jest obecnie
rsasig - wskazując, że używamy pary prywatnej/publicznej
RSA do wykonania uwierzytelnienia.
Zmiany w konfiguracji 10.0.0.216 są analogiczne do tych, wykonanych
na 10.0.0.11:
path certificate "/usr/local/etc/racoon/certs";
remote 10.0.0.11
{
exchange_mode aggressive,main;
my_identifier asn1dn;
peers_identifier asn1dn;
certificate_type x509 "laptop.public" "laptop.private";
peers_certfile "upstairs.public";
proposal {
encryption_algorithm 3des;
hash_algorithm sha1;
authentication_method rsasig;
dh_group 2 ;
}
}
Teraz, gdy już dodaliśmy odpowiednie opcje na obu hostach, musimy
tylko umieścić klucze we właściwych miejscach. Maszyna
`upstairs' powinna mieć pliki upstairs.private,
upstairs.public, i
laptop.public w katalogu
/usr/local/etc/racoon/certs. Upewnij się że
właścicielem tego katalogu jest root a sam katalog ma prawa
dostępu ustawione na 0700 - w przeciwnym wypadku racoon odmówi
ich odczytania.
Maszyna `laptop' powinna mieć pliki laptop.private,
laptop.public i upstairs.public
w katalogu /usr/local/etc/racoon/certs. Innymi
słowy, każdy host potrzebuje dostęp do swojego klucza prywatnego,
publicznego oraz do klucza publicznego hosta z którym chce nawiązać
łączność.
Sprawdź, czy reguły bezpieczeństwa zostały prawidłowo zdefiniowane
(wykonaj polecenia spdadd z
). Teraz uruchom
racoon i wszystko powinno działać.
Jak bezpiecznie budować tunele
Aby ustanowić bezpieczną trasę komunikacji ze zdalnym partnerem,
musimy wymienić klucze publiczne. O ile same klucze publiczne nie
muszą być sekretem, ważne jest by zachować je w niezmienionej
formie. Innymi słowy, trzeba mieć pewność że nie dojdzie do
ataku typu `człowiek-pośrodku' (ang. man in the middle
).
Aby to ułatwić, w OpenSSL zaimplementowano polecenie
digest:
$ openssl dgst upstairs.public
MD5(upstairs.public)= 78a3bddafb4d681c1ca8ed4d23da4ff1
Teraz wystarczy zweryfikować że nasz zdalny partner ma taką
samą sumę kontrolną dla tego pliku. Można to zrobić po prostu
spotykając się, lub przez telefon - generalnie chodzi o to, by
potwierdzić to inną drogą komunikacji. Niedopuszczalne jest, by
zdalna strona wysłała swoją sumę kontrolną również np. mailem!
Innym sposobem osiągnięcia tego samego, jest zaufana trzecia
osoba/instytucja (ang. Trusted Third Party
) która
utrzymuje instytucję certyfikującą (ang. Certificate
Authority
, CA). CA podpisze klucz, który w naszym przypadku
sami podpisaliśmy i partner będzie mógł w CA zweryfikować że
otrzymany od nas klucz jest faktycznie tym, który my pierwotnie
zgłosiliśmy do podpisania w CA.
Tunele IPsec
Jak dotąd zajmowaliśmy się połączeniami IPsec w tak zwanym trybie
`transportowym', w którym oba punkty transmisji rozumieją IPsec.
Ponieważ często nie można doprowadzić do takiej sytuacji, można
skonfigurować IPsec tylko na routerach i kazać im zestawić bezpieczny
tunel dla całej komunikacji z podsieci "za" routerami. Jak można się
łatwo domyślić, nazywane jest to właśnie `tunelowaniem' lub po prostu
trybem tunelu.
Konfiguracja jest prościutka. Aby tunelować cały ruch do podsieci
130.161.0.0/16 z 10.0.0.216 przez 10.0.0.11, wydajemy następujące
polecenie na 10.0.0.216:
#!/sbin/setkey -f
flush;
spdflush;
add 10.0.0.216 10.0.0.11 esp 34501
-m tunnel
-E 3des-cbc "123456789012123456789012";
spdadd 10.0.0.0/24 130.161.0.0/16 any -P out ipsec
esp/tunnel/10.0.0.216-10.0.0.11/require;
Zauważ że opcja -m tunnel jest bardzo istotna!
Linijka konfiguruje SA szyfrujące za pomocą ESP pomiędzy dwoma
końcami tuneli - 10.0.0.216 i 10.0.0.11.
Następnie konfigurujemy sam tunel. Polecenie instruuje kernel, by
szyfrował cały ruch z 10.0.0.0/24 do 130.161.0.0/16. Zaszyfrowany
ruch ma być wysyłany do routera 10.0.0.11.
Host 10.0.0.11 również wymaga analogicznej konfiguracji:
#!/sbin/setkey -f
flush;
spdflush;
add 10.0.0.216 10.0.0.11 esp 34501
-m tunnel
-E 3des-cbc "123456789012123456789012";
spdadd 10.0.0.0/24 130.161.0.0/16 any -P in ipsec
esp/tunnel/10.0.0.216-10.0.0.11/require;
Zauważ że wpisy są prawie identyczne, poza zmianą -P out
na -P in. Tak jak w poprzednich przykładach,
skonfigurowaliśmy reguły dla ruchu przechodzącego w jedną stronę.
Poprawną konfigurację szyfrowania ruchu w drugą stronę pozostawiamy
jako ćwiczenie dla czytelnika.
Inną nazwą dla takiej konfiguracji jest `proxy ESP', która może choć
nie musi być jaśniejsza.
Tunel IPsec wymaga włączonego przekazywania pakietów IP
(ang. IP Forwarding
) w kernelu!
Inne oprogramowanie IPsec
Tomasz Walpuski donosi, że napisał łatkę dla isakmpd w OpenBSD,
pozwalającą na połączenia z implementacją IPsec w Linuksie 2.5. Co
więcej, repozytorium CVS isakmpd zawiera obecnie ten kod! Trochę
informacji znajdziecie na
tej stronie.
isakmpd jest trochę inny niż racoon wspominamy powyżej, ale wiele ludzi
lubi go. Można go znaleźć
tutaj.
Więcej o CVS OpenBSD można przeczytać
tutaj. Tomasz
udostępnił również gotowe
archiwum
dla osób niezaznajomionych z CVS lub ideą nakładania łatek.
Współpraca IPsec z innymi systemami
FIXME: Napisać to
Windows
FIXME: Napisać to
Routing multicastowy
FIXME: nie ma autora!
HOWTO poświęcone temu tematowi jest praktycznie starożytne i może być
niedokładne lub mylące.
Zanim zajmiesz się routingiem multicastowym, musisz skonfigurować swój kernel.
Oznacza to zdecydowanie się na konkretny typ tego routingu. Istnieją cztery
główne "wspólne" rodzaje - DVMRP (multicastowa wersja unicastowego
protokołu RIP), MOSPF (to samo dla OSPF), PIM-SM
("Protocol Independent Multicasting - Sparse Mode", który zakłada że
użytkownicy są mocno rozproszeni) i PIM-DM (to samo, ale w trybie zagęszczonym,
zakładającym że grupy użytkowników będą blisko siebie).
Przy konfiguracji jądra Linuksa zauważysz zapewne, że nie ma tych opcji.
Dzieje się tak, ponieważ sam protokół obsługiwany jest przez aplikację
routującą, np. Zebra, mrouted czy pimd. Z drugiej strony musisz wiedzieć,
którego protokołu będziesz używać by wybrać w konfiguracji kernela odpowiednie
opcje.
Dla całego routingu multicastowego, będziesz zdecydowanie musiał zaznaczyć
opcję `multicasting' i `multicast routing'. Dla DVMRP i MOSPF to wystarczy.
Jeśli będziesz używał PIM, musisz również włączyć PIMv1 lub PIMv2 w zależności
od tego, której wersji używa sieć do której będziesz się podłączał.
Gdy skonfigurujesz już kernel i skompilujesz go, zauważysz, że lista
obsługiwanych protokołów IP wyświetlana podczas startu zawiera również IGMP.
Jest to właśnie protokół do zarządzania grupami multicastowymi. W momencie
pisania tego tekstu, Linuks wspiera wersję 1 i 2, mimo że wersja 3 jest
udokumentowana i istnieje. Nie ma to jednak dużego znaczenia, ponieważ IGMPv3
jest nowe i nowa funkcjonalność nie jest aż tak niezbędna. Ponieważ IGMP
zajmuje się grupami, tylko funkcje obsługiwane przez wszystkie implementacje
w grupie będą używane. W większości przypadków będzie to funkcjonalność IGMPv2,
choć można czasami spotkać gdzieniegdzie również IGMPv1.
Jak na razie szło nieźle. Włączyliśmy multicasting. Teraz poinstruujemy kernel
Linuksa by coś z tym zrobił tak, byśmy mogli zacząć routowanie. Oznacza to
dodanie wirtualnej sieci multicastowej do tabeli rutownania:
ip route add 224.0.0.0/4 dev eth0
(zakładając oczywiście, że zamierzasz obsługiwać ruch multicastowy przez
interfejs `eth0'! Zamień go w poleceniu na twoje urządzenie)
Teraz poinstruujemy Linuksa, by przekazywał pakiety...
echo 1 > /proc/sys/net/ipv4/ip_forward
W tym momencie możesz zastanawiać się czy to w ogóle do czegoś będzie służyło.
By przetestować połączenie, pingnijmy domyślną grupę, 224.0.0.1, by sprawdzić
czy ktoś odpowie. Wszystkie komputery w twojej sieci LAN z włączoną obsługą
multicastów powinny odpowiedzieć - i nic innego. Zauważysz,
że żadna maszyna która odpowiedziała, nie miała adresu 224.0.0.1.
Co za niespodzianka! :) Jest to po prostu adres grupowy (rodzaj
rozgłoszenia tylko dla prenumeratorów) i wszyscy członkowie grupy
odpowiadają swoimi adresami.
ping -c 2 224.0.0.1
W tym momencie jesteś gotowy do prowadzenia routingu multicastowego. Zakładając,
że masz dwie sieci między którymi możesz to robić.
(Będzie kontynuowane!)
Dyscypliny kolejkowania dla Zarządzania Pasmem
Gdy je odkryłem, naprawdę mnie to rozwaliło. Linuks 2.2/2.4
posiada wszystko potrzebne do zarządzania pasmem i to z funkcjonalnością
porównywalną do dedykowanych systemów zarządzania pasmem z górnej półki.
Linuks idzie nawet dalej, wykraczając poza to co dają sieci Frame Relay i ATM.
By zapobiec nieporozumieniom, tc używa następujących
reguł do specyfikacji pasma:
mbps = 1024 kbps = 1024 * 1024 bps => bajtów/sekundę
mbit = 1024 kbit => kilo bitów/sekundę.
mb = 1024 kb = 1024 * 1024 b => bajtów
mbit = 1024 kbit => kilo bitów.
Wewnętrznie, liczby przechowywane są w bps i b.
Ale gdy tc drukuje wartości, używa następujących wartości:
1Mbit = 1024 Kbit = 1024 * 1024 bps => bajtów/sekundę
Kolejki i Dyscypliny Kolejkowania wyjaśnione
Dzięki kolejkowaniu, określamy które dane są WYSYŁANE.
Ważne jest, byś zrozumiał że możemy jedynie kontrolować w ten sposób dane,
które wysyłamy.
Z uwagi na taką a nie inną budowę Internetu, nie mamy bezpośredniej kontroli
nad tym, co ludzie wysyłają do nas. To trochę jak z twoją fizyczną skrzynką
pocztową w domu. Nie ma sposobu by zmusić świat, aby wysyłał ci tylko określoną
liczbę poczty bez skontaktowania najpierw ze wszystkimi ludźmi.
Internet na szczęście oparty jest głównie o TCP/IP, które ma pewne cechy mogące
nam pomóc. TCP/IP nie zna przepustowości sieci pomiędzy dwoma komputerami, więc
zaczyna od wysyłania danych coraz szybciej ( wolny start
) i
kiedy zaczyna gubić pakiety ponieważ nie ma już dla nich miejsca, zwalnia.
Tak naprawdę jest to trochę bardziej skomplikowane, ale więcej napiszemy
później.
Wracając do naszej analogii z fizyczną skrzynką pocztową - to tak jakbyś
przestał czytać np. połowę poczty w nadziei, że ludzie których poczty nie
czytasz, przestaną w końcu do ciebie pisać. Jedyna różnica to fakt, że działa
to dla Internetu :-)
Jeśli masz router i chciałbyś zapobiec sytuacji, w której określone komputery
ściągają dane za szybko, musisz wprowadzić ograniczenia na
wewnętrznym interfejsie routera - tym, który wysyła dane
do twoich komputerów.
Musisz być również pewien, że kontrolujesz połączenie w najwęższym miejscu.
Jeśli masz 100Mbitową kartę sieciową a router ma łącze o przepustowości 256kbitów,
musisz upewnić się że nie wysyłasz więcej danych niż router jest w stanie
obsłużyć. Jeśli o to nie zadbasz, to router będzie kontrolował połączenie i
ograniczał pasmo w mniej lub bardziej przydatny dla nas sposób. Musimy
`zawładnąć kolejką' mówiąc po prostu i być najwolniejszym połączeniem w
łańcuchu. Jest to na szczęście bardzo łatwe.
Proste, bezklasowe Dyscypliny Kolejkowania
Tak jak to już powiedziano, dyscyplinami kolejkowania zmieniamy sposób w jaki
dane są wysyłane. Bezklasowe dyscypliny kolejkowania to te, które zajmują się
jedynie odbieraniem danych, przesuwaniem ich transmisji w czasie lub
ewentualnie odrzucaniem.
Mogą zostać użyte do kontroli pasma dla całego interfejsu, bez żadnych
dodatkowych podziałów. Bardzo ważne jest, byś zrozumiał tą część kolejkowania
zanim zajmiemy się zagadnieniem zagnieżdżonych dyscyplin kolejkowania z
klasami ruchu.
Najczęściej używaną dyscypliną jest `pfifo_fast' - i jest domyślna. Jej
popularność wyjaśnia dlaczego zaawansowane opcje są takie wydajne. Nie
zawierają po prostu nic oprócz `kolejnej kolejki'.
Każda z tych kolejek ma swoje mocne i słabe strony. Nie wszystkie są też
dokładnie przetestowane.
pfifo_fast
Kolejka ta, dokładnie tak jak wskazuje na to jej nazwa, to tradycyjne `Pierwszy
Wszedł, Pierwszy Wyjdzie' (ang. First In First Out
, FIFO).
Oznacza to, że żaden pakiet nie będzie specjalnie traktowany (przynajmniej nie
wprost). Kolejka ta ma 3 `pasma' (ang. band
). W każdym z pasm
reguły FIFO działają niezależnie. Jednak jeśli w paśmie 0 są jeszcze pakiety,
pasmo 1 nie zostanie obsłużone. Tak samo dzieje się w przypadku pasm 1 i 2.
Kernel honoruje tak zwaną flagę `Typu Usługi' (ang. Type of
Service
) i zajmuje się ustawianiem opcji `minimalna zwłoka' w pakietach
z pasma 0.
Nie pomylcie tej bezklasowej kolejki z klasową kolejką PRIO! Mimo, że zachowują
się podobnie, pfifo_fast jest bezklasowa i nie można dodawać innych kolejek do
niej przy użyciu polecenia tc.
Parametry i ich użycie
Nie można konfigurować kolejki pfifo_fast, ponieważ jest ustawiona na sztywno w
domyślnej konfiguracji. Poniżej jak to jest zrobione:
priomap
Określa w jaki sposób priorytety dla pakietów, przydzielane przez kernel,
odwzorowywane są na pasma. Odwzorowywanie zachodzi na podstawie oktetu
ToS pakietu, który wygląda tak:
0 1 2 3 4 5 6 7
+-----+-----+-----+-----+-----+-----+-----+-----+
| | | |
| KOLEJNOŚĆ | TOS | MBZ |
| | | |
+-----+-----+-----+-----+-----+-----+-----+-----+
Czterobitowe pole ToS definiowane jest w następujący sposób:
Binarnie Decymalnie Znaczenie
-----------------------------------------
1000 8 Zminimalizuj zwłokę (md)
0100 4 Zmaksymalizuj przepustowość (mt)
0010 2 Zmaksymalizuj niezawodność (mr)
0001 1 Zminimalizuj koszt (mmc)
0000 0 Normalna usługa
Ponieważ na prawo od pola ToS znajduje się jeszcze jeden bit, pole ToS jest
równe podwojonej wartości bitów ToS. tcpdump -v -v pokazuje
wartość całego pola ToS, nie tylko tych 4 bitów. Jest to wartość, którą możesz
znaleźć w pierwszej kolumnie tej tabeli:
TOS Bity Znaczenie Priorytet Linuksa Pasmo
---------------------------------------------------------------------
0x0 0 Normalna Usługa 0 Najlepszy efekt 1
0x2 1 Zminimalizuj koszt 1 Wypełniacz 2
0x4 2 Zmaksymalizuj niezawodność 0 Najlepszy efekt 1
0x6 3 mmc+mr 0 Najlepszy efekt 1
0x8 4 Zmaksymalizuj przepustowość 2 Większość 2
0xa 5 mmc+mt 2 Większość 2
0xc 6 mr+mt 2 Większość 2
0xe 7 mmc+mr+mt 2 Większość 2
0x10 8 Zminimalizuj zwłokę 6 Interaktywnie 0
0x12 9 mmc+md 6 Interaktywni 0
0x14 10 mr+md 6 Interaktywni 0
0x16 11 mmc+mr+md 6 Interaktywni 0
0x18 12 mt+md 4 Większość interakt.1
0x1a 13 mmc+mt+md 4 Większość interakt.1
0x1c 14 mr+mt+md 4 Większość interakt.1
0x1e 15 mmc+mr+mt+md 4 Większość interakt.1
Dużo numerków. Druga kolumna zawiera wartość czterech bitów pola ToS, a
następnie ich znaczenie. Na przykład wartość 15 oznacza pakiet wymagający
Minimalnego Kosztu, Maksymalnej Niezawodności, Maksymalnej Przepustowości i
Minimalnej Zwłoki. Nazwałbym go `Pakietem Holenderskim'.
Czwarta kolumna to sposób w jaki kernel interpretuje bity ToS, określony
priorytetem, który jest im przyznawany.
Ostatnia kolumna to wynik domyślnej mapy priorytetów (priomap). W linii
poleceń, wygląda ona tak:
1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1
Oznacza to na przykład dla priorytetu 4, że mapowany jest na pasmo 1. Mapa
priorytetów pozwala również na wylistowanie wyższych priorytetów (> 7),
które nie odpowiadają mapowaniom ToS, ale są rozsyłane dla innych zastosowań.
Poniższy wydruk pochodzi z RFC 1349 (przeczytaj ten dokument jeśli chcesz
zapoznać się ze szczegółami) i omawia jak aplikacje mogłyby ustawiać pole TOS
swoich pakietów:
TELNET 1000 (zminimalizuj zwłokę)
FTP
kanał kontroli 1000 (zminimalizuj zwłokę)
Dane 0100 (zmaksymalizuj przepustowość)
TFTP 1000 (zminimalizuj zwłokę)
SMTP
Faza komend 1000 (zminimalizuj zwłokę)
Faza danych 0100 (zmaksymalizuj przepustowość)
Domain Name Service
Zapytanie UDP 1000 (zminimalizuj zwłokę)
Zapytanie TCP 0000
Transfer Strefy 0100 (zmaksymalizuj przepustowość)
NNTP 0001 (zminimalizuj koszt)
ICMP
Błędy 0000
Zapytania 0000 (zwykle)
Odpowiedzi <takie jak zapytania> (zwykle)
txqueuelen
Długość tej kolejki odpowiada konfiguracji interfejsu. Można ją sprawdzić i
ustawić posługując się poleceniami ifconfig i
ip. By ustawić długość kolejki na 10, wykonaj polecenie
ifconfig eth0 txqueuelen 10.
Nie można ustawić wartości tego parametru za pomocą tc!
Token Bucket Filter
Token Bucket Filter (TBF, w wolnym tłumaczeniu Filtr Wiadra Żetonów
)
to prosta kolejka z dyscypliną, która przepuszcza tylko dane przychodzące z
pewną częstotliwością nie przekraczającą nałożonych ograniczeń, ale z
możliwością przyjęcia krótkich serii danych które przekraczają tych
ograniczeń.
TBF jest bardzo precyzyjna, przyjazna zarówno dla sieci jak i procesora. Powinna
być twoim pierwszym wyborem jeśli chcesz po prostu zwolnić interfejs!
Implementacja TBF składa się z bufora (`wiadra', ang. bucket
),
wypełnianego pewnymi wirtualnymi porcjami danych (`żetonami',
ang. token
) z określoną częstotliwością. Najważniejszym
parametrem wiadra jest jego rozmiar, określający ilość żetonów które może
ono przechować.
Każdy nadchodzący żeton wyjmuje jeden przychodzący pakiet z kolejki danych i
jest kasowany z wiadra. Skojarzenie tego algorytmu z dwoma przepływami - żetonów
i danych, daje trzy możliwe scenariusze:
Dane docierają do TBF z częstotliwością równą częstotliwości
napływania żetonów. W tym przypadku każdy przychodzący pakiet ma swój żeton i
przechodzi przez kolejkę bez zwłoki.
Dane docierają do TBF z częstotliwością mniejszą niż
częstotliwość napływania żetonów. Tylko ich część jest używana, więc te puste
zbierane są do momentu osiągnięcia rozmiaru `wiadra'. Mogą być potem użyte do
krótkiej serii pakietów przekraczających normalny limit przepustowości.
Dane docierają do TBF z częstotliwością większą niż częstotliwość
napływania żetonów. Oznacza to, że `wiadro' zostanie w końcu opróżnione z
pustych żetonów, powodując przez moment zwiększenie przepustowości. Nazywa się
to `przekroczeniem limitu' i jeśli pakiety nadal będą napływały z niezmienną
częstotliwością, niektóre będą odrzucane.
Ostatni scenariusz jest bardzo ważny, ponieważ umożliwia kształtować
przepustowość dostępną dla danych które przechodzą przez filtr.
Akumulacja żetonów zapewnia pewnego rodzaju zapas bezpieczeństwa, który
wykorzystany zostanie gdy pakiety zaczną nagle docierać z większą niż
dotychczas częstotliwością. W końcu jednak, ciągłe obciążenie większe od
maksymalnego zdefiniowanego spowoduje przeładowanie i pakiety zaczną być
najpierw opóźniane, a w końcu odrzucane.
Proszę zauważyć, że w implementacji programowej, żetony odpowiadają bajtom a
nie pakietom.
Parametry i ich użycie
Mimo, że zapewne nie będziesz potrzebował ich zmieniać, tbf udostępnia parę
zmiennych kontrolnych. Po pierwsze, parametry dostępne zawsze:
limit lub latency (limit lub opóźnienie)
Limit to numer bajtów, które mogą zostać skolejkowane w oczekiwaniu na wolne
żetony. Możesz również określić parametr wskazując opóźnienie, określające
maksymalny czas jaki pakiet może spędzić w TBF. To drugie bierze pod uwagę
rozmiar `wiadra', częstotliwość i ewentualnie (jeśli zostanie ustawiona)
częstotliwość szczytową.
burst/buffer/maxburst
Rozmar `wiadra', w bajtach. Jest to maksymalna ilość bajtów dla których
jednocześnie mogą być dostępne żetony. Generalnie, kształtowanie ruchu większych
przepustowości wymaga większego bufora. Dla ruchu 10mbit/s na karcie Intel,
potrzebujesz przynajmniej 10 kilobajtowego bufora, jeśli chcesz osiągnąć żądaną
przepustowość!
Jeśli bufor będzie za mały, pakiety mogą być odrzucane dlatego, że przepływa
więcej żetonów na jednostkę zegara, niż mieści się w `wiadrze'.
mpu
Pakiet długości zero bajtów nie zużywa zero przepustowości. Dla ethernetu,
pusty pakiet zużywa mniej niż 64 bajty. `Minimalna Jednostka Pakietu'
(ang. Minimum Packet Unit
) określa minimalną zajętość żetona
przez pakiet.
rate
Ustawienie prędkości. Zajrzyj do notatek powyżej o limitach!
Jeśli `wiadro' zawiera żetony i nie może być puste, domyślnie pracuje z
nieograniczoną prędkością. Jeśli jest to nieakceptowalne, użyj następujących
parametrów:
peakrate
Domyślnie, jeśli dostępne są żetony a przybywają pakiety, są one natychmiast
wysyłane. Może to nie być konkretnie to, czego chcesz, szczególnie jeśli
masz duże `wiadro'.
Parametr `peakrate' może zostać użyty do określenia jak szybko `wiadro' może
być opróżniane. Jeśli go określisz, po wysłaniu pakietu odczekamy chwilę i
dopiero po jej upływie wyślemy następny - dzięki przeliczeniu przestrzeni
czasowej między pakietami tak, aby wysyłać dokładnie tyle ile wynosi wartość
tego parametru.
Jednak ponieważ zegar Unixowy ma rozdzielczość tylko 10ms, otrzymując
10.000 bitów średniego ruchu ograniczeni jesteśmy do `peakrate' równej około
1mbit/s!
mtu/minburst
Oczywiście `peakrate' równe 1mbit/s nie jest zbyt użyteczne, jeśli twój normalny
ruch wynosi więcej. Większa wartość szczytowa możliwa jest do osiągnięcia przez
wysyłanie większej ilości pakietów na jedną jednostkę zegara, co oznacza, że
tworzymy drugie wiadro!
To drugie wiadro domyślnie ma wielkość jednego pakietu, więc tak naprawdę
nie jest wcale wiadrem.
By wyliczyć maksymalną wartość szczytową, pomnóż skonfigurowane MTU przez
100 (lub, bardziej poprawnie, HZ, co oznacza 100 na platformie intelowskiej
i 1024 na Alfie).
Przykładowa konfiguracja
Prosta, ale bardzo przydatna konfiguracja to:
# tc qdisc add dev ppp0 root tbf rate 220kbit latency 50ms burst 1540
No dobra, dlaczego jest taka przydatna? Jeśli masz urządzenie sieciowe z całkiem
dużą kolejką, tak jak na przykład modem kablowy lub DSL i łączysz je do szybkiego
urządzenia takiego jak na przykład interfejs ethernetowy, zauważysz od razu,
że wrzucanie czegoś od razu niszczy interaktywność.
Dzieje się tak dlatego, ponieważ wysyłanie pakietów zapełni kolejkę w modemie,
która jest prawdopodobnie bardzo duża - taka konfiguracja
pomaga uzyskać dużą przepustowość. Ale to nie jest to co chcesz osiągnąć, chcesz
mieć pełną interaktywność a nie zapchać modem jednym strumieniem i nie móc
zrobić już nic innego.
Linia powyżej spowalnia wysyłanie do częstotliwości, która nie prowadzi
zapełniania kolejki w modemie - kolejka będzie już na Linuksie, gdzie mamy
swobodę konfiguracji jej do określonego rozmiaru.
Zmień wartość 220kbit na swoją faktyczną prędkość wysyłania
danych minus parę procent. Jeśli masz naprawdę bardzo szybki modem, możesz
troszkę zwiększyć wartość `burst'.
Sprawiedliwe Kolejkowanie Stochastyczne
(ang. Stochastic Fairness Queueing
)
Stochastic Fairness Queueing (SFQ) to prosta implementacja rodziny algorytmów
ze sprawiedliwym podziałem pasma. Jest mniej dokładna niż inne, ale wymaga
również mniejszej ilości wyliczeń.
Kluczowym pojęciem w SFQ jest konwersacja (lub potok), która odpowiada
zwykle sesji TCP lub strumieniowi UDP. Ruch dzielony jest w dużą ilość
kolejek FIFO, po jednej na każdą konwersację. Następnie każda z kolejek
opróżniana jest na zasadzie `round-robin' tak aby każda z sesji mogła
wysłać swoje dane.
Zapewnia to sprawiedliwą pracę i uniemożliwia jednej konwersacji zajęcie
całego pasma. SFQ nazywana jest `stochastyczną', ponieważ tak naprawdę nie
przydziela kolejki dla każdej sesji, a używa procedury dzielącej ruch na
ograniczoną liczbę kolejek przy pomocy algorytmu `mieszającego'
(ang. hashing
).
Ponieważ używana jest wartość mieszająca ( wspominany hash ), może dojść do
sytuacji w której więcej niż jedna sesja może skończyć w tym samym wiadrze.
Oznaczałoby to w praktyce zmniejszenie szansy wysłania pakietu o połowę i
podzielenie tym samym na pół dostępnej efektywnej prędkości. By temu zapobiec,
SFQ zmienia często algorytm mieszający i nawet jeśli dojdzie do kolizji sesji
będzie to działo się tylko przez parę sekund.
Warto zauważyć, że SFQ jest użyteczne w przypadku gdy twój interfejs wychodzący
jest naprawdę pełen! Jeśli nie będzie, nie stworzona zostanie kolejka i tak
naprawdę nie będzie miało to żadnego efektu. Później omówimy jak połączyć SFQ
z innymi dyscyplinami kolejkowania i uzyskać to co najlepsze z obu sytuacji.
W szczególności, zastosowanie SFQ wobec interfejsu ethernetowego podłączonego
do modemu kablowego lub rutera DSL jest bezcelowe, bez dalszego nałożenia
ograniczeń!
Parametry i użycie
SFQ jest praktycznie samokonfigurowalna:
perturb
Wartość określajaca co ile sekund zmieniany będzie algorytm mieszający. Jeśli
nie zostanie podana, wyliczona wartość mieszająca nie będzie rekonfigurowana.
Generalnie pomijanie tego parametru nie jest zalecane - wartość 10 sekund
wydaje się dobrym wyborem.
quantum
Ilość bajtów, którą strumień może zdjąć z kolejki zanim szansę wysłania otrzyma
kolejna kolejka. Domyślnie ustawione jest na równowartość maksymalnej jednostki
transmisji 1 pakietu (MTU). Nie ustawiaj tego parametru poniżej MTU!
Przykładowa konfiguracja
Jeśli masz urządzenie połączone łączem o identycznej przepustowości jaka jest
ogólnie dostępna, tak jak na przykład w sytuacji połączenia modemowego, to
polecenie pomoże ci uwydatnić sprawiedliwy podział ruchu:
# tc qdisc add dev ppp0 root sfq perturb 10
# tc -s -d qdisc ls
qdisc sfq 800c: dev ppp0 quantum 1514b limit 128p flows 128/1024 perturb 10sec
Sent 4812 bytes 62 pkts (dropped 0, overlimits 0)
Numer `800c:' to automatycznie nadawana etykietą, limit oznacza, że w kolejce
oczekiwać może 128 pakietów. Dostępne są 1024 wiadra kontrolowane algorytmem
mieszającym, z których 128 może być jednocześnie aktywnych (więcej pakietów nie
wejdzie do kolejki!). Co 10 sekund, wartości mieszające są rekonfigurowane.
Kiedy używać której kolejki
Podsumowując, powyższe algorytmy tworzą proste kolejki zarządzające ruchem
przez rekolejkowanie, zwalnianie lub odrzucanie pakietów.
Poniższe podpowiedzi mogą pomóc w wyborze odpowiedniej kolejki. Wspominają one
niektóre dyscypliny kolejkowania omówione w rozdziale
.
Jeśli chcesz zwolnić ruch wychodzący, użyj TBF. Działa nawet dla dużych
przepustowości, jeśli odpowiednio wyskalujesz wiadro.
Jeśli masz naprawdę zapchane łącze i chcesz mieć pewność, że żadna sesja nie
zdominuje całego pasma wychodzącego, użyj SFQ.
Jeśli masz naprawdę dużą sieć szkieletową i wiesz co robisz, rozważ algorytm
RED (opisany w rozdziale zaawansowanym).
By kształtować (ang. shape
) ruch przychodzący, którego nie
przekazujesz gdzie indziej, użyj `Polityki dla ruchu przychodzącego' (ang.
Ingress Policer
). Nawiasem mówiąc, kontrolowanie ruchu
przychodzącego to `określanie polityki' (ang. policing
) a nie
`kształtowanie'.
Jeśli go jednak przekazujesz, używaj TBF na interfejsie wysyłającym te dane,
chyba, że może on wychodzić przez wiele interfejsów. W tym wypadku jedyną
wspólną cechą będzie interfejs którym ruch dotarł i wtedy należy użyć
polityki dla ruchu przychodzącego.
Jeśli nie chcesz kształtować ruchu, a jedynie sprawdzić czy twój interfejs jest
tak obciążony, że musi używać swojej kolejki, użyj kolejkowania `pfifo'
(nie `pfifo_fast'). Brakuje jej ograniczeń, ale zlicza parametry pracy.
Na koniec - możesz użyć kształtowania osobistego
. Nie zawsze
będziesz w stanie użyć dostępnej technologii do osiągnięcia dokładnie
założonego celu, a użytkownicy zwykle odczuwają nakładane ograniczenia jako
złośliwość. Przyjazne słowo może pomoć w osiągnięciu odpowiednich parametrów
pracy w sieci!
Terminologia
By prawidłowo zrozumieć bardziej zaawansowane konfiguracje, niezbędne jest
prawidłowe wytłumaczenie pewnych koncepcji. Z uwagi na poziom skomplikowania i
świeżość tematu, wiele ludzi używa różnych słów na oznaczanie tych samych
rzeczy.
Poniższa lista bazuje na zawartości dokumentu
draft-ietf-diffserv-model-06.txt zatytułowanego
An Informal Management Model for Diffserv Routers. Można
go znaleźć pod adresem
http://www.ietf.org/internet-drafts/draft-ietf-diffserv-model-06.txt
.
Zapoznaj się z dokumentem by poznać dokładne definicje terminów, które będziemy
używali.
Dyscyplina kolejkowania (ang. Queueing Discipline
, qdisc)
Algorytm zarządzający kolejką urządzenia, dla ruchu `przychodzącego'
(ang. ingrees
) lub `wychodzącego' (ang. egrees
).
root qdisc
Główna qdisc to dyscyplina dołączona bezpośrednio do urządzenia.
Bezklasowa dyscyplina kolejkowania (ang. Classless qdisc
)
Qdisc w której nie ma konfigurowalnych wewnętrznych podziałów.
Dyscyplina kolejkowania z klasami (ang. Classful qdisc
)
Dyscyplina kolejkowania może zawierać wiele klas. Każda z nich może zawierać
następne dyscypliny kolejkowania i tak dalej i tak dalej - ale nie musi.
Zgodnie z definicją, `pfifo_fast' jest dyscypliną
kolejkowania z klasami - zawiera trzy pasma będące klasami. Ponieważ jednak
żadne jej parametry nie mogą być modyfikowane narzędziem tc,
z punktu widzenia użytkownika jest bezklasowa.
Klasy (ang. Classes
)
Dyscyplina kolejkowania z klasami, tak jak wskazuje jej nazwa, zawiera klasy.
Mogą one zawierać kolejne dyscypliny i tak dalej i tak dalej. Innymi słowy,
możesz skonfigurować qdisc która będzie rodzicem dla innej qdisc. Liść to
qdisc, która nie posiada dzieci. Klasa ma przydzieloną jedną dyscyplinę
kolejkowania i jest ona odpowiedzialna za wysyłanie danych z tej klasy. Gdy
tworzysz klasę, przydzielana jest do niej domyślnie dyscyplina FIFO. Gdy
dodasz dziecko do dyscypliny, FIFO jest usuwana. Dla klasy będącej liściem,
algorytm FIFO można zastąpić bardziej odpowiednią dyscypliną kolejkowania.
Możesz nawet ją zastąpić dyscypliną kolejkowania z klasami, co pozwoli ci
na dalszą rozbudowę klas.
Klasyfikator (ang. Classifier
)
Każda dyscyplina kolejkowania z klasami musi wiedzieć, do której klasy ma wysłać
pakiet. Wykonuje to właśnie na podstawie klasyfikatora.
Filtr (ang. Filter
)
Klasyfikacja może zostać wykonana na podstawie filtrów. Filtr zawiera pewną
liczbę warunków, które jeśli pasują, sprawiają że filtr również pasuje.
Planowanie (ang. Scheduling
)
Dyscyplina kolejkowania z klasami, z pomocą klasyfikatora może zdecydować, że
niektóre pakiety powinny zostać wysłane wcześniej niż inne. Proces ten nazywamy
planowaniem i jest wykonywany na przykład przez qdisc `pfifo_fast', o której
wspomniano wcześniej. Planowanie nazywa się również `porządkowaniem', ale jest
to raczej mylące.
Kształtowanie (ang. Shaping
)
Proces odwlekania momentu wysłania pakietu tak, by pasował do zdefiniowanych
charakterystyk ruchowych i jego maksymalnych wartości. Kształtowanie ruchu
wykonywane jest przy opuszczaniu przez pakiet systemu. Czasami kształtowanie
oznacza również odrzucanie pakietów zamiast opóźniania ich wysłania.
Narzucanie polityki (ang. Policing
)
Proces odwrotny do kształtowania, wykonywany na ruchu przychodzącym. Może on
tylko odrzucać pakiety a nie odwlekać ich obsługę - nie istnieje
`kolejka dla ruchu przychodzącego'.
Kolejka bezstratna (ang. Work-Conserving
)
Ta qdisc zawsze dostarcza pakiet, jeśli tylko jest dostępny. Innymi słowy,
nigdy nie odwleka wysłania pakietu, jeśli urządzenie sieciowe jest gotowe do
przyjęcia go (w przypadku ruchu wychodzącego).
Kolejka stratna (ang. non-Work-Conserving
)
Niektóre kolejki, takie jak na przykład TBF, mogą być zmuszone przytrzymać
pakiet przez pewien czas, by dopasować się do ustalonego limitu na przepustowość.
Oznacza to, że czasami nie wyślą pakietu, mimo że są już do tego gotowe.
Dobrze, przebrnęliśmy przez terminologię, zobaczmy teraz gdzie te wszystkie
rzeczy się znajdują.
Programy przestrzeni użytkownika (userspace)
^
|
+---------------+-----------------------------------------+
| Y |
| -------> Stos IP |
| | | |
| | Y |
| | Y |
| ^ | |
| | / ----------> Przekazywanie -> |
| ^ / | |
| |/ Y |
| | | |
| ^ Y /-qdisc1-\ |
| | Klasyfikator /--qdisc2--\ |
--->->Przychodząca dla ruchu ---qdisc3---- | ->
| Qdisc wychodzącego \__qdisc4__/ |
| \-qdiscN_/ |
| |
+----------------------------------------------------------+
Dziękuje Jamal Hadi Salim za ten diagram ASCII.
Duży kwadrat reprezentuje kernel. Lewa strzałka reprezentuje ruch docierający do
twojego komputera z sieci. Zostaje on następnie wrzucony do klasyfikatora ruchu
przychodzącego, który może zastować filtry i być może odrzucić ten ruch.
Nazywamy to `narzucaniem polityki'.
Dzieje się to we wczesnym stadium, zanim pakiet obejrzał sobie większość
kernela. Jest to więc dobre miejsce by odrzucać ruch bez zbędnego angażowania
cykli CPU.
Jeśli pakiet zostanie przepuszczony, może być skierowany do aplikacji
działającej lokalnie - trafia wtedy na stos IP by zostać przetworzony a potem
do tej konkretnej aplikacji. Pakiet może jednak być przekazywany dalej, trafia
wtedy do klasyfikatora dla ruchu wychodzącego. Programy przestrzeni użytkownika
wysyłające pakiety również dostarczają danych dla klasyfikatora ruchu
wychodzącego.
Ruch wychodzący z takiego czy innego źródła trafia następnie do przetworzenia w
określonej liczbie skonfigurowanych qdisc. W domyślnym, nieskonfigurowanym
stanie, istnieje jedynie jedna kolejka dla ruchu wychodzącego - jest to
`pfifo_fast', która zawsze odbiera pakiet. Nazywamy to `kolejkowaniem'.
Pakiet czeka zatem w qdisc na decyzję kernela powodującą wysłanie go przez
któryś interfejs sieciowy. Nazywamy to z kolei `opróżnianiem kolejki'.
Rysunek ten ma zastosowanie również dla sytuacji z jednym urządzeniem
sieciowym - strzałki skierowane do i od kernela nie powinny być brane zbyt
dosłownie. W każdym urządzeniu sieciowym obsługiwane jest zarówno odebranie
pakietu jak i jego wysłanie.
Dyscypliny kolejkowania z klasami
qdisc z klasami przydatne są jeśli masz ruch różnego rodzaju, który powinien
być w różny sposób traktowany. Jedną z qdisc z klasami jest `CBQ' -
`Kolejkowanie oparte o klasy' (ang. Class Based Queueing
) i
jest tak popularna, że ludzie identyfikują całe zagadnienie kolejkowania
jako właśnie CBQ, ale nie jest to do końca poprawne.
CBQ jest jedynie najstarszą zabawką - a jednocześnie najbardziej skomplikowaną.
Nie zawsze może robić to co chciałeś. Może to być szok szczególnie dla ludzi
podatnych na `efekt sendmaila' - który uczy nas, że skomplikowane technologie
dostarczane bez dokumentacji muszą być najlepszymi dostępnymi.
Więcej o CBQ i jego alternatywach już niedługo.
Przepływ w qdisc z klasami
Ruch docierający do qdisc z klasami, musi zostać rozesłany do klas podrzędnych,
czyli `sklasyfikowany'. By określić co zrobić z konkretnym pakietem używa się
filtrów. Ważne jest, by zauważyć że to filtry wywoływane są w qdisc a nie
odwrotnie!
Filtry dołączone do określonych qdisc odpowiadają decyzją i kolejka używa jej do
skolejkowania pakietu w jedną z klas. Każda podklasa może sprawdzić swoje
filtry by ewentualnie dopasować się do jeszcze innych założeń czy instrukcji.
Jeśli tego nie robi, klasa kolejkuje pakiet do qdisc, ją zawierającą.
Poza zawieraniem w sobie innych kolejek, większość qdisc z klasami wykonuje
również kształtowanie. Dzięki temu można zarówno planować pakiety (np. przy
użyciu SFQ) i ograniczać częstotliwość z jaką będą wysyłane. Potrzebujesz takiej
możliwości gdy masz szybki interfejs (na przykład, ethernet) i wolne urządzenie
sieciowe (np. modem kablowy).
Gdybyśmy uruchomili tylko SFQ nic się nie stanie, ponieważ pakiety docierają i
opuszczają twój router bez żadnej zwłoki: interfejs wyjściowy jest dużo
szybszy niż faktyczna przepustowość łącza. Nie ma więc kolejki, którą możnaby
kontrolować.
Rodzina kolejek z klasami: korzenie, uchwyty, rodzeństwo i rodzice