仕事で外部のエンジニアに依頼したドメイン移行が正しく動作していなかったため、良い機会と思いDNSについて調べました。

名前解決の方法

そもそも名前解決とは何かというと、ドメインとIPアドレスを紐付けることです。手法として以下の2つが上げられます。

/etc/hostsに直接対応を記述する方法

/etc/resolve.confにDNSサーバーのIPアドレスを記述し、問い合わせる方法

今回はDNSサーバーによる名前解決について説明していきます。

DNSによる名前解決

ドメインツリーによる負荷分散

全世界に無数に存在するドメインの解決を一台のネームサーバーで担当するのは不可能です。そこでDNSでは下記のように、各階層に意味を持たせ、下位のドメインを管理させることで分散型の構造を構築しています。

ドメインツリー

キャッシュサーバーによる高速化

クライアントからDNSサーバーに対してドメインを問い合わせる場合、実際には直接情報(レコード)を保存しているサーバー(=コンテンツサーバー)に問い合わせるのではなく、それぞれのコンテンツサーバーとのやり取りを仲介するサーバー(=キャッシュサーバー)を介して行われます。

DNS解決の流れ

クライアントからキャッシュサーバーへ問い合わせを開始する キャッシュサーバーがルートサーバーへ問い合わせる ルートサーバーからjpを管理するネームサーバーのアドレスが返却される jpを管理するネームサーバーに問い合わせる example.jpを管理するネームサーバーのアドレスが返却される example.jpを管理するネームサーバーへ問い合わせる example.jpのIPアドレス(Aレコード)が返却される

上図のようにルートサーバーから順に問い合わせていくのが基本的な流れですが、毎回この手順を踏むのでは速度面のロスがあるので、キャッシュサーバーは一度取得したレコードを一定期間保存し、キャッシュが存在している場合にはすぐさまクライアントに応答します。

キャッシュが存在している場合

キャッシュの生存期間としてTTLが用いられ、時間を超過すると再度権威サーバーへと問い合わせます。

プライマリ/セカンダリDNSによる冗長化

コンテンツサーバーは普通複数台存在します。プライマリ/セカンダリDNSと呼ばれ、プライマリDNSがなんらかの理由で応答しない場合にセカンダリDNSを参照します。セカンダリDNSはプライマリDNSのレコードをコピーして保持するため常に同期された状態になりますが、プライマリDNSのレコードを更新する際にシリアルナンバーを更新してセカンダリDNSに更新されていることを伝える必要があります。(異なった仕様のものもあるようです)

プライマリDNSとセカンダリDNS

digで名前解決してみる

dig コマンドを使用して実際に名前解決してみます。 nslookup コマンドでもIPアドレスを引くことは出来ますが dig コマンドの方がより詳細に情報を取得できます。 (他にもいくつか挙動が異なる点がありますが割愛します)

>>dig google.com ; <<>> DiG 9.8.3-P1 <<>> google.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19537 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 4 ;; QUESTION SECTION: ;google.com. IN A ;; ANSWER SECTION: google.com. 186 IN A 172.217.26.46 ;; AUTHORITY SECTION: google.com. 55214 IN NS ns3.google.com. google.com. 55214 IN NS ns4.google.com. google.com. 55214 IN NS ns2.google.com. google.com. 55214 IN NS ns1.google.com. ;; ADDITIONAL SECTION: ns1.google.com. 39695 IN A 216.239.32.10 ns2.google.com. 39695 IN A 216.239.34.10 ns3.google.com. 39695 IN A 216.239.36.10 ns4.google.com. 39695 IN A 216.239.38.10 ;; Query time: 3 msec ;; SERVER: 192.168.2.1#53(192.168.2.1) ;; WHEN: Mon Nov 6 14:52:59 2017 ;; MSG SIZE rcvd: 180

各出力項目について

重要な出力について説明していきます。

status

名前解決の状態に関する項目です。上記出力では NOERROR となっているため、正常に名前解決が行われたことを意味します。 他には NXDOMAIN などが表示されることがありますが、この場合は指定したドメインが存在しないことになります。

flags

