DNS and OS
DNS クエリが生成されるまで
curl や ping, dig などは、ホスト名に対して実行できる。 nsswitch.conf を見て hosts を見て resolve.conf を見て〜という流れ以上の粒度で、実際のところ何がどういう順序で実行され、 DNS クエリとして飛んでいくのかの挙動を追う。
strace からの調査
▼ ping コマンド実行時の strace
# strace -e trace=open -f ping -c 1 yokohei.com
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libcap.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libidn.so.11", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/lib64/libattr.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/etc/host.conf", O_RDONLY|O_CLOEXEC) = 4
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 4
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 4
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
open("/lib64/libnss_files.so.2", O_RDONLY|O_CLOEXEC) = 4
open("/etc/hosts", O_RDONLY|O_CLOEXEC) = 4
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
open("/lib64/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = 4
open("/lib64/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 4
PING yokohei.com (54.192.29.155) 56(84) bytes of data.
open("/etc/hosts", O_RDONLY|O_CLOEXEC) = 4
64 bytes from 54.192.29.155: icmp_seq=1 ttl=242 time=1.02 ms
--- yokohei.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.025/1.025/1.025/0.000 ms
+++ exited with 0 +++▼ dig コマンド実行時の strace
ping の時は nsswitch.conf が呼ばれているが、 dig のときは呼ばれない。
dig は DNS クエリを生成するためのツールなので、 nsswitch.conf を見る必要はない、ということかな。
なお、どちらも resolv.conf は呼んでいる。
nsswitch.conf
いろいろなカテゴリーの「名前」サービスの情報を、どの情報源からどういう順序で取得するかを決めるためのもの。 DNS に関する「名前」は hosts のデータベースとして扱われる。
/etc/nsswitch.conf ---- ... hosts: files dns ... ----
今回の例では、 ping の場合はこれが呼ぶようにマッピングされてた。
なので、 /etc/nsswitch.conf を書き換えて、 hosts: files だけにすると、 DNS 名前解決が使えなくなる。
逆に hosts: dns にすると hosts にかかれている localhost が引けなくなる。
以下のようなイメージ図。

ping.c
iputils http://www.skbuff.net/iputils/
iputils/ping.c より一部抜粋
iputils/ping6.c より一部抜粋
ping6 では IPv6 に対応するため getaddrinfo が利用されている。
gethostbyname()
man gethostbyname より抜粋
The domain name queries carried out by gethostbyname() and gethostbyaddr() rely on the Name Service Switch (nsswitch.conf(5)) configured sources or a local name server (named(8)). The default action is to query the Name Service Switch (nsswitch.conf(5)) configured sources, failing that, a local name server (named(8)).
gethostbyname() 自体が、 nsswitch.conf によって設定を決められる。 ソースコードもちゃんと見たい。
getaddrinfo()
gethostbyname はもう古い、いまは getaddrinfo を見よ、とのこと。(by man page)
参考資料
Anatomy of a Linux DNS Lookup https://zwischenzugs.com/2018/06/08/anatomy-of-a-linux-dns-lookup-part-i/
Domain name resolution https://wiki.archlinux.org/index.php/Domain_name_resolution
Tracing Linux Hostname Resolution https://www.kickflop.net/blog/2011/01/02/tracing-linux-hostname-resolution/
Linux Programmer's Manual RESOLV.CONF(5) http://man7.org/linux/man-pages/man5/resolv.conf.5.html
getaddrinfo - ライブラリコールの説明 https://kazmax.zpp.jp/cmd/g/getaddrinfo.3.html
6.4 Protocol-Independent Nodename and Service Name Translation - RFC 2553 https://tools.ietf.org/html/rfc2553#section-6.4
Last updated