WSL上のDnsmasqで名前解決の問い合わせ先をドメインごとに分ける

# やりたいこと

- Windowsパソコンで
- あるドメインの名前解決はDNSその1へ問い合わせる
- 別のドメインの名前解決はDNSその2へ問い合わせる
- その他の名前解決はDNSその3へ問い合わせる
- ただし新規ハードウェアやHyper-Vなどの仮想PCは使用しない

これをWindowsの機能で実現する方法がわからなかったので、できそうな道具を使うことに。

# つかったもの

[Dnsmasq](https://thekelleys.org.uk/dnsmasq/doc.html)

https://thekelleys.org.uk/dnsmasq/doc.html

DNSとDHCPとTFTPのサーバーを兼ねているそうで。今回はDNS機能だけ使いました。

# 手順概要

1. WSLとLinuxの導入
1. Dnsmasqの設定
1. WSLの自動起動設定

# 難しかったこと

- Dnsmasqのリッスン対象の書き方の胆が、インターフェースではなくアドレスにあった
- WindowsからDnsmasqへの問い合わせはlocalhost宛に問い合わせればいいと思っていたら、できなかった
- WSLの自動起動が過去自分がやっていた手法は使えなくなっていた

# 手順

## WSLとLinuxの導入

こちらを参照

https://learn.microsoft.com/ja-jp/windows/wsl/install

自分はRocky Linuxを使いたかったのでこちらも参考にしました

https://www.guri2o1667.work/entry/2022/03/19/%E3%80%90WSL2%E3%80%91Redhat%E7%B3%BB%E3%83%87%E3%82%A3%E3%82%B9%E3%83%88%E3%83%AA%E3%83%93%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E4%BD%BF%E3%81%86

## Dnsmasqの設定

`dnf install dnsmasq`でインストール。設定ファイルは公式マニュアルを読み解き、書きます。

https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html

最初からある設定ファイルは`/etc/dnsmasq.conf`ですが、こちらの変更は最小限にとどめ、`/etc/dnsmasq.d/`に目的別の設定ファイルを新しく作るスタイルにしました。

```/etc/dnsmasq.conf
# 最後の方にあるこの2行を有効にする(コメントを外す)
conf-dir=/etc/dnsmasq.d/,*.conf
conf-dir=/etc/dnsmasq.d,.rpmnew,.rpmsave,.rpmorig
```

上記の設定が有効になれば、`/etc/dnsmasq.d/`に`○○.conf`という名前で作った設定ファイルが読み込まれます。

リッスン対象はインターフェースを指定せず、アドレスで指定しました。

問い合わせ先のDNSはドメインごとに指定ができ、指定ドメイン以外はDNSサーバーのIPアドレスだけ書いたものが使われます。

```/etc/dnsmasq.d/dns.conf
# DNS機能の有効化とポート指定
# port=0を指定すると無効化
port=53

# Dnsmasqが動いているLinuxのIPアドレスを最後に加えないと外部からの名前解決を受け付けない
listen-address=::1,127.0.0.1,Dnsmasqが動いているLinuxのIPアドレス

# ドメイン名のない問い合わせは上位DNSサーバーに転送しない
domain-needed

# プライベートIPアドレスの逆引きを上位DNSサーバーに転送しない
# 対象はRFC6303に記載されている範囲
bogus-priv

# 上位DNSに問い合わせを行う順序をリゾルバ定義ファイルの記載順に固定する
# リゾルバ定義ファイルが別にあることが前提
# no-resolv オプションを指定する場合、strict-order オプションは実質的に無効化される
#strict-order

# hostsファイルのピリオドがないホスト名にドメイン名を付加する
# 付加するドメイン名は domain= で指定すること
expand-hosts

# expand-hostsオプションが有効な場合、DNS名前解決に指定されたドメイン名を付加する
# expand-hostsオプションにかかわらず、DHCP応答にドメイン名を付加する
# domain=<domain>[[,<address range>[,local]]|<interface>]
domain=自分のドメイン名

# 指定されたドメイン名についてはhostsファイルまたはDHCPからのみ応答する
# local=[/[<domain>]/[domain/]][<ipaddr>[#<port>]][@<interface>][@<source-ip>[#<port>]]/

# 上位DNSサーバーを指定する
# server オプションを有効にしてもリゾルバ定義ファイルの読み込みは行われる
# リゾルバ定義ファイルの読み込みを抑制する場合、no-resolvオプションを有効にすること
# server=[/[<domain>]/[domain/]][<ipaddr>[#<port>]][@<interface>][@<source-ip>[#<port>]]
no-resolv
server=/DNSサーバーその1に問い合わせたいドメイン名/DNSサーバーその1のIPアドレス
server=/DNSサーバーその2に問い合わせたいドメイン名その1/DNSサーバーその2に問い合わせたいドメイン名その2/DNSサーバーその2に問い合わせたいドメイン名その3/DNSサーバーその2に問い合わせたいドメイン名その4/DNSサーバーその2に問い合わせたいドメイン名その5/DNSサーバーその2のIPアドレス
server=/DNSサーバーその3に問い合わせたいドメイン名/DNSサーバーその3のIPアドレス
server=1.1.1.1
server=8.8.8.8

# キャッシュされるドメイン名の数
# デフォルトは150 ハードリミットは10000
# https://wiki.archlinux.jp/index.php/Dnsmasq
cache-size=5000

# DNS問い合わせをsyslogに出力
#log-queries
```



## Dnsmasqへの問い合わせ

`nslookup`コマンドで問い合わせを行い、確認をしました。

例えばcockpitであれば、ブラウザから`https://localhost:9090`宛にアクセスすればログイン画面が表示されたので、Windowsからは`nslookup - localhost`と問い合わせればいいのだろう、と思いましたが、全ッ然名前解決できませんでした。

実際はDnsmasqが動いているLinuxのIPアドレスを指定しないとダメでした。これについては未だに理由がわかりません。

WSLのIPアドレスはDHCPで振られているとのことなので、本当は固定するなどの対策をしたうえでIPアドレスを設定する必要があるのかもしれません。

## WSLの自動起動

タスクスケジューラーを使用する方法では8秒で終了してしまうようになったため、こちらを参考にさせて頂きました。

https://hidekatsu-izuno.hatenablog.com/entry/2022/08/31/231539

# 感想

そもそもWindowsだけでもっと楽に実現できそうなものだけど、はて。