
デジタルモード限定・アマチュア局の遠隔操作に対応する その2 DNS設定編
自宅VPNサーバを立てて、自宅外から遠隔操作できるようになりました。ただし、機器をIPアドレスで指定しているのが若干イケていません。ホスト名で指定できるようにすべく、自前でDNSを立ててしまいましょう。
※実際に無線機を遠隔操作するためには局免の変更申請が必要です。
※表題画像はChatGPTに生成させました。無線風味がありませんね。
DNS
ここまでの設定で、VPNを通して自宅LANに参加できるようになりました。LANだけであればmDNSでホスト名を解決できていたのですが、WireGuard VPNはL3なのでUDPのマルチキャストが届きません。という訳で、自前でDNSを立てることにしました。
dnsmasq
WireGuardをインストールしたRasPiに、ローカルに向けたDNSを立ててみましょう。軽量DNSの定番、dnsmasqです。
$ sudo apt install dnsmasq
$ sudo systemctl start dnsmasq
$ sudo systemctl enable dnsmasqこれだけで、/etc/hostsのエントリを参照したDNSが立ち上がります。
ホスト
無線局っぽい雰囲気を重視して、ホスト名はフォネティックコードにしました。LAN側のアドレス (192.168.10.191〜195) はルータのDHCPで固定的に割り当てるよう設定してあります。
alpha: VPNサーバ・DNSサーバ: 192.168.10.191, 10.0.0.1
bravo: VNCクライアント: 192.168.10.192, 10.0.0.2
charlie: 自宅LAN外VNCクライアント: -, 10.0.0.3
delta: WSJT-X/MSHV, 192.168.10.194, 10.0.0.4
echo: RUMlogNG: 192.168.10.195, 10.0.0.5
charlieは自宅LAN内にはありませんが、内部的には192.168.10.193を割り当てます。
設定失敗
ChatGPTに相談しながら設定してみましたが、結論から言えば期待通りには動作しませんでした。備忘のために残しておきますが、失敗に興味のない方は成功例まで読み飛ばして下さい。
方針
LAN側からの問い合わせ → LAN側のアドレスを返す
VPN側からの問い合わせ → VPN側のアドレスを返す
設定例 (失敗)
以下に、ChatGPTが提案してきた内容を示します。この通りに設定しても、期待通りには動作しません。
$ sudo vi /etc/dnsmasq.d/home.conf
domain=home
local=/home/
listen-address=127.0.0.1
listen-address=192.168.10.191
listen-address=10.0.0.1
#bind-interfaces
bind-dynamic
cache-size=1000
domain-needed
bogus-priv
localise-queries
# WireGuard VPN, DNS, RasPi5
host-record=alpha,alpha.home,192.168.10.191,10.0.0.1
# VNC client, MacBook Air
host-record=bravo,bravo.home,192.168.10.192,10.0.0.2
# VNC client, Mac mini
host-record=charlie,charlie.home,192.168.10.193,10.0.0.3
# WSJT-X/MSHV, Debian trixie
host-record=delta,delta.home,192.168.10.194,10.0.0.4
# RUMlogNG, Mac mini @home
host-record=echo,echo.home,192.168.10.195,10.0.0.5
# CNAME
cname=vpn.home,alpha.home
cname=wsjtx.home,delta.home
cname=rumlog.home,echo.home何点かキーポイントがありますので、それらをメインに解説します。
listen-addressとbind-dynamic
問い合わせを受け付けるIPアドレスを指定します。これら以外のアドレス宛てのリクエストは受け付けません。一般的にはbind-interfaces指定でネットワークインタフェース/IPアドレスとの紐付けをしますが、dnsmasqより後にWireGuardが立ち上がる可能性があります。
実際に立ち上がり順はdnsmasqが先だったため、bind-interfaces設定のままではdnsmasqlの起動に失敗しました。
systemctlでサービスの依存関係 (起動順) を調整することでも解決できますが、今回はbind-dynamic指定で、後から (動的に) バインドできるようにしました。
localise-queriesとhost-record
一般的なdnsmasqの設定では /etc/hosts ファイルにIPアドレスとホスト名を列挙していきます。今回は、localise-queriesを指定し、VPN接続している端末からの問い合わせに対してはVPN側のIPアドレス (10.0.0.0/24) を、通常のLANからの端末に対してはLAN側のIPアドレス (192.168.10.0/24) を返すようにします。
ホスト名とIPアドレスの紐付けは以下のような形式になります。
host-record=ホスト名(,ホスト名),IPアドレス(,IPアドレス)今回はドメインなしのホスト名、ローカルドメインありのホスト名、LAN側のアドレス、VPN側のアドレスがありますので、上記の設定ファイルのようになります。
なお、問い合わせ元のネットワークと合致するレコードがない場合は応答しないようです。
cname
いわゆるエイリアス、別名です。host-recordに実体を定義し、cnameで別名を定義します。こうすることで、物理名と論理名を分離して管理することができるようになります。
例えば、ここでの設定例ではechoの別名にrumlogを設定しています。WSJT-XでUDPサーバにrumlogを指定しておけば、echoが壊れてbravoのRUMlogNGでログ受信するよう変更する場合に、DNS側でbraboの別名をrumlogを変更すれば、WSJT-X側は何も手を加える必要がない、という訳です。
設定したら再起動です。
$ sudo systemctl restart dnsmasq動作確認
VPNに繋がない状態でdigを実行してみます。
$ dig bravo +short
10.0.0.2あれ? VPN側のアドレスが返ってきました。LAN側アドレス (192.168.10.192) が返ってきて欲しかったのですが……
ChatGPTを詰めたところ、localise-queriesではhost-recordに設定されたアドレスがいずれもローカルネットワークの場合、どちらのネットワークを選択すればいいのか分からなくなることが判明。いやいやいやいや、そういうことは最初から言えよ > ChatGPT
設定成功
改めて、ネットワークインタフェースごとにDNSインスタンスを起動することにしました。ここではローカル側 (eth0; 192.168.10.1/24) またはVPN側 (10.0.0.0/24) の二つのインスタンスを立ち上げることになります。どこから問い合わせたかではなく、誰に問い合わせたかによって応答を切り替える訳です。
方針
LAN側のインスタンス (eth0, 192.168.10.191:53) に問い合わせ → LAN側のアドレスを返す
VPN側のインスタンス (wg0, 10.0.0.1:53) に問い合わせ → VPN側のアドレスを返す
設定ファイル
まずはLAN側の設定ファイルから。interfaceでLAN側NIC (eth0) を指定しています。追加で no-hosts を入れていますが、これがないと /etc/hosts を読み込んで127.0.1.1 のレコードを返してしまいます。
$ sudo vi /etc/dnsmasq-lan.conf
domain=home
local=/home/
expand-hosts
no-hosts
interface=eth0
listen-address=127.0.0.1
listen-address=192.168.10.191
bind-dynamic
cache-size=1000
domain-needed
bogus-priv
# 上流DNSを使うなら必要に応じて追加
# no-resolv
# server=192.168.10.1
# WireGuard VPN, DNS, RasPi5
host-record=alpha,alpha.home,192.168.10.191
# VNC client, MacBook Air
host-record=bravo,bravo.home,192.168.10.192
# VNC client, Mac mini @office
host-record=charlie,charlie.home,192.168.10.193
# WSJT-X/MSHV, GMKtec
host-record=delta,delta.home,192.168.10.194
# RUMlogNG, Mac mini @home
host-record=echo,echo.home,192.168.10.195
# CNAME
cname=vpn.home,alpha.home
cname=wsjtx.home,delta.home
cname=rumlog.home,echo.home続いてVPN側インスタンスの設定ファイル。LAN側との違いはinterfaceと、except-interfaceでlo (ループバックデバイス) を指定していることです。これがないと127.0.0.1にbindしようとしてLAN側のインスタンスと衝突して起動に失敗します。
$ sudo vi /etc/dnsmasq-vpn.conf
domain=home
local=/home/
expand-hosts
no-hosts
interface=wg0
except-interface=lo
listen-address=10.0.0.1
bind-dynamic
cache-size=1000
domain-needed
bogus-priv
# 上流DNSを使うなら必要に応じて追加
# no-resolv
# server=192.168.10.1
# WireGuard VPN, DNS, RasPi5
host-record=alpha,alpha.home,10.0.0.1
# VNC client, MacBook Air
host-record=bravo,bravo.home,10.0.0.2
# VNC client, Mac mini @office
host-record=charlie,charlie.home,10.0.0.3
# WSJT-X/MSHV, GMKtec
host-record=delta,delta.home,10.0.0.4
# RUMlogNG, Mac mini @home
host-record=echo,echo.home,10.0.0.5
# CNAME
cname=vpn.home,alpha.home
cname=wsjtx.home,delta.home
cname=rumlog.home,echo.homeserviceファイル
dnsmasq標準のserviceファイルは使えないので、自前で用意します。まずはLAN側のserviceファイルです。eth0が立ち上がってからサービスが起動するようにしています。
$ sudo vi /etc/systemd/system/dnsmasq-lan.service
[Unit]
Description=dnsmasq (LAN)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStartPre=/usr/sbin/dnsmasq --test --conf-file=/etc/dnsmasq-lan.conf
ExecStart=/usr/sbin/dnsmasq --keep-in-foreground --conf-file=/etc/dnsmasq-lan.conf
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.target続いてVPN側のserviceファイル。こちらはWireGuardのwg0が立ち上がってからサービスが起動するようにしてあります。
$ sudo vi /etc/systemd/system/dnsmasq-vpn.service
[Unit]
Description=dnsmasq (VPN)
After=network-online.target wg-quick@wg0.service
Wants=network-online.target
Requires=wg-quick@wg0.service
[Service]
Type=simple
ExecStartPre=/usr/sbin/dnsmasq --test --conf-file=/etc/dnsmasq-vpn.conf
ExecStart=/usr/sbin/dnsmasq --keep-in-foreground --conf-file=/etc/dnsmasq-vpn.conf
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.target起動
標準のdnsmasqを停止し、新たに設定した2つのインスタンスを起動します。
$ sudo systemctl disable --now dnsmasq
$ sudo systemctl enable --now dnsmasq-lan
$ sudo systemctl enable --now dnsmasq-vpn確認
digコマンドで確認してみます。
$ dig @192.168.10.191 alpha +short
192.168.10.191
$ dig @192.168.10.191 bravo +short
192.168.10.192
$ dig @192.168.10.191 charlie +short
192.168.10.193LAN側は問題なし。続いてVPN側です。
$ dig @10.0.0.1 alpha +short
10.0.0.1
$ dig @10.0.0.1 bravo +short
10.0.0.2
$ dig @10.0.0.1 charlie +short
10.0.0.3こちらも問題なさそうですね。これでようやく期待通りの動作になりました。
VPNサーバ設定
ファイアウォール設定
DNS問い合わせに使われる53番ポートだけ開いておきたいところですが、ここでも設定をパス。ルータのファイアウォールに頑張ってもらいます。
※26/03/21追記: ufwの設定について個別に記事を起こしました;
DHCPクライアント設定
LAN側DNS
プライマリDNSサーバとして、DHCPサーバから自動的に割り当てられるDNSサーバではなく、今回立てたLAN側のDNS (192.168.10.191) を参照するよう設定します。
VPNクライアント設定
VPN側DNS
VPN接続したらVPN側のDNS (10.0.0.1) を参照するよう、VPN (WireGuard) クライアントの設定を変更します。具体的には、[Interface]の項にDNSを追記します。LinuxのNetworkManagerの場合はGUIから設定できます。
[Interface]
PrivateKey = (VPNサーバ公開鍵)
Address = 10.0.0.2/24
DNS = 10.0.0.1
...VPNを一旦切断して再接続します。VPNに再接続できたらIPアドレスではなくホスト名でpingを打ってみましょう。
% ping alpha
PING alpha (10.0.0.1): 56 data bytes
64 bytes from 10.0.0.1: icmp_seq=0 ttl=64 time=15.563 ms
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=19.801 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=20.965 ms
64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=17.072 ms
...VPNから切断するとLAN側のDNSが有効になります。これで接続しているネットワークに合わせてホスト名を解決できるようになりました。
WSJT-X設定
UDPサーバ
RUMlogNGホストをIPアドレス (10.0.0.5) で指定していた箇所をホスト名 (この例であれば echo.home) で指定できるようになりました。
ただし、dnsmasqのcname設定の項でも説明した通り、後々のことを考慮すると、論理名の rumlog.home で指定した方がよいかと思います。
改善
もうちょっとだけ続くんじゃ。