2026年9月8日
2026年9月8日
systemd-resolved のDNSキャッシュ汚染対策手順
systemd-resolvedを使うLinuxサーバーで、偽のDNS応答がキャッシュされる(キャッシュ汚染)リスクを下げるには、「問い合わせ先を固定する」「問い合わせ経路を暗号化する」「LLMNRなどの不要な名前解決を止める」「疑わしいときにキャッシュを消して検証する」の4点を押さえます。この記事では、現在の設定の確認方法から、resolved.conf のドロップイン設定、DHCPから配られるDNSの扱い、汚染を疑ったときの確認手順までを順に説明します。設定変更の前に現在の設定ファイルを控え、SSH以外の接続手段(コンソールなど)を確保したうえで、まず検証環境で試してください。
systemd-resolved で何が汚染されうるのか
systemd-resolvedは、ローカルの 127.0.0.53 で待ち受けるスタブリゾルバとして動き、上流のDNSサーバーから受け取った応答をキャッシュします。アプリ(PHP、curl、メール送信など)はこのスタブに問い合わせるため、ここに偽の応答が入ると、そのサーバー上のすべてのアプリが偽の宛先へ接続します。
汚染の入り口として現実的なのは、次のようなものです。
- 上流のDNSサーバーまでの経路上で、応答を偽装・改ざんされる。
- DHCPなどで、意図しないDNSサーバーを設定される。
- LLMNRやmDNSで、同じネットワーク内の別の機器が勝手に名前に答える。
/etc/hostsが書き換えられる(systemd-resolvedは既定でhostsも読みます)。
DNSのプロトコル自体の弱点に対する本格的な対策(送信元ポートのランダム化など)は上流のフルリゾルバの役割で、systemd-resolved側でできるのは、信頼できる上流を選び、そこまでの経路を守り、余計な入り口を閉じることです。
現在の設定を確認する
まず、systemd-resolvedが実際に名前解決を担っているか、どのDNSサーバーを使っているかを確認します。
ls -l /etc/resolv.conf
resolvectl status
/etc/resolv.conf が /run/systemd/resolve/stub-resolv.conf へのシンボリックリンクなら、アプリはスタブ経由で問い合わせています。resolvectl status では、全体設定(Global)とインターフェースごとの設定が表示されます。「Current DNS Server」「DNS Servers」に見覚えのないアドレスがないか、DNSSEC や DNSOverTLS(DoT)の状態がどうなっているかを確認します。
対策1:問い合わせ先を固定し、DoTで経路を守る
設定は /etc/systemd/resolved.conf を直接書き換えるより、ドロップインファイルに分けると、パッケージ更新時の衝突を避けられ、元に戻すのも簡単です。
sudo mkdir -p /etc/systemd/resolved.conf.d
sudo nano /etc/systemd/resolved.conf.d/hardening.conf
[Resolve]
# 信頼する上流のDNSサーバー(#以降は証明書の検証に使うサーバー名)
DNS=1.1.1.1#cloudflare-dns.com 1.0.0.1#cloudflare-dns.com
# 設定が無いときに使われる組み込みの予備サーバーを無効化
FallbackDNS=
# 上流との通信をDNS over TLSで暗号化(非対応の上流では名前解決できなくなる)
DNSOverTLS=yes
# すべての問い合わせをこの設定のサーバーへ送る
Domains=~.
# 同一ネットワーク内での名前解決は使わない
LLMNR=no
MulticastDNS=no
DNSOverTLS=yes にすると、上流までの通信が暗号化され、TLSの証明書でサーバーを確認するため、途中での偽装や改ざんが難しくなります。DNSサーバーの後ろに #サーバー名 を付けるのは、証明書の名前を検証させるためです。上流がDoTに対応していないと名前解決が止まるので、利用するDNSサービスの対応状況とサーバー名を、提供元のドキュメントで確認してください。社内DNSを使う環境では、社内DNSのアドレスを指定し、DoTが使えなければ DNSOverTLS= の行は外します。
FallbackDNS= を空にすると、DNSサーバーが一つも設定されていないときに組み込みの予備サーバーへ問い合わせる動作を止められます。問い合わせ先を把握しておきたいサーバーでは、空にしておくほうが管理しやすくなります。
対策2:DNSSECの扱いを決める
DNSSEC= には yes、allow-downgrade、no などを指定できます。yes はDNSSECの署名を自前で検証し、偽の応答を拒否できますが、DNSSECに対応していない上流やネットワーク機器があると名前解決に失敗することがあります。allow-downgrade は上流が対応していなければ検証をあきらめる設定で、man ページでもダウングレード攻撃に弱い点が説明されています。既定値はディストリビューションによって異なります(2026年10月現在)。
現実的な選択肢は二つです。一つは、DNSSECを検証するパブリックDNSや社内のフルリゾルバを上流にし、そこまでをDoTで守る方法です。もう一つは、検証環境で DNSSEC=yes を試し、利用するドメインで失敗が起きないことを確かめてから本番に入れる方法です。いきなり本番で yes にすると、外部APIやメール配送が止まる原因になるので避けてください。
対策3:DHCPやネットワーク設定から入るDNSを制御する
Domains=~. を指定しても、インターフェースごとのDNS設定がDHCPから配られていると、意図しないサーバーが使われることがあります。サーバー用途では、DHCPから受け取るDNSを使わない設定にしておくと安全です。
Netplanを使う環境(Ubuntu Serverなど)の例です。
network:
version: 2
ethernets:
eth0:
dhcp4: true
dhcp4-overrides:
use-dns: false
NetworkManagerを使う環境では、接続ごとに nmcli connection modify 接続名 ipv4.ignore-auto-dns yes のように設定します。インターフェース名や接続名は環境に合わせて置き換えてください。変更後は sudo netplan try のように、問題があれば元に戻る手段を使って適用します。
設定を反映して確認する
sudo systemctl restart systemd-resolved
resolvectl status
resolvectl query example.com
resolvectl status で DNSOverTLS や LLMNR の状態、使われているDNSサーバーが意図どおりか確認し、resolvectl query で実際に名前解決できるかを試します。WordPressのサーバーなら、更新の確認や外部APIへの通信が通るかも合わせて確認します。うまくいかないときは journalctl -u systemd-resolved でエラーを確認し、ドロップインファイルを外して再起動すれば元の動作に戻ります。
汚染を疑ったときの確認手順
接続先がおかしい、証明書エラーが急に出る、といった場合は、次の順で確認します。
resolvectl query 対象ドメインの結果と、dig @権威DNSサーバー 対象ドメイン +norecurseの結果を比べる。/etc/hostsに覚えのない行が追加されていないか確認する。resolvectl statusで、使われているDNSサーバーが変わっていないか確認する。- 問題があれば
sudo resolvectl flush-cachesでキャッシュを消し、resolvectl statisticsで件数が減ったことを確かめてから再度問い合わせる。
hostsやDNS設定が書き換えられていた場合は、DNSの問題ではなくサーバーへの侵入を疑う必要があります。キャッシュを消すだけで済ませず、ログの確認や認証情報の変更など、侵入時の対応に切り替えてください。
まとめ
- systemd-resolvedのキャッシュに偽の応答が入ると、そのサーバーのすべてのアプリが影響を受ける。
- 設定はドロップインファイルで行い、問い合わせ先の固定、
FallbackDNS=の無効化、DoTによる経路の暗号化を検討する。 - LLMNRとmDNSはサーバーでは止め、DHCPから配られるDNSも使わない設定にしておく。
DNSSEC=yesは失敗のリスクがあるため、検証環境で試してから入れる。- 汚染を疑ったら、権威DNSの結果やhostsと比べ、キャッシュを消して再確認する。設定の改ざんがあれば侵入として対応する。