niedziela, 18 marca 2012

DNS i dopełnianie nazw hostów

Od dosyć dawna Bash posiada wsparcie dla dopełniania nazw plików, jednak nie wszyscy zdają sobie sprawę, że dopełniać klawiszem TAB możemy praktycznie wszystko. Jest to mechanizm wysoce konfigurowalny i wiele dystrybucji posiada skrypt /etc/bash_completion który definiuje specjalne dopełnianie dla wielu popularnych poleceń - np dopełnianie opcji. Krótkie wprowadzenie można znaleźć tutaj - część pierwsza i druga.

W codziennej pracy administratora na pewno bardzo przydatną opcją jest dopełnianie nazw hostów. Doszukamy się nawet gotowego rozszerzenia dla ssh, scp i innych poleceń - zwykle wystarczy zainstalować tylko pakiet bash-completion. Rozszerzenie to potrafi nawet dopełniać w poleceniu scp nazwy plików i katalogów na zdalnym hoscie!

Cały mechanizm jest świetny, ale jak zapewne się już domyślacie jest jedna rzecz którą chce poprawić :) Dopełnianie nazw hostów bazuje na urządzeniach/komputerach do których już się zalogowaliśmy (poprzez ssh), lub takich które mamy zapisane w plikach hosts (np. /etc/hosts). Takie rozwiązanie nie sprawdza się w dużym środowisku, gdzie bardzo często logujemy się do hostów na których wcześniej nie byliśmy, dodatkowo dokładanych jest cały czas sporo maszyn a inne są usuwane.

Można ten problem rozwiązać instalując avahi... ale jest to trochę jak strzelanie z armaty do muchy, a dodatkowo musielibyśmy wprowadzić ten pakiet na większość maszyn.

Dla mnie idealnym rozwiązaniem jest dopełnianie nazw hostów bezpośrednio z serwera dns... jak? Po pierwsze musimy jakoś te nazwy wydobyć. Z pomocą przychodzi nam tutaj polecenie rndc dumpdb -zones które potrafi wylistować wszystkie strefy i zapisać je w pliku named_dump.db. Jest to plik tekstowy, który nadaje się idealnie do dalszej obróbki. Wykonujemy zatem polecenia dzięki którym wygenerujemy listę wszystkich hostów i stref zdefiniowanych w naszym lokalnym serwerze DNS:

# ssh root@zlomex.local "rndc dumpdb -zones; cat /var/cache/bind/named_dump.db" > named_dump.db
# sed -ne '/in-addr.arpa/d; s/^\([[:alnum:].-]\+\)\..*IN.*/\1/p' named_dump.db | sort | uniq > named_hosts.db
# rm named_dump.db

Mój serwer DNS to oczywiście zlomex.local :) Polecenia te najlepiej ustawić jako cyklicznie wykonywane zdanie cron, zwłaszcza jeżeli używamy do autentykacji kluczy ssh - nie musimy wtedy podawać hasła. Plik named_hosts.db zawiera teraz listę hostów:

local
localhost
test.local
wpad.local
zlomex.local

Następnie modyfikujemy standardowy skrypt dopełniający nazwy hostów, tak by uwzględnił zawartość pliku named_hosts.db. Edytujemy zatem /etc/bash_completion i szukamy funkcji _known_hosts_real() używanej do dopełniania nazw hostów. Przy końcu tej funkcji, ale przed wywołaniem __ltrim_colon_completions, dokładamy kilka linijek przeszukujących dodatkowo nasz plik named_hosts.db. Końcówka funkcji powinna zatem wyglądać podobnie jak poniżej:

named_hosts=$( grep "$cur" /etc/named_hosts.db )
if [ -n "$named_hosts" ]; then
COMPREPLY=( "${COMPREPLY[@]}" $named_hosts )
fi

__ltrim_colon_completions "$prefix$user$cur"

return 0
}

ps: Jeżeli nie mamy dostępu poprzez ssh do maszyny, możemy spróbować jeszcze polecenia listującego całą strefe, np dig @zlomex.local local axfr.

ps2: W ostateczności można również przelecieć poleceniem sed pliki konfiguracyjne binda ;)