W zasadzie większość z nas ma stały adres IP, najczęściej zmienia się tylko w przypadku gdy nasz router ponownie nawiązuje połączenie z usługodawcą (ISP).
W takiej sytuacji, np. w warunkach domowych, aż pragnie się wystawić na świat np. album zdjęć lub inne rzeczy, których nie chcemy umieszczać bezpośrednio na serwerach firm trzecich (w tzw. chmurze).
Tylko jak przekazać link innym? Przecież za każdym razem nie będziemy podawać czegoś w stylu http://125.130.125.2. Po pierwsze ponieważ jutro możemy mieć już inny publiczny adres IP nadany przez ISP (np. modem się zrestartował), a po drugie łatwiej zapamiętać http://home.domena.pl .
DDNS – zewnętrzni usługodawcy
Skonfigurowanie subodmeny to rzecz prosta. Pozostaje inna kwestia – jak zautomatyzować proces, aby adres home.domena.pl zawsze kierował na naszą domową maszynę? Nic prostszego – możemy wykorzystać DDNS / DynDNS / dynamiczny DNS.
Proces polega na tym, że wydzielamy z naszej domena.pl subdomenę, która ma inny TTL (czas odświeżania) i zarządzamy samą domeną oddzielnie (co też umożliwia lepszą kontrolę pod względem bezpieczeństwa).
Możemy wykorzystać darmowe serwisy oferujące usługę DDNS, gdzie dostaniemy subdomenę w ramach ich domeny. Z naszej strony pozostaje ustawić cykliczną operację (cron) na wysłanie zapytania do API celem aktualizacji wpisu DNS dla subdomeny.
Taką usługę oferuje chociażby FreeDNS. Rejestracja jest bardzo prosta, po wszystkim pozostaje nam wywołanie przekazanego URI z tokenem naszej subdomeny w naszej sieci lokalnej (router/serwer/etc):
1 2 |
[~] $ curl https://sync.afraid.org/u/CyTXMbtq5cPnLjEg5vKHTPDE/ Updated demo.freshdns.com from 107.170.238.X to 50.23.197.94 |
Jeśli posiadacie własną domenę i korzystacie z gotowego panelu do zarządzania domeną to często jest możliwość skonfigurowania bezpośrednio tam DDNS. Taką usługę oferuje chociażby OVH.
DDNS – własne rozwiązanie
Ale może niektórzy z Was lubią posiadać większą kontrolę nad domeną (specyficzne rekordy) niż oferuje firma, w której opłacacie domenę. Posiadacie np. własną instancję BIND, gdzie trzymacie kilka domen (prostą konfigurację BIND opisałem w 2010 roku) i chcielibyście wykorzystać ten serwer nazw do DDNS.
Sam tak właśnie pomyślałem, gdy okazało się, że na jednym z interfejsów zewn. posiadam dość zmienną adresację.
DDNS – modyfikacja w BIND
Zacznijmy od zmiany w samym BIND. Powiedzmy, że posiadamy domenę domena.pl i jej strefa u nas wygląda następująco:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
$TTL 86400 $ORIGIN domena.pl. @ IN SOA dns1.domena.pl. root.domena.pl. ( 2010111801 ;; serial 2H ;; refresh 1H ;; retry 7D ;; expire 1D ;; TTL ) @ IN NS dns1.domena.pl. @ IN NS dns2.domena.pl. @ IN MX 10 mail.domena.pl. @ IN A XXX.XX.XX.X dns1 IN A XXX.XX.XX.X dns2 IN A YYY.YY.YY.Y www IN CNAME @ mail IN CNAME @ ftp IN CNAME www |
I gdy chemy dodać dodać naszą domową/lokalną subdomenę tworzymy dodatkową pozycją:
1 |
home IN A ZZZ.ZZ.ZZ.Z |
Ale w naszym przypadku dodajemy home.domena.pl z informacją, że jest zarządzana osobno:
1 |
home IN NS dns1.domena.pl. |
Czyli „powiedzieliśmy”, że home.domena.pl będzie osobą strefą… Tak też zróbmy, w naszym pliku gdzie definiujemy strefy (np. etc/bind/named.conf.local) dodajemy stosowną informację:
1 2 3 4 5 6 |
zone "home.domena.pl" { type master; file "/etc/bind/M/home.domena.pl"; notify yes; allow-update { XXX.XXX.XXX.XX; key home.domena.pl; }; }; |
Jak widzicie pozwalamy na modyfikację domeny (allow-update) przez serwer XXX.XXX.XXX.XX, ale również wykorzystując klucz, który nazywa się home.domena.pl. Są to 2 różne sposoby na zabezpieczenie zmian w domenie przez niepowołane osoby.
Oczywiście bezpieczniejsza opcja to poprzez klucz szyfrujący i na tym się skupimy.
Algorytm klucza możemy dobrać wg uznania, dla ułatwienia wybierzemy „krótką” wersję (HMAC-MD5). Tworzymy odpowiedni katalog na klucze i generujemy:
1 2 3 |
mkdir /etc/bind/tsig cd /etc/bind/tsig dnssec-keygen -a HMAC-MD5 -b 128 -n HOST home.domena.pl |
W wyniku otrzymamy 2 pliki, z których interesuje nas zawartość pliku *.key:
1 2 3 4 5 |
Khome.domena.pl.+157+35440.key Khome.domena.pl.+157+35440.private cat Khome.domena.pl.+157+35440.key home.domena.pl. IN KEY 512 3 157 BFQTloe90QYscNMUpwptlQ== |
Naszym kluczem (TSIG) jest ciąg BFQTloe90QYscNMUpwptlQ== , któremu nadajemy odpowiednią nazwę, abyśmy mogli z niego korzystać.
W tym celu tworzymy plik z kluczami i informujemy o tym nasz serwer nazw. W pliku named.conf dodajemy:
1 |
include "/etc/bind/named.conf.tsig"; |
i tworzymy podany plik (named.conf.tsig) z odpowiednią wartością dla klucza i informacją o rodzaju klucza:
1 2 3 4 |
key "home.domena.pl" { algorithm hmac-md5; secret "BFQTloe90QYscNMUpwptlQ=="; }; |
Przeładowujemy BIND i możemy już aktualizować naszą strefę home.domena.pl uwierzytelniając się wprowadzonym kluczem lub uderzając z wprowadzonego adresu serwera
DDNS – serwer z PHP i request aktualizacyjny
Mamy przygotowane już zaplecze, pozostaje nam stworzyć fragment kodu, który będzie aktualizował strefę DNS. Jeśli mamy gdzieś dostępny serwer z PHP możemy posłużyć się takim fragmentem kodu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
/** * @param string $domain nazwa domeny, ktorej modyfikujemy wartosc A * @param string $secret klucz do podpisania zadania * @param string $ip adres IP ktory ma byc uzyty w rekordzie A * @param string $actualIP obecny adres IP z rekordu A * @param string $serverDns nazwa serwera nazw * @return mixed|null */ function updateDomain($domain, $secret, $ip, $actualIP, $serverDns) { if ($ip == $actualIP) { return null; } $nsUpdateParam = $secret ? ' -y hmac-md5:' . $secret : ''; $process = proc_open( 'nsupdate' . $nsUpdateParam, [ 0 => ['pipe', 'r'], 1 => ['pipe', 'w'], ], $pipes, NULL, NULL ); fwrite($pipes[0], 'server ' . $serverDns . "\n"); fwrite($pipes[0], 'update delete ' . $domain . ". A\n"); fwrite($pipes[0], 'update add ' . $domain . '. 2 A ' . $ip . "\n\n"); fclose($pipes[0]); echo stream_get_contents($pipes[1]) . PHP_EOL; $return = proc_close($process); if ($return == 0) { return $ip; } return null; } |
Prosty, ale w pełni funkcjonalny kod update.php dostępny na GitHub.
Jak widzicie korzystamy z PIPE-ów i polecenia dostępnego w większości systemów Linux – nsupdate (łącząc się, usuwając stary rekord A, dodając nowy rekord A).
Plik wystarczy umieścić gdzieś gdzie mamy PHP, może to być localhost.
Parametr secret składa się z 2 części: nazwy klucza i samego klucza. Możemy ten ciąg znaków uzyskać następująco posiłkując się danymi z miejsca, gdzie generowaliśmy klucz:
1 2 |
#nazwa_klucza:wartość_klucza php -r "echo rawurlencode('home.domena.pl:v/BFQTloe90QYscNMUpwptlQ==') . PHP_EOL;" |
Pozostaje nam już tylko uderzyć. Jeśli nasz router na to pozwala, lub jakiś lokalny serwer (np. NAS Synology) to tworzymy operację cykliczną (cron) z czasem ustawionym np. co 5 minut podając:
1 |
http://serwer_php/update.php?domain=home.domena.pl&secret=home.domena.pl%3Av%2FBFQTloe90QYscNMUpwptlQ%3D%3D |
Jeśli chcecie sprawdzić czy operacja się udała, możecie skorzystać z polecenia dig:
1 |
dig home.domena.pl A @dns1.domena.pl |
i zweryfikować aktualnie ustawione rekord A.