ISP が DNS をハイジャックしていた
ホームラボのコンテナが 1 つのサイトに到達できなかった。DNS の応答は ISP 自身を指していた。Hegde が証拠を順にたどり、Unbound、DNSSEC、DoH が何を守れて何を守れないのかを明らかにする。
日本語
コピー

ある退屈な土曜日の午後、homelab のいくつかの問題を片付けることにした。そのひとつが、Podman コンテナから外部サイトにどうしても接続できない、というものだった。
ほぼ即座に「Site cannot be reached」が出た。DNS の設定が怪しいと踏んで、そのドメインに対して dig を実行した。Google DNS、Cloudflare と、いくつかのリゾルバを片っ端から試した。ほとんどが同じ IP アドレスを返す。ところが Cloudflare の DoH エンドポイントで試すと、まったく別の IP アドレスが返ってきた。
「は?」——これがそのときの率直な反応だった。
最初の DNS 解決で得た IP の所有者を調べてみると、出てきたのはよりにもよって自分の ISP だった。そこでようやく、ISP が DNS クエリをハイジャックし、改ざんされた IP アドレスを返していることに気づいた。



明らかな解決策は DoT(DNS over TLS)か DoH(DNS over HTTPS)だ。このことをポストしたら、なぜかバズった。
だがリプライを眺めていると、誤解や疑問が少なからず見つかった。いちいち返信するのは無理だ。
というわけで、この記事でそのいくつかに答えるとともに、いくつかの誤解を解いておきたい。
Unbound を自前で立てているから安全
知らない人もいるかもしれないが、Unbound は要するに DNS リゾルバで、Cloudflare が 1.1.1.1 で動かしているものと似ている。違いは、ローカルで動かせることだ。ルートサーバーから始めて、そのドメインの権威サーバーにたどり着くまで DNS サーバーを順に問い合わせ、ドメインの IP アドレスを特定する。
問題はまさにそこにある。DNS 解決は 1 本の接続で完結しない。リゾルバが IP アドレスを特定するには複数の DNS サーバーと通信する必要があり、そうしたクエリは伝統的に平文 DNS、たいていは UDP で送られる。つまり、そう、ISP はあなたの DNS トラフィックを覗き見ることも改ざんすることもできる。
ただし、Unbound に forward-zone を設定する手はある。こうすると Unbound は自分で DNS クエリを解決せず、別の DNS リゾルバに転送する。転送先が DoT に対応していれば、その間の接続は暗号化され、ISP が転送中の DNS クエリを勝手に覗いたり改ざんしたりはできなくなる。
DNSSEC を使えばいい
ここでの防御は DNSSEC だと思っている人がいる。無理もない。名前からして DNS と Security だ。ある意味その通りだが、DNSSEC が担うのは検証であって暗号化ではない。
DNSSEC は DNS トラフィックをリゾルバに送る前に暗号化するものではない。暗号学的な署名によって、DNS データが本物で改ざんされていないことを検証する。問題は残ったままだ。DNS トラフィックは転送中も暗号化されていない。つまり ISP は相変わらず覗き見できるし、応答に手を加えることもできる。
しかも DNSSEC の検証が機能するには、問い合わせるドメイン側で DNSSEC が正しく設定され、有効な署名と信頼の連鎖が存在している必要がある。ここにもうひとつ問題がある。2026 年 10 月の Defaults.Exposed 調査によれば、評価対象ドメインのうち有効かつ完全に検証可能な DNSSEC チェーンを持つのは 7.03% にすぎない。
改ざんされた応答が DNSSEC の検証を通らなければ、リゾルバは偽の IP アドレスを渡す代わりに SERVFAIL を返す。
DoH と DoT は改ざんを防げない
その通り。DoT と DoH は、クエリの送り先の DNS リゾルバを信頼することを前提にしている。接続を暗号化するので、ISP が転送中の DNS トラフィックを勝手に覗いたり改ざんしたりはできない。だが、リゾルバ自身が応答に細工をしないという保証はない。DNS サーバーの運営者を依然として信頼していることに変わりはない。
そもそも ISP にはどのサイトか見えている
確かに。通常のインターネットトラフィックは TLS で暗号化されるが、ISP は TLS ハンドシェイク時にホスト名(SNI)を見ることができる。宛先 IP だけでどのサイトか分かることもある。
もちろん、トラフィックを VPN トンネル経由にすれば別だ。自分は Tailscale の exit node 機能で Mullvad を使っている。
とはいえ、これでは信頼の一部を VPN プロバイダに移しただけにすぎない。それはまた別の話だ。
で、自分の構成はどうなっているのか
Pi-hole/AdGuard は 3 年以上使っている。振り返れば、セルフホストに初めて触れたきっかけがこれだった。
だが、すべてのコンテナをローカル DNS サーバー経由にしていないのには、もうひとつ理由がある。コンテナを更新するとき、何か問題が起きて DNS サーバーが落ちると、それに依存する他のコンテナの DNS 解決まで巻き添えにしたくない。だから一部のコンテナには、外部 DNS リゾルバをフォールバックとして用意している。
現在、DNS には AdGuard を使っていて、上流の DNS クエリは dnscrypt-proxy が DNSCrypt で処理している。だから DNS トラフィックは転送中も暗号化されている。DNS 障害がどうしても許されないコンテナには、Cloudflare をフォールバックとして設定してある。とはいえ、プライマリ DNS は今もローカルの AdGuard だ。
サーバーでは NixOS も動かしている。興味があれば、dotfiles はオープンソースだ。