応答の意味が表示されています。それぞれ下記の意味を示しています。上記応答は qr rd ra となっているため、サーバーからの応答で、なおかつキャッシュサーバーによる応答であり、キャッシュサーバーは再帰的問い合わせに対応している、ということがわかります。

aa: コンテンツサーバーからの応答であることを示します

qr: サーバーからの応答であることを示します。DNSでの名前解決では必ずこのフラグが付いています。

rd: 再帰的問い合わせの結果であることを示します

ra: 再帰的問い合わせが可能であることを示します

ANSWER SECTION

問い合わせに対するレスポンスになります。google.comのIPアドレスが得られている事がわかります。二列目の値が残りのTTLになります。このTTLが切れた場合に再度コンテンツサーバーに問い合わせることになります。

google.com. 186 IN A 172.217.26.46

AUTHORITY SECTION

コンテンツサーバー(権威サーバー)のドメイン情報が表示されています。この中から１つが選択され、再帰的に問い合わせが行われます。

google.com. 55214 IN NS ns3.google.com. google.com. 55214 IN NS ns4.google.com. google.com. 55214 IN NS ns2.google.com. google.com. 55214 IN NS ns1.google.com.

ADDITIONAL SECTION

付加情報が表示される項目です。ネームサーバーが返却された場合、ネームサーバーのIPアドレスなどが付加情報として返却されます。

ns1.google.com. 39695 IN A 216.239.32.10 ns2.google.com. 39695 IN A 216.239.34.10 ns3.google.com. 39695 IN A 216.239.36.10 ns4.google.com. 39695 IN A 216.239.38.10

digの使い方いろいろ

実際にどのような使い方があるのかを、今回調査に使用したものを中心に紹介します。

非再帰的問い合わせ

通常digコマンドでは再帰的に問い合わせが行われていますが、 +norec オプションを付加することで、たらい回す先のDNSサーバーを返すようになります。

>> dig google.com +norec ; <<>> DiG 9.8.3-P1 <<>> google.com +norec ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42047 ;; flags: qr ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 4 ...

flagsからrdの項目が消えていることがわかります。

問い合わせるネームサーバーを指定する

@DNSサーバーアドレス を使用することで、ネームサーバーを直接指定して名前解決を行うことができます。またキャッシュサーバーではなくコンテンツサーバーを指定した場合、再帰的問い合わせを行うことはできないので、自身が管理するレコードのみを返すことになります。

>> dig google.com @ns1.google.com ; <<>> DiG 9.8.3-P1 <<>> google.com +norec @ns1.google.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14958 ;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;google.com. IN A ;; ANSWER SECTION: google.com. 300 IN A 172.217.26.46 ;; Query time: 75 msec ;; SERVER: 216.239.32.10#53(216.239.32.10) ;; WHEN: Mon Nov 20 19:50:46 2017 ;; MSG SIZE rcvd: 44

flagsにaaと表示されているのがわかります。

再帰的問い合わせの状況を確認する

+trace オプションを付加することで、再帰的問い合わせの状況を追うことができます。浸透状況を疑う場合はこのコマンドを実行すると良さそうです。 下記出力ではルートサーバーから順に問い合わせている状態が確認できます。

