IPv6 i Linux

[ mapka tuneli CETI ]
Aktualne tunele CETI (link)

Uwaga: Ta konfiguracja nie działa prawie od dwóch lat, należy ją więc traktować jako przykładową.

Podstawy IPv6

6BONE jest ogólnoświatową siecią komputerów wykorzystujących protokół IPv6 to komunikacji między sobą. Sieć ta jest oparta w większości o połączenia tunelujące IPv6 w protokole IPv4. 6BONE służy praktycznie wyłącznie do badania zachowania IPv6 w różnych warunkach i dominującą w nim usługą jest ping oraz traceroute. Podłączenie się do 6BONE to przede wszystkim okazja do poznania wielu aspektów działania sieci opartych o protokół IP, wykorzystania w praktyce rutingu dynamicznego opartego o BGP itp.

Protokół IPv6 w codziennych zastosowaniach nie różni się bardzo od nowoczesnych implementacji IPv4. Podłączenie się do 6BONE wymaga wiedzy teoretycznej i praktycznej w tym zakresie. Pisząc o nowoczesnych implementacjach mam tu na myśli przede wszystkim ruting CIDR, pojęcie prefiksów, długości prefiksu itp. Krótkie wprowadzenie na ten temat można znaleźć w moim artykule ,,Ruting IP w Linuxie 2.2'' (patrz strona o CBQ).

Wiele informacji o samym IPv6 można znaleźć na stronach: www.ipv6.org, www.6bone.net i innych, poświęconych IPv6 oraz 6BONE.

Kernel

Obsługa IPv6 jest dostępna w Linuxach nowszych niż 2.1.8. W praktyce należy używać wersji 2.2 lub 2.3, możliwie jak najnowszych, ponieważ w międzyczasie usunięto wiele błędów w obsłudzie IPv6.

Szczególnie polecam skorzystanie z pakietów RPM dostępnych w dystrybucji PLD, ponieważ zarówno dostępny w niej kernel, biblioteki i oprogramowanie domyślnie obsługują IPv6.

Podczas konfiguracji kernela należy włączyć następujące opcje:

Sekcja Opcja Ustawienie
Code maturity level options Prompt for development and/or incomplete code/drivers Yes
Networking options IP: tunneling Yes
Networking options The IPv6 protocol (EXPERIMENTAL) Yes
Networking options IPv6: enable EUI-64 token format Yes
Networking options IPv6: disable provided based addresses Yes

Wszystkie opcje wkompilowałem do kernela na stałe. Niektóre z nich nie chciały działać jako moduły, w szczególności tunneling.

Oprogramowanie

W momencie pisania tego tekstu faktycznym standardem jest glibc-2.1, które posiada wszystkie niezbędne do IPv6 funkcje. Ponadto potrzebne są aplikacje do konfiguracji interfejsów. Jeśli chodzi o IPv4, wielu administratorów używa ifconfig, który w odpowiednio aktualnej wersji umożliwia również operacje na adresach IPv6. Zasłużoną popularność zdobył sobie także program iproute2 Aleksieja Kuźniecowa. Ze względu na to, że iproute2 umożliwia wiele rzeczy, których nie da się zrobić przy pomocy ifconfig, osobiście używam wyłącznie iproute2, zarówno do IPv4 i do IPv6. Poniższe wskazówki zakładają wyłączne korzystanie z iproute2.

I tutaj po raz kolejny warto zapoznać się z PLD, ponieważ jest ono całkowicie oparte o iproute2, zawiera także wszystkie niezbędne pliki konfiguracyjne opisane poniżej.

Przygotowanie systemu pod IPv6

Do pliku /etc/hosts należy dodać:

::1             ipv6-localhost ipv6-loopback
fe00::0         ipv6-localnet
ff00::0         ipv6-mcastprefix
ff02::1         ipv6-allnodes
ff02::2         ipv6-allrouters
ff02::3         ipv6-allhosts

Rekordy dotyczące IPv6 w pliku /etc/protocols są zdefiniowane w RFC 2292. Należy do niego dodać następujące pozycje:

hopopt           0    # hop-by-hop options for ipv6
ipv6            41    # ipv6
ipv6-route      43    # routing header for ipv6
ipv6-frag       44    # fragment header for ipv6
esp             50    # encapsulating security payload for ipv6
ah              51    # authentication header for ipv6
ipv6-icmp       58    # icmp for ipv6
ipv6-nonxt      59    # no next header for ipv6
ipv6-opts       60    # destination options for ipv6

