Linux環境でnslookupやdigコマンドでDNSを学ぶ

DNSを復習しようということで実際にnslookupコマンドやdigコマンドをやって確認した時のメモ

# 環境

+ Amazon Linux AMI 2015.09.2 (HVM)

# DNS(Domain Name Sysem)とは

かなりざっくり書きますので詳細は本などで確認して頂ければと思います。

 + TCP/IPで通信を行う場合には通信相手のIPアドレスを知る必要があるが、ドメイン名( www.yahoo.co.jp など)を入力してもブラウザではどのようなIPアドレスを示すか分からない
 + そこでドメイン名をIPアドレスに変換する必要がある。どのドメイン名をどのIPアドレスに変換すれば良いかはローカルのPCは分からない(/etc/hostsを使えばローカルでも設定できるが、変更時に併せてファイルの変更が必要)
 + そのため、ドメインとIPアドレスの変換はサーバーで行わせ、クライアントからのドメイン名変換依頼に対して対応するIPアドレスを返却するのがDNSサーバーの役目。ドメイン名からIPアドレスの変換は名前解決と呼ばれる
 + DNSサーバーには大きく分けて2種類ある。キャッシュDNSサーバーと権威DNSサーバー。キャッシュDNSサーバーをフルサービスリゾルバ、権威DNSサーバーをコンテンツサーバーと書いてあったりもする
 + キャッシュDNSサーバーはドメイン名とIPアドレスの結果をキャッシュする役割を持っている。キャッシュすることでクライアントへ結果の返却が早くできる
 + 権威DNSサーバーはIPアドレスとドメインの対応表を持っている。対応情報はAレコードと呼ばれる。キャッシュDNSサーバーからの名前解決の依頼に対して対応するIPアドレスを返却する
 + キャッシュDNSサーバーでキャッシュする時間はAレコードのTTLという値が利用される。この値が1秒毎に-1され、TTLが0になれば再度権威サーバーに問い合わせを行う

 
# nslookupコマンドを使って名前解決をしてみる
 
色々わかり難いので実際にコマンドを打って挙動などを確認していきましょう。
`nslookup`コマンドを使って **www.yahoo.co.jp** というドメイン名の名前解決を行ってみます。

```bash
$nslookup www.yahoo.co.jp
Server:		172.31.0.2
Address:	172.31.0.2#53
Non-authoritative answer:
www.yahoo.co.jp	canonical name = www.g.yahoo.co.jp.
Name:	www.g.yahoo.co.jp
Address: 182.22.70.250
Name:	www.g.yahoo.co.jp
Address: 183.79.27.149
Name:	www.g.yahoo.co.jp
Address: 183.79.197.242
Name:	www.g.yahoo.co.jp
Address: 183.79.198.240
```

色々結果が返却されました。
上から少しずつ見ていきます。

```bash
Server:     172.31.0.2
Address:    172.31.0.2#53
```

上記はクライアントPCから名前解決の要求を行ったDNSのIPアドレスとポート番号(ポート番号53)です。
問い合わせを行うDNSのIPアドレスは`/etc/resolv.conf`に記載されています。

```bash
$cat /etc/resolv.conf
; generated by /sbin/dhclient-script
search ap-northeast-1.compute.internal
nameserver 172.31.0.2
```

`nslookup`コマンドで返却された次の文はどのような意味でしょうか


```bash
Non-authoritative answer:
www.yahoo.co.jp	canonical name = www.g.yahoo.co.jp.
```

`Non-authoritative answer`については後述するので先に2行目の部分に説明します。

こちらには`canonical name`という記述があります。DNSサーバーではAレコード(IPアドレスとドメイン名の対応を示す情報を)を記述することでクライアントにドメインに対応するIPアドレスを返却できると書きました。そうなるとドメインとIPアドレスは1:1な気もしますが、複数のサブドメイン名でも同じIPアドレスを返却したい場合もあると思います。(実際あるかは置いておいて site.hogefuga.com と www.hogefuga.com で同じIPアドレスを返却したいなど )その場合、CNAMEレコードという情報をDNSサーバーに記述することで対応が可能です。CNAMEレコードは対応させたいサブドメイン名と対応するAレコードを記述することで複数サブドメインを定義できます。上記の例では

+ www.g.yahoo.co.jp というドメインに対するAレコードが4つ
+ www.yahoo.co.jp というドメイン名での名前解決の依頼がある場合、www.g.yahoo.co.jpのAレコードの情報を返却せよ、と意味するCNAMEレコードが1件

ということが分かります。

