名前が解決される道を最後まで辿る
このラボはVM上で動きます
Ubuntu 24.04ではsystemd-resolvedが名前解決を担当します。そこにdnsmasqで自分のDNSサーバーをもう1つ立て、2つの層を行き来しながら、名前がどこで答えを得るのかを見ます。dnsmasqはすでにインストールされていますが、サービスが失敗したままです。その理由を探すのがステップ3です。
目標
/etc/resolv.confのスタブアドレスが何か、本当の上流サーバーはどこか、自分のDNSサーバーを特定のドメインだけにつなぐにはどうするか、/etc/hostsがなぜDNSに優先されるのかを、コマンドで確認します。
なぜ重要なのか
「つながらない」の最初の分かれ道が名前です。ところが最近のLinuxでは、名前解決は1つの層ではありません。アプリケーションはlibcのgetaddrinfoを呼び、それはnsswitch.confの順にまず/etc/hostsを見て、次にresolv.confのスタブ(127.0.0.53)に尋ね、スタブはリンクごとの設定を見て上流へ転送します。digはこのうち最後の段階だけを直接叩きます。そのため、digは通るのにcurlは通らないということが実際に起き、どの層が違うのかを知って初めて直せます。
ステップ
/etc/resolv.confが指す実際のファイルパスとnameserverの行を/root/dns/resolv.txtに保存してください。- スタブが実際に尋ねる上流DNSサーバーのアドレスを、
/root/dns/upstream.txtにupstream=<주소>の1行で保存してください(プレースホルダーはアドレスです)。 - dnsmasqがなぜ起動しないのかを調べ、ポート53を掴んでいるプロセスを示す
ssの出力を/root/dns/port53.txtに保存してください。 - ダミーインターフェース
dns0に10.53.0.1/24を付け、/etc/dnsmasq.d/lab.confで、dnsmasqが10.53.0.1だけで待ち受け、app.lab.internal→10.53.0.10、db.lab.internal→10.53.0.20を答えるようにして、サービスを復旧させてください。 dig @10.53.0.1 app.lab.internalの全出力を/root/dns/dig.txtに保存してください。resolvectlでdns0リンクにDNSサーバー10.53.0.1とルーティングドメイン~lab.internalを指定して、getent hosts app.lab.internalが通るようにし、resolvectl status dns0を/root/dns/link.txtに保存してください。/etc/hostsに10.53.0.99 db.lab.internalを入れ、getentとdig @10.53.0.1の答えを/root/dns/hosts.txtにgetent=・dig=の2行で保存してください。/root/dns/report.mdに、stub=・upstream=・local=の3行、dnsmasqのクエリログからapp.lab.internalの行1つ、そして/etc/hostsがDNSに優先される理由を書いてください。
参考
readlink -f /etc/resolv.conf、resolvectl status、resolvectl dns、resolvectl domain。- ポートを掴んでいるプロセス:
ss -ulpn 'sport = :53'。journalctl -u dnsmasqに失敗の理由があります。 - dnsmasqの設定キー:
listen-address=、bind-interfaces、no-resolv、log-queries、address=/이름/주소(プレースホルダーは名前とアドレスです)。変更後はsystemctl restart dnsmasqを実行します。 - よくある間違い1:
bind-interfacesを抜かすことです。そうすると、dnsmasqがすべてのアドレスの53を掴もうとして、スタブとまた衝突します。 - よくある間違い2: ステップ6でドメインの前の
~を抜かすことです。~がないと検索ドメインになり、短い名前の後ろに付けるだけで、クエリをそのサーバーへ送ることはありません。
resolv.confの正体
/etc/resolv.confが指す実際のファイルパスとnameserverの行を /root/dns/resolv.txt に保存してください。
readlink -f /etc/resolv.confがシンボリックリンクの先の本当のパスを返します。grep nameserver /etc/resolv.confでスタブのアドレスを見ます。両方を1つのファイルに入れてください。
本当のサーバーはどこか
スタブが実際に尋ねる上流DNSサーバーのアドレスを、/root/dns/upstream.txt にupstream=<주소>の1行で保存してください(プレースホルダーはアドレスです)。
resolvectl statusのリンクの項目にCurrent DNS Serverがあります。デフォルトルートのインターフェース(enp1s0)の値です。resolvectl dns enp1s0のほうが短く済みます。
dnsmasqはなぜ起動しないのか
dnsmasqがなぜ起動しないのかを調べ、ポート53を掴んでいるプロセスを示すssの出力を /root/dns/port53.txt に保存してください。
systemctl status dnsmasqとjournalctl -u dnsmasqにAddress already in useがあります。誰が掴んでいるかはss -ulpn 'sport = :53'で確認します。-pがプロセス名を表示します(rootで実行する必要があります)。
自分のDNSサーバーを立てる
ダミーインターフェースdns0に10.53.0.1/24を付け、/etc/dnsmasq.d/lab.conf で、dnsmasqが10.53.0.1だけで待ち受け、app.lab.internal→10.53.0.10、db.lab.internal→10.53.0.20を答えるようにして、サービスを復旧させてください。
ip link add dns0 type dummyのあとにアドレス設定とUPを行います。設定はlisten-address=10.53.0.1とbind-interfacesでそのアドレスだけを掴ませ、address=/app.lab.internal/10.53.0.10のように名前を固定します。no-resolvは上流を使わないという意味です。終わったらsystemctl restart dnsmasqのあとにsystemctl is-active dnsmasqを実行します。
digで直接尋ねる
dig @10.53.0.1 app.lab.internalの全出力を /root/dns/dig.txt に保存してください。
@서버はresolv.confを無視して、そのサーバーに直接尋ねます(プレースホルダーはサーバーのアドレスです)。出力のANSWER SECTIONにAレコードが、ヘッダーにstatus: NOERRORが表示されている必要があります。
スタブに自分のサーバーをつなぐ
resolvectlでdns0リンクにDNSサーバー10.53.0.1とルーティングドメイン~lab.internalを指定して、getent hosts app.lab.internalが通るようにし、resolvectl status dns0を /root/dns/link.txt に保存してください。
resolvectl dns dns0 10.53.0.1とresolvectl domain dns0 '~lab.internal'を実行します。~が付いたドメインは、「このドメインのクエリは、このリンクのサーバーへ送る」というルーティングルールです。確認はgetent hosts app.lab.internalで、10.53.0.10が出力される必要があります。
/etc/hostsが勝つ
/etc/hostsに10.53.0.99 db.lab.internalを入れ、getentとdig @10.53.0.1の答えを /root/dns/hosts.txt にgetent=・dig=の2行で保存してください。
echo '10.53.0.99 db.lab.internal' >> /etc/hostsを実行します。そのあとgetent hosts db.lab.internal | awk '{print $1}'とdig @10.53.0.1 db.lab.internal +shortを実行します。2つの値は異なります。それがこのステップの要点です。
学んだこと
/root/dns/report.md に、stub=・upstream=・local=の3行、dnsmasqのクエリログからapp.lab.internalの行1つ、そして/etc/hostsがDNSに優先される理由を書いてください。
stubはステップ1のnameserver、upstreamはステップ2の値、localは自分のdnsmasqのアドレスです。ログはjournalctl -u dnsmasq --no-pager | grep 'query\[A\] app.lab.internal'で取り出します。理由には、nsswitchまたはfilesという語を含める必要があります。