Adresy IPv6

Ciekawą właściwością IPv6 jest to, że hosty w sieci lokalnej mogą się porozumiewać między sobą praktycznie bez żadnej dodatkowej konfiguracji, poza podniesieniem interfejsu. Przyznawanie specjalnych, prywatnych adresów jest niepotrzebne, dzięki automatycznie konfigurowanym adresom tzw. link-local, działających w obrębie jednego segmentu sieci lokalnej. Adres link-local te można zobaczyć poleceniem ip addr show scope link, zaczyna się on od prefiksu fe80::. Znając adres link-local drugiego hosta w sieci lokalnej można z nim nawiązać łączność, co można sprawdzić np. przy pomocy pinga.

Adresy link-local nie są nigdy przekazywane przez rutery, w związku z czym nie można przy pomocy korzystać z 6BONE. Do tego celu trzeba uzyskać pulę adresów o zasięgu globalnym (scope global), przy czym obecnie zaczynają się one zawsze od prefiksu 3ffe: (adresy 6BONE) lub 2001: (adresy IANA). Przydziałem adresów tego typu zajmuje się regionalny koordynator pNLA (pseudo Next Level Aggregation), którym w chwili obecnej jest Rafał Maszkowski (kontakt emailem pod adresem <6tunnels@sunsite.icm.edu.pl>). pNLA przydziela pule o długości prefiksu 48 bitów (po 280 adresów). W przypadku posiadania kilku tuneli warto jednak uruchomić dla swojej puli rozgłaszanie przy pomocy dynamicznego protokołu rutingu BGP 4+, co pozwoli na pełne wykorzystanie możliwości 6BONE.

Prostszym rozwiązaniem jest uzyskanie mniejszej puli adresów od kogoś, posiadającego pulę /48, podłączenie się do niego statycznym tunelem i działanie w ramach jego Systemu Autonomicznego (Autonomous System). Jeden i drugi wariant zapewnia przyłączenie do 6BONE, z tym że w przypadku tunelu statycznego należy się raczej nastawić na połączenie tylko do jednego AS i brak możliwości eksperymentowania z dynamicznym rutingiem.

Konfiguracja interfejsów

Mając adresy globalne, można przystąpić do konfiguracji interfejsu na danym hoście. W obecnie preferowanym przez polskie 6BONE wariancie jest to zwykłe, numerowane (numbered) połączenie punkt-punkt. W przeszłości testowaliśmy różne inne, nieraz dość egzotyczne, konfiguracje, ale połączenia numerowane adresami globalnymi wydają się być najbardziej uniwersalne i najlepiej rozumiane przez demony BGP.

Konfiguracja tunelu IPv6 w IPv4 składa się z trzech kroków. Pierwszym jest określenie końców tunelu w IPv4.

$ ip tunnel add pipeta mode sit remote 149.156.137.250 local 195.116.211.27

Powyższa linijka jest częścią mojej działającej konfiguracji. Tworzy nowy interfejs sieciowy o nazwie pipeta, działający w trybie SIT (Simple Internet Transition), co jest linuksowym określeniem tunelu typu ,,IPv6 po IPv4''. Tunel zaczyna się na moim hoście 195.116.211.27 (mam kilka równoprawnych interfejsów, więc konieczne jest sprecyzowanie który jest końcem tunelu). Kończy się na hoście 149.156.137.250. Następna czynność to podniesienie interfejsu:

$ ip link set pipeta up

W kolejnym kroku musimy przydzielić nowemu tunelowi jakiś adres IPv6:

$ ip addr add 3ffe:8010:3::2:0:1/126 dev pipeta

To wymaga pewnego komentarza. W przypadku tunelu statycznego adres swojego tunelu otrzymasz zapewne od administratora Systemu Autonomicznego, który cię podłącza. W przypadku własnej puli warto na adresy tuneli przeznaczyć jakąś niedużą sieć, na przykład o długości prefiksu 96 bitów (nota bene ma ona wielkość 32 bitów, czyli dokładnie tyle ile cały współczesny Internet). Sieci o takiej długości można także przydzielać np. interfejsom Ethernet do sieci lokalnej.

