Dla pełnego obrazu problemu i rozwiązania muszę naszkicować sytuację w naszej sieci firmowej.
Mamy kilkanaście oddziałów rozrzuconych po Polsce i mamy kilkuset użytkowników laptopów, z czego wielu przemieszcza się między różnymi oddziałami.
Oddziały mają rózne klasy adresowe /16, adresy są przydzielane przez DHCP na podstawie adresu MAC.
Wszystkie komputery zapisane są w bazie danych jako (nazwa, adres-IP, adres-MAC). Pole adres-IP definiuje młodsze szesnaście bitów 32-bitowego adresu IP, czyli to, co dostał każdy oddział. Z tej właśnie bazy mamy mapowanie adresów MAC-IP.
Dla przykładu załóżmy, że mamy komputer rudolf o adresie IP x.x.10.20, to w oddziałach z sieciami 172.16.0.0/16 i 172.18.0.0/16 rudolf dostanie adresy, odpowiednio, 172.16.10.20 i 172.18.10.20.
Każdy z komputerów ma zainstalowany serwer UltraVNC, żeby informatycy znajdujący się w centrali mogli bez problemów pomagać użytkownikom znajdującym się w innym mieście. Dla jeszcze większego ułatwienia został napisany frontend dla VNC viewera. Ten frontend pobiera listę komputerów z bazy i prezentuje ją operatorowi pozwalając wybrać, z którym komputerem ma się połączyć.
Przydałoby się mieć jakiś stały element, który pozwoli dostać się do komputera niezależnie od aktualnego miejsca pracy użytkownika. Użytkownicy przemieszczają się między sieciami, więc nie można wklepać do bazy pełnego adresu IP. Tu z pomocą przychodzą dynamiczne aktualizacje wybranej strefy DNS wykonywane przez serwer DHCP (schemat interim, jako ten zalecany przez dokumentację ISC DHCP i jedyny obsługiwany przy statycznych dzierżawach).
Tłumaczyć jak skonfigurować do tego serwer DHCP nie mam zamiaru, choćby wspomniana dokumentacja przyzwoicie to wyjaśnia. Wspomnę tylko, że nazwy pakowane do DDNS są wybierane przez serwer, nie przez klienta (opcja ddns-hostname w definicji każdego hosta i update-static-leases on w sekcji globalnej).
Ciekawy jest natomiast problem, który się dla tej konfiguracji pojawia. Przy statycznie skonfigurowanych przydziałach adresów IP dhcpd nie kasuje wpisów DNS (man dhcpd.conf, opcja update-static-leases). Gdy wymieniany jest cały komputer, czyli gdy zupełnie inna maszyna dostaje wcześniej używaną nazwę, aktualizacja DDNS nie powodzi się. Okazuje się, że identyfikator maszyny (tytułowy DHCID), który jest zapisywany w rekordzie TXT, dla jednego i drugiego komputera jest różny, a dhcpd zamienia wpisy w DNS tylko gdy maszyna, która dostała dzierżawę, ma taki sam identyfikator jak ten zapisany w DNS albo gdy rekord A o tej samej nazwie w DNS nie istnieje. Gdy rekord A jest obecny, a w rekordzie TXT znajduje się coś innego albo tego rekordu w ogóle nie ma, DNS nie jest uaktualniany.
Najlepsze rozwiązanie, na jakie wpadłem, polega na regularnym sprawdzaniu, czy DHCID w DNS zgadza się z tym, który dostanie komputer o odpowiedniej nazwie, i ewentualnym kasowaniu par rekordów A i TXT, jeśli DHCID z TXT się nie zgadza.
Łatwiej powiedzieć niż zrobić, bo rzeczony DHCID trzeba najpierw umieć generować. W sieci nijak nie mogłem znaleźć algorytmu, a draft RFC i sam RFC 4701 o rekordach dla DHCP nie przystają do tego co robi ISC DHCP. Trzeba było zastosować metodę dozziego: tar zxf dhcp-*.tar.gz; cd dhcp-*; vim *.c.
Na efekt kopania w kodzie źródłowym trzeba było czekać cztery godziny. Okazało się, że w rekordach TXT zapisywana jest szesnastkowo zapisana suma MD5 pewnych danych poprzedzona bajtem 0x00 albo 0x31 (nie wnikałem od czego ten bajt zależy). Danymi, którymi jest nakarmiony algorytm MD5, jest bajt 0x01 (raz się zdarzył 0x00, znowu nie wnikałem dlaczego akurat tak) i doklejony do niego adres MAC komputera, zapisany jako sześciobajtowy string. A obrazowo, dane z rekordu TXT można porównać tak:
#!/usr/bin/perl -l
use Digest::MD5 qw/md5_hex/;
my $mac = '00:0C:6B:7A:E8:70';
print "expected: 31b717509e296b7b34587f80910a641021";
my $data = "\x01";
#my $data = "\x00"; # tylko raz mi sie zdarzylo ze bylo trzeba uzyc tego
$data .= chr hex $_ for split /:/, $mac;
print "computed: 31" . md5_hex($data);
# drugi wariant:
#print "computed: 00" . md5_hex($data);
Jeśli się odetnie dwa pierwsze heksy, zostają tylko dwie możliwości: $data zaczęta od 0x01 (częstsza sytuacja) albo od 0x00 (znalazłem tylko jedną taką). Dzięki temu co godzinę można uruchomić sprawdzanie, czy któryś z rekordów TXT nie jest czasem nieaktualny.
Dla kompletności wpisu dodam, że usuwanie wpisów DDNS można spokojnie załatwić narzędziem nsupdate z dystrybucji BIND-a.