Dnsmasq で おうち DNS on Ubuntu 20.04 LTS
GitLab の Pages とか Environments とかは DNS、しかもワイルドカードレコードが必須なわけですが、手許でさくっと試せるようにしたくて、おうち DNS を立てることにしました。
用意した環境は、とりあえず、今使っている Windows 10 マシンに VMware Workstation Player で立てた Ubuntu 20.04 LTS の VM です。省エネで常時動作させるために Rapsberry Pi 4 でやってみたかったんだけど、超品薄[1]なため一旦断念。そのうち買って移したいところです。
始める前に: Ubuntu のローカルリゾルバー
今回これをやり始めて初めて知ったんですが[2]、Ubuntu は "systemd-resolved" というローカルリゾルバーサービスを介して名前解決をしています。図にするとこんな感じ。
で、どうやら /etc/systemd/resolved.conf
の DNSStubListenerExtra=
に外向きのアドレスを書けば、ローカルマシンだけでなく外向きにもリゾルバーサービスを提供できそう[3]、つまり Dnsmasq を入れなくてもよいかも[4]、と思ったのですが、残念ながら DNSStubListenerExtra=
は systemd v247 からサポートでした。20.04 に入っているのは v245。
# systemd --version
systemd 245 (245.4-4ubuntu3.17)
ところで、ちょっと横道に逸れますが、systemd-resolved は 127.0.0.53
をリッスンしています。localhost
に代表されるローカルループバックアドレスは 127.0.0.0/8
なので、こういうこともできるわけですが、実用的に意味がある目的に使われている例を初めて見た気がします。どういう意味かは少し後で書きます。
Dnsmasq のインストールと設定
というわけで、systemd-resolved だけでやるのはさっくり諦めて、素直に Dnsmasq を入れることにします。sudo apt install dnsmasq
だけで入ります。
OS 標準の仕組みを弄くりまくったり止めたりすると、後々めんどくさいことが起きがちなので、既存の systemd-resolved まわりはできる限りそのまま活かして、そこにうまく Dnsmasq をはめ込もうと考えました。ここで前述の 127.0.0.53
がうまい具合に働きます [5]。Dnsmasq を、それとは別のループバックアドレス、まぁ素直に普通の 127.0.0.1
にバインドすれば、コンフリクトしないわけです。図にするとこんな感じ。ここで、外向きのアドレスは 192.168.1.160
にしてありますが、空いてた以外に特に意味はありません。言わずもがなですが、このアドレスは DHCP サーバーで固定に設定してあります。
これを設定に落としていきます。
/etc/dnsmasq.conf
(デフォルト値を変えた箇所のみ)
no-resolv
no-poll
server=192.168.1.1
bind-interfaces
listen-address=127.0.0.1
listen-address=::1
listen-address=192.168.1.160
listen-address=fe80::20c:29ff:fef9:a2a1
address=/pages.internal/192.168.1.161
no-dhcp-interface=
no-resolv
, no-poll
: /etc/resolv.conf
が systemd-resolved を見に行くようになっているので、Dnsmasq がそうやってループしてしまわないよう /etc/resolv.conf
参照を抑止
server=
: その代わりにローカルネットワークの DNS に直接問い合わせるように設定
bind-interfaces
: liseten-address
に指定したアドレスのインタフェースだけバインドするように指定
listen-address=
: バインドするインターフェースのアドレス
address=
: ワイルドカードドメインの指定 (/etc/hosts
に *.pages.internal
のように書いても効かなくて、ここにこう書く必要があります)
no-dhcp-interface=
: DHCP は既にあるやつを使うので抑止
/etc/systemd/resolved.conf
(デフォルト値を変えた箇所のみ)
[Resolve]
DNS=127.0.0.1
DNS=
: systemd-resolved が問い合わせに行く上流の DNS。ここに Dnsmasq の listen-address
を書く
設定したら、両者を restart
して
# systemctl restart dnsmasq systemd-resolved
netstat
がこんな感じになれば OK。
# netstat -nlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN 15153/dnsmasq
tcp 0 0 192.168.1.160:53 0.0.0.0:* LISTEN 15153/dnsmasq
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 13765/systemd-resol
tcp6 0 0 ::1:53 :::* LISTEN 15153/dnsmasq
tcp6 0 0 fe80::20c:29ff:fef9::53 :::* LISTEN 15153/dnsmasq
udp 0 0 127.0.0.1:53 0.0.0.0:* 15153/dnsmasq
udp 0 0 192.168.1.160:53 0.0.0.0:* 15153/dnsmasq
udp 0 0 127.0.0.53:53 0.0.0.0:* 13765/systemd-resol
udp6 0 0 ::1:53 :::* 15153/dnsmasq
udp6 0 0 fe80::20c:29ff:fef9::53 :::* 15153/dnsmasq
クライアントの設定
Linux
Ubuntu (16.10 以降)
上の図で Remote machine
のところに書いたように、/etc/systemd/resolved.conf
を下記のように変更します。
[Resolve]
DNS=192.168.1.160
その他のディストリビューション
調べてません、ごめんなさい。
WSL
/etc/resolv.conf
がこんな風になっていて、
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 172.21.0.1
vEthernet (WSL)
というアダプターを通じて Windows ホストを参照するようになっています。なので、Windows に任せておけばよいのですが、次項で書くように Windows 側がどうも不安定な感じがあるので、指示されているように /etc/wsl.conf
を作って下記のように入れて、
[network]
generateResolvConf = false
/etc/resolv.con
を下記のように変更して、直接 Dnsmasq を参照するようにしました。
nameserver 192.168.1.160
Windows 10
ネットワークアダプタのプロパティの、インターネット プロトコル パージョン 4 (TCP/IPv4)
と インターネット プロトコル パージョン 6 (TCP/IPv6)
のそれぞれのプロパティを開き、
下図のように、優先 DNS サーバー
に Dnsmasq のアドレスを設定します。代替 DNS サーバー
の方にはもともとの DNS サーバーのアドレスを残しておきましょう。
nslookup では引けるのに ping が DNS エラーになる場合
設定は以上なのですが、nslookup
では名前解決できているのに ping
では ホストが見つかりません
エラーになってしまうという、ググるとたくさんヒットする現象に見舞われます。この違いは、nslookup
は DNS を直接参照するのに対して、ping
などの WinSock クライアントは Windows の DNS クライアントサービスを使っているから生じているらしいです。
この場合は、Windows の コマンドプロンプト を管理者権限で起動して下記のコマンドを実行すれば
ipconfig /registerdns
だいたい解決します。そうです、「だいたい」です。解決しないことや、解決しても何かの拍子にまただめになっていることもあって、これが上で「不安定」と言っていたやつです。
DNS サーバー (Dnsmasq) が Windows 上の VM なので、Windows のネットワークサービスの起動と、VM のサスペンドからの復帰とのタイミングとかが関係してるような気がします。早く Rapsberry Pi 4 買って常時動作にしたい (いや普通に PC 買えよ (だって先立つ物がですね...
プライベート TLD (Top Level Domain)
.local を使ってはいけない
.local
は、Multicast DNS 用に IETF によって予約されているので、プライベート TLD として使ってはいけません。
DNS リゾルバーの中には、この理由で .local
を特別扱いするものもあります。実際、dig ではローカルマシンは引けるけど全インタフェースのアドレスが返る、ping では Temporary failure in name resolution
エラーになる、という謎現象が発生します (しました)。
プライベート TLD に使える名前
じゃあ何を使えばいいかというと、厳密には使っていい名前は現状ありません。ただし、そういう名前を制定しようと議論はされているようです[6]。
今のところ .internal
[7] が有力候補で、かつ比較的安全なのではないかと勝手に判断して、自己責任で使うことにしました。この記事を読まれた方が TLD に .internal
をお使いになってもし何か起きたとしても、私は責任を追うことはできないので、ご承知置きください。
Discussion