Przykładowo, mój interfejs eth0 może mieć adres 3ffe:8010:3::0:0:3/96 (dwa zera można tak naprawdę pominąć). Następna ,,duża'' sieć /96 będzie miała adres ::1:0:0/96, a następna ::2:0:0/96. Z tej ostatniej wydzielamy właśnie małą, dwubitową podsieć /126, zawierającą dwa adresy interfejsów.

Zawsze w przypadku tunelu statycznego (lub przed uruchomieniem BGP) warto ustawić także ruting domyślny na sieci 6BONE:

$ ip route add 3f00::/8 via 3ffe:902:3::2:0:1

Jak widać, powyższa trasa domyślna ma niewiele wspólnego ze znanym z IPv4 0.0.0.0/0. Wynika to stąd, że część prefiksów w IPv6 jest zastrzeżona (jak fe80::) i ruting domyślny musi być bardziej specyficzny.

Testy

Jeśli drugi koniec tunelu jest skonfigurowany, to powinniśmy być w stanie przynajmniej go pingować (ping6 jest częścią pakietu iputils, również autorstwa Kuźniecowa):

$ ping6 3ffe:902:3::1:0:1
PING 3ffe:902:3::1:0:1(pipeta.chemia.pk.edu.pl) 56 data bytes
64 bytes from pipeta.chemia.pk.edu.pl: icmp_seq=0 time=73.9 ms
64 bytes from pipeta.chemia.pk.edu.pl: icmp_seq=1 time=10.0 ms
64 bytes from pipeta.chemia.pk.edu.pl: icmp_seq=2 time=9.5 ms
64 bytes from pipeta.chemia.pk.edu.pl: icmp_seq=3 time=18.6 ms

Analogicznie można również spróbować traceroute6 do swojego sąsiada oraz gdzieś dalej. W tym ostatnim wypadku nie trzeba szukać jakiegoś ,,działającego'' adresu, wystarczy spróbować skrócić jakiś znany prefiks i zobaczyć dokąd doprowadzi:

$ traceroute6 3ffe::1
traceroute to 3ffe::1 (3ffe::1) from 3ffe:8010:3::ffff:ffff:9, 30 hops max, 16 byte packets
 1  ceti-ipv6.icm.edu.pl (3ffe:8010:3::ffff:ffff:a)  23.077 ms  24.328 ms  33.533 ms
 2  3ffe:1400:0:ff00::12 (3ffe:1400:0:ff00::12)  168.333 ms  167.384 ms *
 3  uni-c-if.6r1.doc.london.ip6.pipex.net (3ffe:1100:0:c05::1)  222.768 ms *
...itd...

Powyższe adresy ::ffff:ffff:x są prawdziwymi adresami moich interfejsów, zupełnie legalnymi z punktu widzenia adresacji IPv6. Żałuję tylko, że nie skonfigurowałem tuneli na adresach typu ::dead:beef:x ;)

W razie problemów z łącznością niezawodnym narzędziem jest tcpdump. Można go używać na dwa podstawowe sposoby -- jeśli nie działa łączność między końcami tuneli to należy sprawdzić, czy pakiety IPv4 poprawnie przenoszą enkapsulowane IPv6:

$ tcpdump src or dst host 149.156.137.250
Kernel filter, protocol ALL, datagram packet socket
tcpdump: listening on eth0
21:37:03.644653 echo2.cyf.ceti.com.pl > pipeta.chemia.pk.edu.pl: v6-in-v4
                 3ffe:8010:3::3 > 3ffe:8010:3::1:0:1 icmpv6: echo request (DF) [tos 0x10]
21:37:03.655184 pipeta.chemia.pk.edu.pl > echo2.cyf.ceti.com.pl: v6-in-v4
                 3ffe:8010:3::1:0:1 > 3ffe:8010:3::3 icmpv6: echo reply (DF) [tos 0x10]

Jeśli łączność w warstwie IPv4 jest poprawna, to można przyjrzeć się łączności w warstwie IPv6. Już w powyższym wypadku tcpdump wyświetlał poprawnie zawartości przenoszonych po IPv4 pakietów, ale możliwe jest także nasłuchiwanie samych pakietów IPv6:

$ tcpdump -vv -s512 icmpv6
Kernel filter, protocol ALL, datagram packet socket
tcpdump: listening on eth0
21:40:10.261292  3ffe:8010:3::3 > 3ffe:8010::1  (len 64, hop 64) icmpv6: echo request
21:40:10.284221  3ffe:8010::1 > 3ffe:8010:3::3  (len 64, hop 63) icmpv6: echo reply