Aレコードとして登録されている`www.g.yahoo.co.jp`で名前解決をするとcanocial nameの記述がないことからも上記の状態であることがわかります。

```bash
$nslookup www.g.yahoo.co.jp
Server:		172.31.0.2
Address:	172.31.0.2#53

Non-authoritative answer:
Name:	www.g.yahoo.co.jp
Address: 183.79.75.234
Name:	www.g.yahoo.co.jp
Address: 183.79.139.228
Name:	www.g.yahoo.co.jp
Address: 183.79.11.230
Name:	www.g.yahoo.co.jp
Address: 183.79.43.200
```

次に`Non-authoritative answer`の部分を説明します。こちらはnon-authoritative answerという英語のように権威サーバーでないサーバーが回答した、ということを意味します。権威サーバーではないサーバーとなるとつまりキャッシュDNSサーバーが結果を返却した、ということになります。

権威サーバーに直接問い合わせを行えば記述が消えるはずなので、試しに問い合わせを行うDNSサーバーを172.31.0.2でなく、www.yahoo.co.jpのAレコードの情報を持つ権威サーバーに変えて試してみます。

```bash
# 引数なしで実行
$nslookup

# 問い合わせるDNSサーバーを変更
> server gns01.yahoo.co.jp.
Default server: gns01.yahoo.co.jp.
Address: 118.151.254.132#53

# 権威サーバー直接問い合わせているのでNon-authoritative answerの記述はない
> www.g.yahoo.co.jp.
Server:		gns01.yahoo.co.jp.
Address:	118.151.254.132#53

Name:	www.g.yahoo.co.jp
Address: 182.22.39.242
Name:	www.g.yahoo.co.jp
Address: 182.22.40.240
Name:	www.g.yahoo.co.jp
Address: 183.79.231.182
Name:	www.g.yahoo.co.jp
Address: 182.22.59.229
```

予想通り、Non-authoritative answerの記述は消えました。

では最後の以下の部分を確認しましょう。

```bash
Name:	www.g.yahoo.co.jp
Address: 182.22.70.250
Name:	www.g.yahoo.co.jp
Address: 183.79.27.149
Name:	www.g.yahoo.co.jp
Address: 183.79.197.242
Name:	www.g.yahoo.co.jp
Address: 183.79.198.240
```

先ほど www.yahoo.co.jp というドメイン名は　www.g.yahoo.co.jp の別名(CNAMEレコード)として登録されていることが分かりました。上記結果だけを見ると www.yahoo.co.jp に対する名前解決の依頼をしているのに www.g.yahoo.co.jp のドメインに対応するIPアドレスが4つ返却されているような気がしますが、CNAMEを定義しているので www.yahoo.co.jp = www.g.yahoo.co.jp であるため、返却されるIPアドレス群はwww.yahoo.co.jpに対応するIPアドレスと言え、解答としては合っているかと思います。

実際に返却されるIPアドレスを使ってGETリクエストをした場合でもYahooのトップページの情報を取得することができます。

```bash
$curl http://118.151.231.231
```

# digコマンドを使って名前解決してみる

`dig`コマンドを使っても名前解決ができるのですが、nslookupコマンドよりも詳細な情報が取得できます

```bash
$dig www.yahoo.co.jp

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.37.rc1.45.amzn1 <<>> www.yahoo.co.jp
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10130
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;www.yahoo.co.jp.		IN	A

;; ANSWER SECTION:
www.yahoo.co.jp.	556	IN	CNAME	www.g.yahoo.co.jp.
www.g.yahoo.co.jp.	16	IN	A	182.22.70.250
www.g.yahoo.co.jp.	16	IN	A	182.22.70.252
www.g.yahoo.co.jp.	16	IN	A	182.22.71.252
www.g.yahoo.co.jp.	16	IN	A	183.79.27.149

;; Query time: 1 msec
;; SERVER: 172.31.0.2#53(172.31.0.2)
;; WHEN: Mon Mar 21 22:15:45 2016
;; MSG SIZE  rcvd: 117
```

+ QUESTION SECTIONで問い合わせ内容を表示。オプションをつけない場合、引数に指定されたドメイン名のAレコードの問い合わせを行う(オプションで違うレコード情報の要求も可能)
+ ANSWER SECTIONで問い合わせに対する結果を表示。CNAMEレコード情報が1件、Aレコード情報が4件返却されている
+ 末尾にどのDNSサーバーへ問い合わせを行ったかなどを表示。

こちらの方が情報が多く分かりやすいので、デバッグを行う際にはdigコマンドの方が良いかと思います。