>> dig google.com +trace ; <<>> DiG 9.8.3-P1 <<>> google.com +trace ;; global options: +cmd . 152273 IN NS f.root-servers.net. . 152273 IN NS l.root-servers.net. . 152273 IN NS e.root-servers.net. . 152273 IN NS j.root-servers.net. . 152273 IN NS d.root-servers.net. . 152273 IN NS b.root-servers.net. . 152273 IN NS g.root-servers.net. . 152273 IN NS i.root-servers.net. . 152273 IN NS h.root-servers.net. . 152273 IN NS c.root-servers.net. . 152273 IN NS a.root-servers.net. . 152273 IN NS k.root-servers.net. . 152273 IN NS m.root-servers.net. ;; Received 492 bytes from 192.168.2.1#53(192.168.2.1) in 10 ms ;; Truncated, retrying in TCP mode. com. 172800 IN NS l.gtld-servers.net. com. 172800 IN NS b.gtld-servers.net. com. 172800 IN NS c.gtld-servers.net. com. 172800 IN NS d.gtld-servers.net. com. 172800 IN NS e.gtld-servers.net. com. 172800 IN NS f.gtld-servers.net. com. 172800 IN NS g.gtld-servers.net. com. 172800 IN NS a.gtld-servers.net. com. 172800 IN NS h.gtld-servers.net. com. 172800 IN NS i.gtld-servers.net. com. 172800 IN NS j.gtld-servers.net. com. 172800 IN NS k.gtld-servers.net. com. 172800 IN NS m.gtld-servers.net. ;; Received 824 bytes from 192.5.5.241#53(192.5.5.241) in 13 ms google.com. 172800 IN NS ns2.google.com. google.com. 172800 IN NS ns1.google.com. google.com. 172800 IN NS ns3.google.com. google.com. 172800 IN NS ns4.google.com. ;; Received 164 bytes from 192.54.112.30#53(192.54.112.30) in 152 ms google.com. 300 IN A 172.217.27.78 ;; Received 44 bytes from 216.239.34.10#53(216.239.34.10) in 38 ms

ルートサーバーから順に問い合わせている様子がわかります。

プライマリDNSサーバーを確認する

soa をオプションとして付加することで、プライマリDNSサーバーを調べることができます。

>> dig google.com soa ; <<>> DiG 9.8.3-P1 <<>> google.com soa ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47193 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 4 ;; QUESTION SECTION: ;google.com. IN SOA ;; ANSWER SECTION: google.com. 60 IN SOA ns1.google.com. dns-admin.google.com. 176366135 900 900 1800 60 ;; AUTHORITY SECTION: google.com. 151698 IN NS ns3.google.com. google.com. 151698 IN NS ns4.google.com. google.com. 151698 IN NS ns1.google.com. google.com. 151698 IN NS ns2.google.com. ;; ADDITIONAL SECTION: ns1.google.com. 324498 IN A 216.239.32.10 ns2.google.com. 324498 IN A 216.239.34.10 ns3.google.com. 324498 IN A 216.239.36.10 ns4.google.com. 324498 IN A 216.239.38.10 ;; Query time: 37 msec ;; SERVER: 192.168.2.1#53(192.168.2.1) ;; WHEN: Tue Nov 21 11:48:38 2017 ;; MSG SIZE rcvd: 210

ns1.google.com がプライマリDNSサーバーであることがわかります。

TTLと浸透時間について

ドメインの移行が上手く行っていない際に「浸透時間が〜」という話を良く耳にしますが、基本的にはTTLを正しく設定していれば問題ないようです。 具体的には下記のような手順で移行することで、短時間でドメインの移行を完了することができます。

現在のTTLを確認する。例えば86400(24時間)と設定されていると仮定します。 移行前にTTLを300(5分)に設定します。 現在のTTLが86400となっているため、24時間以上の時間を置きます。 キャッシュサーバーに保存されるTTLが300になっているはずなのでレコードの更新を行います。(TTLは長い時間を設定しても問題ありませんが、ミスが起きたときのために短い時間を設定しておくのが良いです)

今回の件で調査したこと

最後に今回問題を調査するにあたって、どのように問題解決に至ったかをメモしました。

キャッシュの確認

まず、キャッシュサーバーが古いドメインを返しているのではと思い、 +trace オプションを使用して経路を確認しました。レコードが登録されているであろうネームサーバーまでは到達していましたが、最終的に到達するドメインが古いものになっている状態でした。しかしTTLには十分短い時間が設定されていたため、TTL設定の不備では無さそうです。

プライマリDNSの確認

次に soa オプションを使用して到達している複数のネームサーバーの中からプライマリDNSを確認します。プライマリDNSがわかったので直接指定して確認したところ、そちらの方では新しいドメインに向いていました。そこでプライマリDNSとセカンダリDNSの同期が上手くなされていないのではと思い、担当者に調査をお願いした所、プライマリDNSのシリアルナンバーを更新していなかったことがわかりました。

まとめ

DNSの仕組みと問題が起きた際の調査方法について説明しました。DNSの仕組みを理解していればある程度問題が予測できそうです。

参考