Unboundで自宅のLAN内の名前解決がしたい

# やりたいこと

- 自宅のLAN内ではサーバやルータ等の複数のノードが稼働している
- 各ノードにはプライベートIPアドレスが静的に割り当てられている
- しかし、IPアドレスを覚えるのは面倒なため、LAN内で名前解決できる仕組みを取り入れたい
    - e.g. `foo.internal`のような独自に定義したドメインと`192.168.0.1`のようなプライベートIPアドレスを変換する

# 使用技術

### Unbound

- OSSのDNSキャッシュサーバ
- 動作が高速で設定が簡単という特徴を持つ
- GitHub: https://github.com/NLnetLabs/unbound
- オランダの[NLnet Labs](https://www.nlnetlabs.nl/)が開発している
- NLnet Labsは他にも[NSD](https://github.com/NLnetLabs/nsd)や[OpenDNSSEC](https://github.com/opendnssec/opendnssec)の開発も行っている
- ちなみに自宅での利用用途の場合、[dnsmasq](https://github.com/imp/dnsmasq)という選択肢もありそう
- 今回は、単に検証してみたかったという理由や、設定の容易さ、DNSフォワーダや簡易的なDNSコンテンツサーバとしての利用もしたかったことから選定

### local-data

- Unboundは通常、DNSキャッシュサーバとして利用することが一般的
- しかし、Unboundのlocal-dataという機能を使用することで、擬似的にDNSコンテンツサーバのような振る舞いをさせることができる
    - 手動でレコードを設定し、それを永続的なキャッシュとして保存する
- 本格的にDNSコンテンツサーバとしての機能を利用したい場合はNSDはBIND等を別途構築することが推奨される

# ネットワーク構成

### LAN内の名前解決

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78249/781b54fa-5a80-6cdd-974f-e7674ba3f5fe.png)

1. クライアント(例えばラップトップ等)はLAN内でのみ有効なドメイン(`foo.internal`等)をUnboundに問い合わせ(正引き)
1. Unboundが自身で持つレコードを参照し(local-data)、`192.168.0.1`のようなプライベートIPアドレスに名前解決して応答
1. クライアントは得られたプライベートIPアドレスに接続する

### インターネット上の名前解決

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78249/419b0985-3ec1-d913-db41-1cb5aae550e9.png)

1. クライアントはUnboundにインターネット上で有効なドメイン(`example.com`等)を問い合わせ(正引き)
1. Unboundは自身で再帰問い合わせをせず、デフォルトゲートウェイが提供するDNSキャッシュサーバにフォワーディング
    - つまり、インターネット上の名前解決に関しては、UnboundはDNSフォワーダとして振る舞う
    - ちなみにフォワーディング先はGoogle Public DNS(`8.8.8.8`)等のパブリックDNSでも良い
1. デフォルトゲートウェイが再帰問い合わせを行い、名前解決
1. クライアントは得られたグローバルIPアドレスに接続する

# Unboundの構築

- UnboundはUbuntu Server 22.04.2 LTS上に構築する

### Unboundの設定

- Unboundのインストール

```bash
$ sudo apt install unbound -y
```

- コンフィグの作成

```bash
$ sudo vim /etc/unbound/unbound.conf.d/unbound.conf
```

```conf:unbound.conf
server:
    # ログを出力するファイルの指定
    logfile: "/var/log/unbound.log"

    # ログ出力先にsyslogを使用するのをやめる
    use-syslog: no

    # エラーと操作情報のサマリを出力
    verbosity: 1

    # リクエストを受け付けるインタフェース
    interface: 0.0.0.0
    interface: ::0

    # アクセスを許可するネットワーク
    access-control: 0.0.0.0/0 refuse
    access-control: ::0/0 refuse
    access-control: 127.0.0.0/8 allow
    access-control: ::1 allow
    access-control: 192.168.0.0/24 allow
    access-control: 2001:XXXX:XXXX:XXXX::0/64 allow

    # 内部向けのDNSコンテンツサーバ
    local-data: "foo.internal. IN A 192.168.0.1"
    local-data: "bar.internal. IN A 192.168.0.2"
    local-data: "baz.internal. IN A 192.168.0.3"

# Unboundでは再帰問い合わせを行わない
forward-zone:
    name: "."
    forward-addr: 192.168.0.1
```

- コンフィグに誤りがないかをチェック(主にシンタックス周り)

```bash
$ unbound-checkconf unbound.conf
unbound-checkconf: no errors in unbound.conf
```

- Unboundを再起動し、コンフィグを反映
- しかし再起動に失敗する

```bash
$ sudo systemctl restart unbound
Job for unbound.service failed because the control process exited with error code.
See "systemctl status unbound.service" and "journalctl -xeu unbound.service" for details.
```

- どうやら53番ポートでsystemd-resolved(DNSスタブリゾルバ)が稼働している模様

```bash
$ sudo ss -lntp | grep 53
LISTEN 0      4096   127.0.0.53%lo:53        0.0.0.0:*    users:(("systemd-resolve",pid=837,fd=14))
```

- systemd-resolvedのDNSスタブリゾルバとしての機能をオフにする

```bash
$ sudo vim /etc/systemd/resolved.conf
```

```ini:resolved.conf
[Resolve]
DNSStubListener=no
```

- systemd-resolvedの再起動

```bash
$ sudo systemctl restart systemd-resolved
```

- systemd-resolvedが正常に起動していることを確認

```bash
$ systemctl status systemd-resolved
● systemd-resolved.service - Network Name Resolution
     Loaded: loaded (/lib/systemd/system/systemd-resolved.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2023-03-14 22:38:36 UTC; 11s ago
       Docs: man:systemd-resolved.service(8)
             man:org.freedesktop.resolve1(5)
             https://www.freedesktop.org/wiki/Software/systemd/writing-network-configuration-managers
             https://www.freedesktop.org/wiki/Software/systemd/writing-resolver-clients
   Main PID: 11823 (systemd-resolve)
     Status: "Processing requests..."
      Tasks: 1 (limit: 2233)
     Memory: 4.3M
        CPU: 62ms
     CGroup: /system.slice/systemd-resolved.service
             └─11823 /lib/systemd/systemd-resolved

Mar 14 22:38:36 ubuntu-server systemd[1]: Starting Network Name Resolution...
Mar 14 22:38:36 ubuntu-server systemd-resolved[11823]: Positive Trust Anchors:
Mar 14 22:38:36 ubuntu-server systemd-resolved[11823]: . IN DS 20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d
Mar 14 22:38:36 ubuntu-server systemd-resolved[11823]: Negative trust anchors: home.arpa 10.in-addr.arpa 16.172.in-addr.arpa 17.172.in-addr.arpa >
Mar 14 22:38:36 ubuntu-server systemd-resolved[11823]: Using system hostname 'ubuntu-server'.
Mar 14 22:38:36 ubuntu-server systemd[1]: Started Network Name Resolution.
```

- 53番ポートで何も稼働していないことを確認

```bash
$ sudo ss -lntp | grep 53
```

- 再度、Unboundを再起動し、コンフィグを反映

```bash
$ systemctl restart unbound
```

- Unboundが正常に起動していることを確認

```bash
$ systemctl status unbound
● unbound.service - Unbound DNS server
     Loaded: loaded (/lib/systemd/system/unbound.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2023-03-14 23:14:29 UTC; 9s ago
       Docs: man:unbound(8)
    Process: 15902 ExecStartPre=/usr/lib/unbound/package-helper chroot_setup (code=exited, status=0/SUCCESS)
    Process: 15905 ExecStartPre=/usr/lib/unbound/package-helper root_trust_anchor_update (code=exited, status=0/SUCCESS)
   Main PID: 15908 (unbound)
      Tasks: 1 (limit: 2233)
     Memory: 7.0M
        CPU: 60ms
     CGroup: /system.slice/unbound.service
             └─15908 /usr/sbin/unbound -d -p

Mar 14 23:14:29 ubuntu-server systemd[1]: Starting Unbound DNS server...
Mar 14 23:14:29 ubuntu-server unbound[15908]: [1678835669] unbound[15908:0] error: Could not open logfile /var/log/unbound.log: Permission denied
Mar 14 23:14:29 ubuntu-server unbound[15908]: [1678835669] unbound[15908:0] notice: init module 0: subnet
Mar 14 23:14:29 ubuntu-server unbound[15908]: [1678835669] unbound[15908:0] notice: init module 1: validator
Mar 14 23:14:29 ubuntu-server unbound[15908]: [1678835669] unbound[15908:0] notice: init module 2: iterator
Mar 14 23:14:29 ubuntu-server unbound[15908]: [1678835669] unbound[15908:0] info: start of service (unbound 1.13.1).
Mar 14 23:14:29 ubuntu-server systemd[1]: Started Unbound DNS server.
```

- 53番ポートでUnboundが稼働していることを確認

```bash
$ sudo ss -lntp | grep 53
[sudo] password for kazukichi:
LISTEN 0      256          0.0.0.0:53        0.0.0.0:*    users:(("unbound",pid=15908,fd=4))
LISTEN 0      256        127.0.0.1:8953      0.0.0.0:*    users:(("unbound",pid=15908,fd=8))
LISTEN 0      256             [::]:53           [::]:*    users:(("unbound",pid=15908,fd=6))
LISTEN 0      256            [::1]:8953         [::]:*    users:(("unbound",pid=15908,fd=7))
```

### Unboundの動作確認

- `192.168.0.5`は今回、Unboundを構築したUbuntu Serverに設定されているIPアドレス
- LAN内の名前解決

```bash
$ dig foo.internal @192.168.0.5

; <<>> DiG 9.10.6 <<>> foo.internal @192.168.0.5
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 23706
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;foo.internal.			IN	A

;; ANSWER SECTION:
foo.internal.		3600	IN	A	192.168.0.1

;; Query time: 11 msec
;; SERVER: 192.168.0.5#53(192.168.0.5)
;; WHEN: Thu Mar 16 05:05:59 JST 2023
;; MSG SIZE  rcvd: 57
```

- インターネット上の名前解決

```bash
$ dig example.com @192.168.0.5

; <<>> DiG 9.10.6 <<>> example.com @192.168.0.5
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35119
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;example.com.			IN	A

;; ANSWER SECTION:
example.com.		50569	IN	A	93.184.216.34

;; Query time: 3194 msec
;; SERVER: 192.168.0.5#53(192.168.0.5)
;; WHEN: Thu Mar 16 04:56:47 JST 2023
;; MSG SIZE  rcvd: 56
```

- どちらも正常に動作していることが確認できる