AWS EC2 (Ubuntu) で DNS のスタブリゾルバ 127.0.0.53 と Amazon Provided DNS の関連を確認する

# はじめに
AWS で VPC を構築した時、VPC 内のインスタンスが参照する DNS サーバ ( Amazon Provided DNS ) のアドレスは 「 VPC のネットワークアドレス + 2 」です。
例えば VPC のネットワークアドレスが 10.0.0.0 であれば、DNS サーバのアドレスは 10.0.0.2 です。
[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_Subnets.html)に書いてあるので、間違いありません。

しかし、EC2 インスタンスの OS を Ubuntu とした場合、参照先の DNS サーバはデフォルトで **127.0.0.53** となっているように見えます。
本記事では、この **127.0.0.53** について深堀りし、Amazon Provided DNS との関連を確認した結果を備忘録としてまとめます。

# 想定される参照先 DNS サーバのアドレス

検証用のクライアント (EC2) のプライベート IP アドレスは、以下で示されるように 172.31.43.50 で、VPC のネットワークアドレスは 172.31.0.0 です。
この時、通常は参照先の DNS サーバのアドレスが **172.31.0.2** であるはずです。

```bash
$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 06:72:1e:15:cd:f4 brd ff:ff:ff:ff:ff:ff
    inet 172.31.43.50/20 brd 172.31.47.255 scope global dynamic ens5
       valid_lft 1986sec preferred_lft 1986sec
    inet6 fe80::472:1eff:fe15:cdf4/64 scope link 
       valid_lft forever preferred_lft forever
```

# まずは nslookup で検証

Ubuntu OS の設定上、どこの DNS サーバを参照しているかは、適当に `nslookup` すると分かります。
以下の通り、nslookup を打った時に参照しているアドレスは **127.0.0.53** で、Amazon Provided DNS の IP アドレスではありません。
この 127.0.0.53 は、ローカルアドレスに見えますが、一体何者なのでしょうか。

```bash
$ nslookup amazonaws.com                                                                 
Server:         127.0.0.53
Address:        127.0.0.53#53

Non-authoritative answer:
Name:   amazonaws.com
Address: 72.21.206.80
Name:   amazonaws.com
Address: 207.171.166.22
Name:   amazonaws.com
Address: 72.21.210.29
```

# /etc/resolv.conf を見る

DNSと言えば /etc/resolv.conf であり、ここを見れば 127.0.0.53 の正体も分かるだろうと思い、覗いてみました。

ひとまず `ls` してみるのですが、ここで resolv.conf がシンボリックリンクになっていることが判明します。

```bash
$ ls -l /etc/resolv.conf
lrwxrwxrwx 1 root root 39  9月 13  2018 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
```

さて、肝心の resolv.conf を読むと **127.0.0.53** と書いてあるだけです。

```bash
$ cat /etc/resolv.conf                                                                             
# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients to the
# internal DNS stub resolver of systemd-resolved. This file lists all
# configured search domains.
#
# Run "systemd-resolve --status" to see details about the uplink DNS servers
# currently in use.
#
# Third party programs must not access this file directly, but only through the
# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,
# replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.

nameserver 127.0.0.53
options edns0
search ap-northeast-1.compute.internal
```

しかし、この設定ファイルのコメントをよく読むと、手がかりが見えてきました。
コメントには次のように書かれています。

```text
This is a dynamic resolv.conf file for connecting local clients to the internal DNS stub resolver of systemd-resolved. 
This file lists all configured search domains.
Run "systemd-resolve --status" to see details about the uplink DNS servers currently in use.
```

コメントには resolv.conf の設定が内部の DNS スタブリゾルバである **systemd-resolved** に接続するためのものと書かれています。
おそらく systemd-resolved が IP アドレス 127.0.0.53 を持っていそうです。
また `systemd-resolve --status` を実行すると、systemd-resolved が現在参照している DNS サーバの詳細が分かりそうです。

# lsof してみる

system-resolved が本当に 53 番ポート ( DNS ) で待ち受けているのかどうかは `lsof` すれば分かります。
実行すると、以下の通り systemd-resolve が炙り出されました。

