クライアントで広告がまだ表示され、Pi-hole は自分を正常と報告し、トンネルも稼働している。だからそのクライアントの通信を Pi 経由でルーティングしたくなる。それは間違った曲がり角だ。フィルタリングに必要なのはパケットではなく問い合わせであり、クエリがプロバイダーのリゾルバーに送られるクライアントは、通信がどこを流れてもフィルタリングされないままだ。この一覧を順に進め、最初に失敗した手順で止めること。前の手順が壊れている間は、後の手順は何も教えてくれない。

1. クライアントが実際に使っているリゾルバーを読む

ルーターではなくクライアントに聞く。Linux では resolvectl status がリンクごとの DNS サーバーとどのリンクが優先されるかを表示する。 /etc/resolv.conf 単体は通常 127.0.0.53 を指すスタブだ。Windows では ipconfig /all がアダプターごとに DHCP で配布されたサーバーを一覧し、macOS では scutil --dns がスコープごとに同じものを表示する。答えが Pi-hole のアドレスでなければ割り当ての問題であり、手順 2 がその在りかだ。

システムのリゾルバーが正しく設定されていても、二つのものに敗れる。独自のセキュア DNS を持つブラウザー(Chrome の “Use secure DNS”、Firefox の network.trr.mode)は HTTPS で公開リゾルバーにクエリを送り、ポート 53 を決して開かない。そしてクライアント上の VPN クライアントが、トンネルインターフェースに ~. のルーティングドメイン付きで DNS サーバーをインストールすることがあり、それによりそのリンクがすべての名前に対して権威を持つ。

アプリケーションが通る経路をテストし、デバッグツールが通る経路をテストしない。resolvectl query example.com はどのリンクが答えたかを示し、getent hosts example.com はアプリケーションと同じ NSS 経路を通る。macOS では dscacheutil -q host -a name example.com が scutil --dns の一覧するスコープ付きリゾルバーを読む。素の dig はこれをせず、 /etc/resolv.conf を読んでリンクごとの選択を飛ばすため、すべてのアプリケーションがプッシュされたリゾルバーを使っているのに Pi-hole から答えることがある。これがこの一覧の存在理由である失敗そのものだ。特定のサーバーを試すには dig @192.168.1.53 を残す。

2. 誰が答えを配っているかを確認する

割り当ては DHCP に答える何かから来る。dnsmasq では一行、dhcp-option=6,192.168.1.53 だ。ルーターの Web UI では LAN の DHCP セクションの DNS フィールドだ。クライアントはそれを見る前に更新しなければならない。何日も起動している機器はまだ古いリースを保持しており、手入力のリゾルバーを持つ機器は永久にそれを保持する。伝播を仮定せず、テスト用クライアントで更新すること。

IPv6 は見落とされる半分だ。ルーター広告は独自の DNS サーバー(RDNSS)を運ぶことがあり、OpenWrt では odhcpd の ra_dns オプションがそれだ。IPv6 を優先するクライアントはそのサーバーを使い、たった今設定した DHCPv4 オプションは未使用のままになる。IPv6 の DNS を提供する準備ができていないなら、DNS 広告だけを消すこと:odhcpd の ra_dns、あるいはルーター広告に答えるものの中の RDNSS オプションだ。広告全体を切ると LAN から IPv6 アドレッシングも消え、意図したよりはるかに大きな変更になる。一方 DNS オプションだけを消せばアドレッシングは無傷のまま残り、欠けている RDNSS がパケットキャプチャで見えるようになる。

3. クエリが Pi-hole に届くことを証明する

Pi からのクエリはネットワーク経路について何も証明しない。クライアントから実行し、応答コードを読むこと:

dig @192.168.1.53 example.com
dig @192.168.1.53 doubleclick.net

タイムアウトはフィルタリングかルートを、REFUSED はアクセス規則を、SERVFAIL は Pi-hole 背後の上流リゾルバーを示し、クエリログに決して現れない正しい応答はクライアントが別のことを尋ねたという意味だ。UDP と TCP 53 を確認すること。大きな応答や一部のリゾルバーは TCP にフォールバックし、Pi-hole がコンテナーで動く場合は両方を公開する。UDP だけを覆うマッピングは、パケット損失のように見える断続的な失敗を生む。

次に Pi-hole のリッスンモードが、そもそも応答するかどうかを決める。ローカルのみのモードでは、dnsmasq は直接接続されたサブネット上にない送信元からのクエリを無視する。別のルーターの背後にいるクライアントやトンネル経由で来るクライアントはまさにそう見える。クライアントはタイムアウトし、クエリはログに決して届かない。それでも REFUSED として現れるクエリは、代わりにアクセスリストやファイアウォール規則で拒否されたものだ。すべての送信元を許可するのが通常の修正で、ポート 53 を自分のサブネットに限定するファイアウォール規則と組み合わせる。

4. トンネルが応答を置き換えたのか飲み込んだのかを確認する

これが両方の症状が潜むケースだ。ルーター自身が VPN クライアントのとき、プッシュされた DNS オプションがトンネルが上がった瞬間に LAN の設定を上書きすることがある。OpenVPN サーバーは dhcp-option DNS をプッシュし、WireGuard プロファイルは独自の DNS エントリーを持つ。トンネルを上げた状態でルーターの実効リゾルバーを読み、その前には読まず、LAN ページの主張は無視すること。

もう一つの不具合は置き換えではなく到達性だ。トンネルの許可プレフィックスに LAN サブネットが含まれていると、ルーターには 192.168.1.53 へのクエリをトンネルへ送るルートがあり、反対側には戻りルートがない。トンネルが健全でもクエリはタイムアウトする。逆は Pi-hole がトンネルの運ばないサブネットにあるときに起きる。DNS に再び触れる前に、アドレスをトンネルの許可プレフィックスとルーターのルートテーブルと照らし合わせること。

両方ではなく一つの修正を選ぶ。トンネルを DNS から遠ざけるか — OpenVPN で pull-filter ignore “dhcp-option DNS”、WireGuard で AllowedIPs に LAN プレフィックスを入れない —、プッシュされたリゾルバーを受け入れてそのルーター背後のクライアントのローカルフィルタリングを諦めるかだ。どちらを選んでもプロファイルの隣に書き残すこと。そうしなければ次に編集する人が誤って決定を覆す。

5. 再接続後にテストを繰り返す

クライアントからクエリを行い、そのクライアントが Pi-hole のログに現れることを確認し、次にブロックされるべきドメインを解決して、実際の応答ではなくブロック応答が返ることを確かめる。トンネルを再接続し、同じ二つのクエリを実行すること。次の接続までしか持たないリゾルバー設定は、間違った層に適用した修正のよくある結果だ。

トンネルに依存しない二次リゾルバー経路を残し、Pi-hole の停止がブラウジング不能ではなくフィルタリングなしのブラウジングに劣化するようにする。テストが二回通るまで以前の DHCP とリゾルバーの値を保つこと。夕食時に家庭のインターネットを壊す変更は、一分で戻せる変更よりはるかにデバッグが難しい。

関連記事