embryo

エンジニアの備忘録

DNSの仕組みと調査方法について

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

名前解決の方法

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

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

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

DNSによる名前解決

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

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

f:id:sue71:20171121143038p:plain
ドメインツリー

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

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

f:id:sue71:20171121152115p:plain
DNS解決の流れ

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

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

f:id:sue71:20171121143044p:plain
キャッシュが存在している場合

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

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

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

f:id:sue71:20171121143047p:plain
プライマリ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

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

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を正しく設定していれば問題ないようです。 具体的には下記のような手順で移行することで、短時間でドメインの移行を完了することができます。

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

今回の件で調査したこと

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

キャッシュの確認

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

プライマリDNSの確認

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

まとめ

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

参考