V předchozím díle krátkého seriálu jsme si vysvětlili princip, na jehož
základě lze zpřístupnit téměř libovolné zařízení na internetu pomocí
IPv6 a tunelu. V této části si ukážeme prakticky, jakým způsobem je možné takový
tunel vytvořit a jak přidělit svému zařízení za NATem veřejnou IPv6 adresu.
14.2.2013 00:00 | Petr Bravenec | přečteno 4898×
Při praktickém nastavování tunelu jsem se nechal inspirovat tímto krátkým návodem:
http://www.sixxs.net/wiki/L2tp
Pokud nezvolíte nějakou neobvyklou architekturu, mohli byste mít podle tohoto návodu nastavený základ pro tunel s IPv6 během chvilky. S trochou štěstí by vám mohl tunel už napoprvé fungovat alespoň na linkových adresách během půl hodiny (já jsem si celou úlohu trochu zkomplikoval procesorem ARM, ale už po dvou týdnech jsem na internetu našel fungující zdrojáky linuxového kernelu a mohl doplnit podporu pro l2tp a ppp).
Tunel jsem zkoušel vytvořit v distribuci Debian (na architektuře x86) a Gentoo (arm). Pro vytvoření tunelu s linkovými adresami potřebujete prakticky jen démony xl2tpd a pppd, pro nastavení veřejné IPv6 adresy pak můžete potřebovat i některý další program: radvd, dhcpd nebo, jako já, něco úplně jiného.
Na serveru vytvořte konfigurační soubor /etc/xl2tpd/xl2tpd.conf:
[global] [lns default] name = mujserver assign ip = no require chap = yes refuse pap = yes require authentication = yes unix authentication = no ppp debug = no pppoptfile = /etc/ppp/options.l2tpd
Zařízení se musí při vytváření tunelu autentikovat mechanismem chap. Heslo je uložené v souboru /etc/xl2tpd/l2tp-secrets:
# Secrets for authenticating l2tp tunnels # us them secret # my oni heslo # mujserver zarizeni heslo
Podobný soubor s hesly je umístěn i na zařízení, tam jsou však strany "my" a "oni" prohozené. Heslo můžete mít společné pro různá zařízení, není však problém vytvořit pro každé zařízení heslo vlastní.
V konfiguračním souboru můžete chtít změnit pouze parametr name - tento parametr je společným propojovatelem klientské části, serverové části a heslo.
Xl2tpd démon poslouchá na UDP portu 1701 (nezapomeňte na pravidla ve firewallu) a při příchozím požadavku na vytvoření tunelu od zařízení startuje pro toto zařízení démona pppd. Toho musíte nastavit taky. V konfiguraci xl2tpd je uvedeno, že pro pppd se má použít konfigurační soubor /etc/ppp/options.l2tpd:
refuse-eap noccp noauth nodefaultroute crtscts idle 1800 mtu 1410 mru 1410 lock connect-delay 5000 noip # zakáže IPv4 +ipv6 # povolí IPv6 ipv6 , # adresy pro IPv6 (nepřidělují se, zůstává prázdné) ipv6cp-accept-local # nastavit pouze linkové adresy
Po nastavení stačí na serveru spoustit démon xl2tpd. Jedinou podmínkou pro fungování démona je podpora pro l2tp a ppp v kernelu (obvykle není problém) a natažené moduly ipv6 a l2tp_ppp.
Na straně zařízení je nastavení podobně jednoduché. Konfigurační soubor /etc/xl2tpd/xl2tpd.conf:
[global] [lac mujserver] name = zarizeni lns = mojebrana.hobrasoft.cz:1702 redial = yes redial timeout = 15 require chap = yes refuse pap = yes require authentication = yes ppp debug = yes pppoptfile = /etc/ppp/options.l2tpd.client
Konfigurace xl2tpd na straně zařízení je podobná konfiguraci na serveru. Pravděpodobně budete chtít změnit jméno sekce "lac" - sem uveďte jméno tunelu na serveru - zde "mujserver", a parametr "name". Důležité je nastavení parametru "lns" - zde se očekává buď IPv4 adresa nebo dns jméno, uvést můžete i číslo portu (port 1702 používám kvůli jistému adminovi v zahraničí, který na požadavek "povolte ven port 1701 protokolem UDP" povolil vše ostatní, kromě portu 1701 - ten zakázal. Než shánět tlumočníka, abych adminovi sdělil svůj názor a vysvětlil význam požadavku, bylo jednodušší doplnit na serveru jedno pravidlo do iptables a změnit port).
Velmi podobný je i soubor s hesly /etc/xl2tpd/l2tp-secrets:
# Secrets for authenticating l2tp tunnels # us them secret # my oni heslo # zarizeni mujserver heslo
Konfigurace pppd je umístěná v souboru /etc/ppp/options.l2tpd.client a je prakticky shodná s konfigurací na serveru:
refuse-eap noccp noauth nodefaultroute crtscts idle 1800 mtu 1410 mru 1410 lock connect-delay 5000 noip # zakáže IPv4 +ipv6 # povolí IPv6 ipv6 , # adresy pro IPv6 (nepřidělují se, zůstává prázdné) ipv6cp-accept-local # nastavit pouze linkové adresy
Jakmile máte nakonfigurovaný a nastartovaný xl2tpd démon na obou koncích, na serveru i na zařízení, můžete na zařízení vyzkoušet nastartovat tunel:
echo "c mujserver" > /var/run/xl2tpd/l2tp-control
S trochou štěstí by se už nyní mohl tunel rozběhnout, ověřit jej můžete příkazem ifconfig nebo ip. Ve výpisu by mělo figurovat síťové rozhraní ppp0 s linkovou IPv6 adresou:
# ifconfig ppp0 Link encap:Point-to-Point Protokol inet6-adr: fe80::1923:481c:d7f8:68dd/10 Rozsah:Linka AKTIVOVÁNO POINTOPOINT BĚŽÍ NEARP MULTICAST MTU:1410 Metrika:1 RX packets:11 errors:0 dropped:0 overruns:0 frame:0 TX packets:11 errors:0 dropped:0 overruns:0 carrier:0 kolizí:0 délka odchozí fronty:3 RX bytes:720 (720.0 B) TX bytes:618 (618.0 B) # ip addr 109: ppp0:mtu 1410 qdisc pfifo_fast state UNKNOWN qlen 3 link/ppp inet6 fe80::1923:481c:d7f8:68dd/10 scope link valid_lft forever preferred_lft forever
Máte-li adresu nastavenou, můžete svůj nový tunel vyzkoušet. Nezapomeňte, že linkové adresy lze použít pouze na síťovém rozhraní ppp0 a příkazu ping musíte parametrem -I sdělit, které rozhraní má použít. Adresu protějšku můžete zjistit na druhé straně tunelu:
# ping6 -I ppp0 fe80::fdc8:d2e6:eb72:ac51 PING fe80::fdc8:d2e6:eb72:ac51(fe80::fdc8:d2e6:eb72:ac51) from fe80::1923:481c:d7f8:68dd ppp0: 56 data bytes 64 bytes from fe80::fdc8:d2e6:eb72:ac51: icmp_seq=1 ttl=64 time=108 ms 64 bytes from fe80::fdc8:d2e6:eb72:ac51: icmp_seq=2 ttl=64 time=102 ms 64 bytes from fe80::fdc8:d2e6:eb72:ac51: icmp_seq=3 ttl=64 time=86.0 ms
Nyní by měl mezi serverem a zařízením fungovat veškerý síťový provoz, můžete se zkusit připojit například přes ssh, opět nezapomeňte uvést jméno síťového rozhraní:
# ssh 'fe80::fdc8:d2e6:eb72:ac51%ppp0' The authenticity of host 'fe80::fdc8:d2e6:eb72:ac51%ppp0 (fe80::fdc8:d2e6:eb72:ac51%ppp0)' can't be established. RSA key fingerprint is 68:7d:e6:2b:e4:e9:5c:a2:a9:a7:d4:90:4b:83:6b:06. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'fe80::fdc8:d2e6:eb72:ac51%ppp0' (RSA) to the list of known hosts. Password: server ~ #
Zprovoznění IPv6 protokolu na linkových adresách je základ, bez kterého nemá smysl pokračovat dál. Máte-li s nastavením tunelu problém, zkuste hledat v logu /var/log/daemon.log, pomoci vám může i utilita tcpdump.
Pro automatické startování tunelu musíte do startovacích skriptů spouštěných při startu systému zahrnout i xl2tpd. Tím však nastartujete pouze démona, tunel se nevytvoří. Ten se vytváří až při zápisu příkazu "c mujserver" do souboru /var/run/xl2tpd/l2tp-control. Teoreticky by mělo stačit vytvořit tunel jednorázově po startu xl2tpd. Prakticky to nestačí - xl2tpd v distribuci Debian po nějakém čase neúspěšnou snahu na nastartování tunelu vzdá a vy tak můžete zůstat bez připojení, dokud někdo zařízení schované za NATem nerestartuje (parametr max redial nefunguje, jak by měl). Vhodnější a jednodušší, než vytvářet vlastní startovací skript pro vytvoření tunelu, je jediný řádek v crontab:
*/5 * * * * echo "c mujserver" > /var/run/xl2tpd/l2tp-control
Přizabijete tak dvě mouchy jednou ranou: vytváření tunelu při startu systému a restart tunelu při déletrvajících problémech s IPv4.
Zprovoznění linkové adresy je jen část úkolu. Kvůli point-to-point komunikaci nemělo smysl nastavovat IPv6 tunel, v původním zadání šlo o zpřístupnění zařízení v lokální síti pomocí veřejné IPv6 adresy.
Máte-li v internetu jediné zařízení, které chcete takto vybavit veřejnou IPv6 adresou, je nejjednodušší uvést adresy přímo do konfiguračního souboru pro pppd:
# Původní řádek zakomentovat, nebo smazat # ipv6 , # adresy pro IPv6 (nepřidělují se, zůstává prázdné) ipv6 2001:db8:3000:1::1, 2001:db8:3000:1::2
Máte-li zařízení více, je možné použít pro přidělování adres démona radvd. V tomto případě je ale potřeba vytvořit konfiguraci pro každé síťové rozhraní v souboru /etc/radvd.conf podobnou této:
interface ppp0 { AdvSendAdvert on; MinRtrAdvInterval 3; MaxRtrAdvInterval 10; AdvHomeAgentFlag off; prefix 2001:db8:3000:1::/64 { AdvOnLink on; AdvAutonomous on; AdvRouterAddr off; }; };
Potíž může být v tom, že při přidělování adres pomocí radvd můžete dostat pokaždé jinou IPv6 adresu. Neovlivníte ani síťové rozhraní, nad kterým se tunel vytváří, takže vaše zařízení může dokonce pokaždé spadnout i do jiné sítě. Pokud vám to nevadí, může být radvd nejjednodušším řešením (nezkoušel jsem).
Výše zmiňovaný informační pramen zmiňuje pro nastavení IP adres také program quagga a routovací protokol ospf6.
Jinou cestou může být přidělování adres pomocí dhcp (na IPv6 nemám zkušenosti), kde však může být problém naopak s tím, že dostanete pokaždé stejnou IPv6 adresu - mně to třeba vadí z toho důvodu, že potřebuji mít adresu nastavitelnou jednoduše v zařízení. Sám jsem proto zvolil třetí, nejméně vhodnou cestu: zařízení se dohodne na IPv6 adrese se serverem pomocí jednoduchého skriptu, který se spouští po úšpěšném vytvoření tunelu.
Jakmile je tunel vytvořený a ppp nastaví linkové adresy pro spojení zařízení se serverem, máte možnost do celého procesu vstoupit pomocí skriptu /etc/ppp/ipv6-up. Ten je volán z programu pppd a umožňuje vám provádět s celou linkou další různá kouzla. V distribucích už bývají obsažené různé skripty, které mění například /etc/resolv.conf, sambu, poštovní server (v každé distribuci najdete něco jiného). Skript lze s úspěchem použít i pro nastavení IPv6 adres na obou stranách tunelu (jak na serveru, tak na zařízení). Jako typické využití skriptu bych viděl nastavení firewallu.
Skript se spouští na obou stranách tunelu. Skript je volaný s několika užitečnými parametry (podle pořadí):
Všimněte si, že skript dostane všechny potřebné informace pro komunikaci s druhou stranou. Ve skriptu na zařízení se můžete připojit na server přes nově vytvořený tunel a požádat si například o IP adresu pomocí HTTP protokolu (na druhé straně musí poslouchat webový server):
wget http://$4%1/dej-mi-adresu?HOSTNAME=`hostname`
Na straně serveru pak můžete skript využít pro nastavení firewallu, například takto:
ip6tables -A FORWARD -i $1 -j ACCEPT ip6tables -A FORWARD -o $1 -j ACCEPT
Podobně, jako je při vytvoření tunelu volaný skript /etc/ppp/ipv6-up, při ukončení tunelu se volá skript /etc/ppp/ipv6-down. Sem lze umístit například uklízení v iptables na straně serveru, aby se vám ve firewallu nehromadila zbytečná pravidla:
ip6tables -D FORWARD -i $1 -j ACCEPT ip6tables -D FORWARD -o $1 -j ACCEPT
U zařízení pro sběr dat z fotovoltaických elektráren jsem skripty využil jak pro nastavení veřejných IPv6 adres a firewallu, tak i pro další konfiguraci zařízení, aby se zprovoznění vlastního zařízení omezilo na zapojení do sítě, nastavení hostname a případně nastavení IPv4 adresy (pro případ, že je nutné zařízení provozovat v síti bez DHCP).
Pro předávání parametrů jsem využil utilitu netcat6. Netcat je velmi univerzální nástroj pro komunikaci po síti - dokaže se připojit protokolem UDP či TCP na libovolnou IP adresu s libovolným číslem portu (pak jej můžete používat místo telnetu), nebo dokáže poslouchat na síti, čekat na příchozí spojení a síťový provoz propojit s vaším vlastním skriptem. Pomocí nástroje netcat tak můžete vytvořit v shellu jednoduchý síťový server.
"Originál" netcat nedovede pracovat v síti IPv6. V Gentoo jsem objevil čtyři různé verze programu netcat, ale z těch vyzkoušených pro mé účely vyhovoval pouze netcat6.
Pro skripty v ppp je dále výhodou, že u programu netcat lze velmi přesně specifikovat, na jakém síťovém rozhraní, na kterém portu a jakým protokolem má netcat poslouchat, nastavit lze i různé timeouty. Díky tomu je možné netcat nastavit tak, aby se vaše zařízení mohla domlouvat pouze přes tunel a pouze v krátkém časovém okamžiku těsně po vytvoření tunelu. Nemusíte se proto příliš trápit se zabezpečením (nikdo jiný se s vámi bavit nemůže), ani s uklízením (po vypršení timeoutu netcat automaticky skončí).
Ukážu vám nyní svoje skripty pro nastavení linky (očesané na nezbytné minimum). Berte je, prosím, s malou rezervou. Chcete-li si situaci maximálně zjednodušit, můžete ve svých skriptech nastavit IPv6 adresy natvrdo (nemáte-li zařízení více a hodláte spoléhat na to, že váš ISP vaše IPv6 adresy nezmění).
#!/bin/sh # Pracovní skript v /tmp adresáři # Spouští se z programu netcat, jakmile protistrana naváže spojení SCRIPT=/tmp/ipv6-up.$$.sh # Přidat pravidlo do ip6tables ip6tables -A FORWARD -i $1 -j ACCEPT ip6tables -A FORWARD -o $1 -j ACCEPT # Zde se vytváří skript pro netcat cat < $SCRIPT #!/bin/sh IFACE=$1 LOCALIP=$4 REMOTEIP=$5 # do proměnné X je načteno hostname protistrany read X PUBLICIP=\$( cat /root/seznam-zarizeni | awk -v X="\$X" '\$1 == X { print \$2; }' ) if [ "\$PUBLICIP" = "" ]; then PUBLICIP="2001:db8:3000::1" fi LOCALPUBLICIP="\${PUBLICIP}1" REMOTEPUBLICIP="\${PUBLICIP}2" /sbin/ip addr add "\$LOCALPUBLICIP" dev $1 /sbin/ip -6 route add "\$PUBLICIP/64" dev $1 echo "\$REMOTEPUBLICIP" echo echo ! chmod 700 $SCRIPT # Spustí se netcat a poslouchá na portu 1371 na spojení protistrany # Jakmile je spojení uskutečněno, spustí se skript pro komunikaci # s protistranou (vyvořený výše). Skript očekává hostname a podle # hostname v jednoduchém seznamu vyhledá adresu a pošle ji protistraně nc6 --timeout 15 --idle-timeout 3 -6 --exec $SCRIPT --listen --port 1371 --address "$4%$1" rm -f $SCRIPT
#!/bin/sh sleep 1 # Parametry spojení zjištuji podle hostname export HOSTNAME=$(hostname) # Do X se uloží odpověď serveru (IPv6 adresa) X=$(echo $HOSTNAME | nc6 --timeout 3 --idle-timeout 3 -6 "$5%$1" 1371) NET=$(echo $X | sed 's/::.*/::/') /sbin/ip addr add $X dev $1 /sbin/ip -6 route add ${NET}/64 dev $1 /sbin/ip -6 route replace default via ${NET}1 dev $1
Součástí uvedeného řešení je i tabulka s parametry. V tomto případě je tabulka velmi jednoduchá. Skript ji očekává v /root/seznam-zarizeni. V tabulce je pro každé zařízení jeden řádek s hostname zařízení a adresou sítě:
zarizeni1 2001:db8:3000:1:: zarizeni2 2001:db8:3000:2:: zarizeni3 2001:db8:3000:3::
Dnešní technologie dokáže levně a snadno řešit množství úloh, které dříve spadaly do kategorie scifi. Kde včera sbíral data několik dní člověk se zápisníkem, stačí dnes jednoduché, jednoúčelové zařízení postavené na bázi PC nebo jednodeskového ARM počítače. Kupodivu je to jiná technologie - IPv4 a NAT, která efektivnímu využívání brání.
Řešení představené v článku ukazuje jednu z cest, jak využít alespoň oklikou množství adres, které nabízí IPv6. Nepochybuji o tom, že by se dalo vymyslet lepší řešení, zvláště pro přidělování a předávání veřejných IPv6 adres. Budu rád, pokud mě na taková řešení upozorníte.