Resolver i NSS

Resolver w systemie operacyjnym odpowiada za tłumaczenie nazw domenowych na adresy IP. Jest to tak naprawdę zbiór bibliotek systemowych służących do rozwiązywania nazw. Posiada własne pliki konfiguracyjne /etc/resolv.conf który jest zapewne znany dla większości użytkowników Linuksa, /etc/hosts, bardzo często edytowany na potrzeby różnych testów, oraz /etc/host.conf chyba najrzadziej dotykany, ponieważ obowiązuje dla starej wersji biblioteki libc. Nad całością czuwa NSS (Name Service Switch) który pojawił się w libc'ach od wersji 5. Przede wszystkim to właśnie konfiguracja NSS (/etc/nsswitch.conf), mówi o sposobie w jaki należy zrealizować rozwiązanie nazwy i nie chodzi tu jedynie o DNS ale również o takie podstawowe elementy systemu jak użytkownicy (passwd, group, shadow), protokoły sieciowe, itd... te usługi muszą być tłumaczone w jakiś sposób, np. użytkownicy na UID, grupy na GID a protokoły na porty. Wszystkie te pliki tworzą jedną całość pozwalającą na swobodną pracę w Internecie.

Spróbuję od początku przedstawić jak odbywa się proces zamiany hosta na IP i który plik dokładnie na co ma wpływ. Zaczynając od /etc/hosts, jest to statyczna tabela zawierającą adres IP oraz HOST z nim powiązany, jest to plik do którego najczęściej sięgamy kiedy chcemy jakiejś domenie przypisać zupełnie inny IP, np. na czas testów. Za przykład posłuży taki wpis:

# /etc/hosts

127.0.0.1 google.com www.google.com

ta linijka spowoduje, że odwołując się do domeny google.com/www.google.com (np. wpisując w przeglądarce adres) resolver skieruje nas do 127.0.0.1, a nie do prawdziwego serwera Google, dzieje się tak ponieważ NSS posiada zdefiniowaną kolejność w której będzie sprawdzał hosty, przyjrzyjmy się plikowi /etc/nsswitch.conf

# /etc/nsswitch.conf

passwd: compat
group: compat
shadow: compat
hosts: files dns
networks: files
protocols: db files
services: db files
ethers: db files
rpc: db files
netgroup: nis

taki zapis, mówi, że obsługa rozwiązywania nazw (hosts: files dns), powinna odbywać się w kolejności, pliki (/etc/hosts) a dopiero w przypadku niepowodzenia, należy przekazać żądanie do zewnętrznych serwerów DNS zdefiniowanych w pliku /etc/resolv.conf:

# /etc/resolv.conf

search pl
nameserver 195.205.203.2
nameserver 194.204.159.1

  • search pl - określa człon domeny (w tym przypadku pl) który będzie doklejany do hosta jeśli nasze zapytanie nie będzie zawierało przynajmniej jednej kropki
  • nameserver 195.205.203.2 - pierwszy zewnętrzny serwer DNS który będzie odpytywany
  • nameserver 194.204.159.1 - drugi zewnętrzny serwer DNS, odpytywany w przypadku kiedy pierwszy zawiedzie

Trochę wyjaśnienia dla parametru search pl:

# host varlog
varlog.pl has address 195.205.203.232
varlog.pl mail is handled by 10 aspmx4.googlemail.com.
varlog.pl mail is handled by 10 aspmx5.googlemail.com.
varlog.pl mail is handled by 1 aspmx.l.google.com.
varlog.pl mail is handled by 5 alt1.aspmx.l.google.com.
varlog.pl mail is handled by 5 alt2.aspmx.l.google.com.
varlog.pl mail is handled by 10 aspmx2.googlemail.com.
varlog.pl mail is handled by 10 aspmx3.googlemail.com.

pomimo tego, że odpytaliśmy o domenę varlog, resolver dokleił .pl i całe zapytanie wyglądało tak:

# tcpdump -ni eth0 port 53
10:50:51.562311 IP 195.205.203.232.47005 > 195.205.203.2.53: 18839+ A? varlog.pl. (27)
10:50:51.583712 IP 195.205.203.2.53 > 195.205.203.232.47005: 18839 1/9/8 A 195.205.203.232 (351)

gdybyśmy chcieli odpytać tylko o hosta varlog, tak by resolver nie doklejał nic od siebie musimy dodać kropkę na końcu:

# host varlog.
Host varlog. not found: 3(NXDOMAIN)

# tcpdump -ni eth0 port 53
10:52:47.538299 IP 195.205.203.232.43781 > 195.205.203.2.53: 5424+ A? varlog. (24)
10:52:47.539653 IP 195.205.203.2.53 > 195.205.203.232.43781: 5424 NXDomain 0/1/0 (99)

Dlaczego tak się dzieje? Resolver daje możliwość określenia ile kropek w nazwie domeny musi się znajdować, aby search nie był brany pod uwagę, ten parametr domyślnie wynosi 1, dlatego odpytanie o varlog spowodowało doklejenie .pl a odpytanie o varlog. już nie. Za ilość kropek odpowiada parametr ndots, który jest konfigurowany w /etc/resolv.conf:

# /etc/resolv.conf

options ndots:n

n - jest liczbą kropek która musi wystąpić w zapytaniu.

Na koniec jeszcze jeden ciekawy przykład, dodajemy wpis w /etc/hosts:

# /etc/hosts

127.0.0.1 testtesttest.pl

Spróbujmy wykonać polecenie host testtesttest.pl

# host testtesttest.pl
Host testtesttest.pl not found: 3(NXDOMAIN)

Polecenie host nic nam nie zwróciło... a wpis znajduje się w /etc/hosts... teraz dla odmiany ping testtesttest.pl

# ping -c 3 testtesttest.pl
PING testtesttest.pl (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.031 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.028 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.033 ms

--- testtesttest.pl ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.028/0.030/0.033/0.006 ms

Dziwne? ;-) wynika to z tego, że polecenie host nie korzysta z gethostbyname() do zamiany nazwy na IP, czyli przez to nie korzysta w ogóle z NSS'a. Pomija przez to /etc/hosts i od razu wysyła żądanie do zewnętrznych serwerów DNS. Dlatego ping, telnet zadziała, a host już nie...

Więcej informacji:

  • man resolv.conf
  • man host.conf
  • man hosts
  • man nss
  • man nsswitch.conf
  • man gethostbyname

Warto zapamiętać, że resolver systemowy nie jest daemonem ani usługą... jest tak naprawdę zbiorem bibliotek systemowych, które często nawet nieświadomie są pośrednio przez nas używane, siedzą gdzieś ukryte w systemie i odwalają za nas kawał dobrej roboty... ;-)