```bash
$ sudo lsof -i:53
COMMAND   PID            USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
systemd-r 786 systemd-resolve   12u  IPv4  16116      0t0  UDP localhost:domain 
systemd-r 786 systemd-resolve   13u  IPv4  16117      0t0  TCP localhost:domain (LISTEN)
```

# systemd-resolve --status してみる

先程のコメントの通り `systemd-resolve --status` を実行します。
すると **DNS Servers: 172.31.0.2** の文字列が発見されました。
この IP アドレスは VPC の Amazon Provided DNS の IP アドレスと一致します。

どうやら /etc/resolv.conf ではなく、最終的に問い合わせる systemd-resolved の設定に Amazon Provided DNS のアドレスが書かれているようです。

``` bash
$ systemd-resolve --status
Global
          DNSSEC NTA: 10.in-addr.arpa
                      16.172.in-addr.arpa
                      168.192.in-addr.arpa
                      17.172.in-addr.arpa
                      18.172.in-addr.arpa
                      19.172.in-addr.arpa
                      20.172.in-addr.arpa
                      21.172.in-addr.arpa
                      22.172.in-addr.arpa
                      23.172.in-addr.arpa
                      24.172.in-addr.arpa
                      25.172.in-addr.arpa
                      26.172.in-addr.arpa
                      27.172.in-addr.arpa
                      28.172.in-addr.arpa
                      29.172.in-addr.arpa
                      30.172.in-addr.arpa
                      31.172.in-addr.arpa
                      corp
                      d.f.ip6.arpa
                      home
                      internal
                      intranet
                      lan
                      local
                      private
                      test

Link 2 (ens5)
      Current Scopes: DNS
       LLMNR setting: yes
MulticastDNS setting: no
      DNSSEC setting: no
    DNSSEC supported: no
         DNS Servers: 172.31.0.2
          DNS Domain: ap-northeast-1.compute.internal
```

# DHCP オプションセットの効き目

DNS Servers に **172.31.0.2** が書かれている 「ens5」 そのものの設定を確認します。
/etc/network/interfaces の下には何もなく、/etc/netplan/ の下に .yaml が置かれていますので、確認します。

```bash
$ cat /etc/netplan/50-cloud-init.yaml
# This file is generated from information provided by the datasource.  Changes
# to it will not persist across an instance reboot.  To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    version: 2
    ethernets:
        ens5:
            dhcp4: true
            match:
                macaddress: 06:72:1e:15:cd:f4
            set-name: ens5
```

ens5 で DHCP が有効になっていることが確認できましたが、これは AWS の VPC なので当然と言えば当然の結果となります。
AWS VPC では、[デフォルトの DHCP オプションセット](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_DHCP_Options.html#DHCPOptionSets)で Amazon Provided DNS が指定されており、Amazon Provided DNS のアドレスは、今回の場合、冒頭で述べた **172.31.0.2** です。
**172.31.0.2** は、AWS VPC の DHCP で OS 側に通知されています。

# まとめ
* VPC の DHCP オプションセットの設定がデフォルトで、NIC が DHCP 設定であれば、 Amazon Provided DNS のプライベート IP アドレスが、参照先 DNS サーバの IP アドレスとして通知されます。
* しかし Ubuntu OS では、nslookup すると、デフォルト設定により、まずは DNS のスタブリゾルバである systemd-resolved ( 127.0.0.53 ) に問い合わせされます。
* その後 systemd-resolved が、Amazon Provided DNS のプライベート IP アドレスに問い合わせます。

# 参考文献
* [ubuntu18.04のネットワーク周り設定](https://qiita.com/atomyah/items/1989138730f3385844dd)
* [Ubuntu 18.04 の systemd-resolved で local DNS stub listener の利用をやめる](https://qiita.com/shora_kujira16/items/31d09b373809a5a44ae5)
* [Ubuntu 18.04: ネットワークを設定する] (https://www.hiroom2.com/2018/05/29/ubuntu-1804-network-ja/) (From Narrow Escape)
* [VPC とサブネット](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_Subnets.html) (From AWS公式)
* [DHCP オプションセット](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_DHCP_Options.html) (From AWS公式)