開発用に任意のドメイン名をローカルループバックアドレスに名前解決させる(Linux + systemd-resolved + NetworkManager + Dnsmasq の環境で)


## 概要
Fedora Linuxの環境で開発のため任意のドメイン名とその全てのサブドメインをローカルループバックアドレスに名前解決させるように設定しました。その方法を説明します。

## 環境
- OS: Fedora 38
- DNSクライアント: systemd-resolved
- ネットワーク接続管理ツール: NetworkManager(Dnsmasqプラグイン使用)

## 設定

### Dnsmasqのインストール

NetworkManagerでDnsmasqプラグインを使用するにはDnsmasqのバイナリが必要なため、dnsmasqのパッケージをインストールします。

```shell-session
[vagrant@localhost ~]$ sudo dnf install dnsmasq
```

NetworkManager経由でDnsmasqを起動するためdnsmasq.serviceは有効にしません。

### NetworkManager + Dnsmasq の設定

Dnsmasqプラグインを有効に設定する。

```conf:/etc/NetworkManager/conf.d/90-use-dnsmasq.conf
[main]
dns=dnsmasq
```
`example.com`ドメインおよびそのサブドメインをローカルループバックアドレス`127.0.0.1`に解決するように設定する。

```conf:/etc/NetworkManager/dnsmasq.d/example.com.conf
address=/example.com/127.0.0.1
```

設定をリロードする。

```shell-session
[vagrant@localhost ~]$ sudo nmcli general reload
```

Dnsmasqが動作していることを確認する。

```shell-session
[vagrant@localhost ~]$ sudo lsof -i :53 -nP
COMMAND    PID            USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
systemd-r  602 systemd-resolve   14u  IPv4  31318      0t0  UDP 192.168.122.93:58251->192.168.122.1:53
systemd-r  602 systemd-resolve   16u  IPv4  16937      0t0  UDP 127.0.0.53:53
systemd-r  602 systemd-resolve   17u  IPv4  16938      0t0  TCP 127.0.0.53:53 (LISTEN)
systemd-r  602 systemd-resolve   18u  IPv4  16939      0t0  UDP 127.0.0.54:53
systemd-r  602 systemd-resolve   19u  IPv4  16940      0t0  TCP 127.0.0.54:53 (LISTEN)
systemd-r  602 systemd-resolve   23u  IPv4  31356      0t0  UDP 192.168.122.93:35870->192.168.122.1:53
dnsmasq   4024         dnsmasq    4u  IPv4  31334      0t0  UDP 127.0.0.1:53
dnsmasq   4024         dnsmasq    5u  IPv4  31335      0t0  TCP 127.0.0.1:53 (LISTEN)
[vagrant@localhost ~]$
```

### systemd-resolved の設定

systemd-resolvedの設定に`[Resolve]`セクションを追加し、`example.com`ドメイン及びそのサブドメインに対する名前解決要求をdnsmasqのアドレス`127.0.0.1`にルーティングするように設定する。

```conf:/etc/systemd/resolved.conf.d/example.com.conf
[Resolve]
DNS=127.0.0.1
Domains=~example.com
```

`example.com`の問い合わせ先DNSサーバがDnsmasqのアドレス`127.0.0.1`になっていることを確認。

```shell-session
[vagrant@localhost ~]$ resolvectl status
Global
         Protocols: LLMNR=resolve -mDNS -DNSOverTLS DNSSEC=no/unsupported
  resolv.conf mode: stub
       DNS Servers: 127.0.0.1
        DNS Domain: ~example.com

Link 2 (eth0)
    Current Scopes: DNS LLMNR/IPv4 LLMNR/IPv6
         Protocols: +DefaultRoute LLMNR=resolve -mDNS -DNSOverTLS DNSSEC=no/unsupported
       DNS Servers: 192.168.122.1
```

## 名前解決の確認

`dig`, `ping`コマンドで`example.com`, `*.example.com`のIPアドレスが`127.0.0.1`に解決されることを確認する。


```shell-session
[vagrant@localhost ~]$ dig example.com

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

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

;; ANSWER SECTION:
example.com.            0       IN      A       127.0.0.1

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Fri Aug 11 07:53:08 UTC 2023
;; MSG SIZE  rcvd: 56

[vagrant@localhost ~]$
[vagrant@localhost ~]$ dig abc.example.com

; <<>> DiG 9.18.17 <<>> abc.example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49763
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

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

;; ANSWER SECTION:
abc.example.com.        0       IN      A       127.0.0.1

;; Query time: 0 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Fri Aug 11 07:53:15 UTC 2023
;; MSG SIZE  rcvd: 60

[vagrant@localhost ~]$
[vagrant@localhost ~]$ ping -c 5 example.com
PING example.com (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.031 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.039 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.063 ms
64 bytes from localhost (127.0.0.1): icmp_seq=4 ttl=64 time=0.072 ms
64 bytes from localhost (127.0.0.1): icmp_seq=5 ttl=64 time=0.052 ms

--- example.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4132ms
rtt min/avg/max/mdev = 0.031/0.051/0.072/0.015 ms
[vagrant@localhost ~]$
[vagrant@localhost ~]$
[vagrant@localhost ~]$ ping -c 5 abc.example.com
PING abc.example.com (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.014 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.056 ms
64 bytes from localhost (127.0.0.1): icmp_seq=3 ttl=64 time=0.046 ms
64 bytes from localhost (127.0.0.1): icmp_seq=4 ttl=64 time=0.055 ms
64 bytes from localhost (127.0.0.1): icmp_seq=5 ttl=64 time=0.053 ms

--- abc.example.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4079ms
rtt min/avg/max/mdev = 0.014/0.044/0.056/0.015 ms
[vagrant@localhost ~]$

```