Należy podkreślić, że w obu wypadkach należy posiadać wersję tcpdumpa ,,rozumiejącą'' IPv6. Wersja taka jest np. rozprowadzana w pakietach PLD.

DNS

Adresy IPv6 są przechowywane w rekordach AAAA (w odróżnieniu od rekordów A dla IPv4). Są one obsługiwane przez BIND 4.9.7 oraz 8.1.2. Dla potrzeb IPv6 warto stworzyć w swojej domenie poddomenę ipv6 (np. ipv6.ceti.com.pl) i w niej dodawać adresy maszyn podłączonych do 6BONE. Poniższe przykłady dotyczą BIND 8, przykłady dla wersji 4.9.7 można znaleźć na stronie http://www.visc.vt.edu/ipv6/doc/dns.html.

Wpis w /etc/named.conf:

zone "ipv6.ceti.com.pl" {
        type master;
        file "ipv6.hosts";
};

Plik ipv6.hosts:

@               IN      SOA     tau.ceti.com.pl.  hostmaster.tau.ceti.com.pl.  (
                                1998040301
                                21600
                                7200
                                1209600
                                172800 )

                IN      NS      tau.ceti.com.pl.
                IN      NS      zatoka.icm.edu.pl.
                IN      MX      10 tau.ceti.com.pl.
                IN      MX      20 alfa.ceti.com.pl.
                IN      MX      30 pipeta.chemia.pk.edu.pl.

druid           IN      AAAA    3ffe:902:3::2
inny_host	IN	AAAA	3ffe:902:3::3
inny_host	IN	AAAA	3ffe:902:3::4

Do mapowania adresów IPv6 na nazwy kanoniczne służy domena IP6.INT, w której adres jest zapisywany od końca, cyferka po cyferce. Delegację domen w IP6.INT prowadzi węzeł od którego otrzymujemy podsieć, w naszym przypadku pNLA. Przykładowo, dla sieci 3ffe:0902:0003::/48 delegowana jest domena 3.0.0.0.2.0.9.0.e.f.f.3.ip6.int. Dla znajdującego się w tej sieci hosta 3ffe:902:3::2 należy stworzyć rekord:

2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR druid.ipv6.ceti.com.pl.

Jak można się domyślić, po połączeniu łańcucha cyfr odpowiadającego adresowi hosta z łańcuchem odpowiadającym adresowi delegowanej sieci całość powinna mieć długość 32 cyferek. Przykładowe pliki dla BIND 8 znajdują się poniżej:

Wpis w /etc/named.conf:

// 3ffe:902:3::2
zone "3.0.0.0.2.0.9.0.e.f.f.3.ip6.int" {
        type master;
        file "3ffe:902:3";
};

Plik /var/named/3ffe:902:3:

@               IN      SOA     tau.ceti.com.pl. hostmaster.tau.ceti.com.pl. (
                                1998040601 ; YYYYMMDDxx
                                86400
                                7200
                                1209600
                                21600 )

                IN      NS      tau.ceti.com.pl.
                IN      NS      zatoka.icm.edu.pl.
;                       hosty w domenie 3.0.0.0.2.0.9.0.e.f.f.3.ip6.int
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0         IN      PTR     zatoka.ipv6.icm.edu.pl.
2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0         IN      PTR     druid.ipv6.ceti.com.pl.

Po skonfigurowaniu DNSu i odwrotnego DNSu programy powinny prawidłowo rozwiązywać zarówno nazwy hostów w domenie ipv6. oraz adresy w domenie odwrotnej.

Zasoby

WWW

Pierwsze dwie strony są częsciowo nieaktualne (szczególnie w sekcjach dotyczących uzyskiwania adresów IPv6), ale zawierają wiele przydatnych informacji na temat oprogramowania IPv6 pod Linuxa.

Listy dyskusyjne

6bone-pl@sunsite.icm.edu.pl
zapisy na petidomo@sunsite.icm.edu.pl, z tekstem subscribe 6bone-pl w treści listu
netdev@nuclecu.unam.mx
zapisy na majordomo@nuclecu.unam.mx, z tekstem subscribe netdev w treści listu
6bone@isi.edu
zapisy na majordomo@zephyr.isi.edu, z tekstem subscribe 6bone w treści listu

Podziękowania

Oraz pozostali uczestnicy 6bone w Polsce i za granicą.


Paweł Krawczyk <kravietz@ceti.pl>