DNSクエリをホップごとに追い、本当の送信元を突き止める
クライアントに押し付けたリゾルバアドレスは、クエリの行き先を決めるだけで、リゾルバが見る送信元までは決めない。クライアント、フォワーダ、受け取るサーバを順に追い、経路を書き残す。
クライアントにリゾルバアドレスを渡しても決まるのはクエリの送り先であり、リゾルバが見る送信元ではない。ルーティング、転送、アドレス変換が両端のあいだで順番に介在する。送信元の疑問に向けた手順書は、クエリをホップごとに追い、各観測点が実際に何を見たかを記録する。順序が重要なのは、観測より前に立てた主張は、見栄えのよい推測にすぎないからだ。
証拠を集める前に構成を書き出す
DNSの送信元について何かを教えてくれる場所は四つあり、どれも同じことを言うわけではない。クライアントのカーネルはどの送信元を使うかを知り、フォワーダは上流へ何を送ったかを知り、変換する機器は何を書き換えたかを知り、受け取るリゾルバは何が届いたかを知っている。何かを集める前に、そのうちどれに実際に手が届くのかを書き出しておく。
| Observation point | What it can prove | What it cannot prove | How to read it |
|---|---|---|---|
| client kernel | which source address it would use for that resolver | anything a device in between rewrote | ip route get against the resolver address |
| forwarder | that it sent an upstream query, and from which source | what the client originally asked for | its own log and its cache state |
| translating device | that a source was rewritten, and to what | whether the query was legitimate | NAT policy and its counters |
| receiving resolver | the address that actually arrived | which client behind that address asked | a scoped capture on port 53 |
自分の予想も、使われていると考えているリゾルバも含めて書いておく。分割経路はクエリをまったく別の場所へ送りうるし、キャッシュは上流とのやり取りなしに応答しうるので、頭の中だけに置いた前提は最初の驚きで崩れる。宣言した設計と観測した経路は同じ記録の別々の欄に置き、両者が食い違ったときには追いかける価値のある問いが見つかったことになる。
クエリを実際に送ったプロセスを確かめる
クライアントから始め、リゾルバアドレス、クエリ名、時刻を記録したうえで、どのプロセスが送ったのかを確認する。下の最初の行は UDP ソケットを保持しているプロセスを示しており、それがこの見出しの約束する確認だ。そのプロセスがシステムのリゾルバではなくブラウザの補助プロセスやコンテナのランタイムなら、残りの追跡が描くのは誰も尋ねていない経路である。
ss -tunp 'dport = :53'
dig @10.20.30.53 host.corp.example +noall +answer
ip route get 10.20.30.53
複数のインターフェースを持つホストでは、ほかを調べる前に、カーネルがその宛先に対してどの送信元アドレスを選ぶのかを突き止める。経路が完全に自分の制御下にある最後の点がそこであり、リゾルバの報告と比べる値もそれだ。食い違えば、途中の何かがパケットを書き換えたか、二つの異なるクエリが出たということになる。
テスト用の名前は内部に留める。内部名を公開リゾルバに送っても内部経路の何も証明できず、公開する必要のない名前を公開してしまううえ、安全な DNS を有効にしたブラウザはそのソケット一覧にまったく現れないが、その不在こそが答えである。
フォワーダは二度目のおのずから別のクエリを出す
フォワーダは一回のやり取りを二回に変える。下流の要求が届くと、フォワーダは自分で選んだアドレスから自分のクエリを上流へ送る。上流のリゾルバが何を見るかを決めるのは、クライアントではなくその設定である。
dnsmasq のマニュアルが読む価値のあるのはそのためで、フォワーダが上流サーバをどう選び、待ち受け側をどう束ねるかが書かれており、その構成のどこにもクライアントの送信元は上流へ運ばれない。だからゲートウェイのアドレスが載ったリゾルバのログは正常であって、障害の証拠ではない。不在も同じくらい読み違えやすく、キャッシュヒットは上流クエリを一切生まず、決して届かなかったクエリと見分けがつかない。どちらの結論を出す前に、フォワーダの設定とキャッシュの状態を読むこと。問いは二つ、見る場所も二つ。
受け取るリゾルバ側で送信元を読む
これを決着させる唯一の観測はサーバ側で取る。クライアントのインターフェース一覧から推測したことは、リゾルバが実際に何が届いたかを報告するまで仮説にすぎない。
tcpdump -ni any port 53 and host 10.20.30.53
リゾルバのホストで取得し、取得は短く範囲を絞って、ポリシーが許す場所に保存する。観測された送信元が変換後のアドレスなら、次に問うのはどの機器が変換したのか、そのポリシーが意図したものかどうかだ。取得が答えるのは何が届いたかであり、ポリシーがなぜ許したかは説明しない。記録に観測点とホップを書くのは、ゲートウェイについてのプライバシーの主張が経路全体ではなくそのホップについての主張だからだ。
所見はアドレスではなく経路として書く
クライアント、リゾルバ、介在するフォワーダ、各ホップで観測した送信元、それを律するポリシーを記録する。その記録があれば、以後の多くの問いは追加の取得なしに答えられる。鎖として描くのは、アドレスの一覧ではどのホップがどれを生んだのかが隠れてしまうからだ。
図には日付、クライアントの版、設定のリビジョンを添え、後から読む人がそれがまだ当てはまるか判断できるようにする。転送の送信元は、サービスが扱うほかのすべてと切り分ける。ゲートウェイのアドレスが見えることは、ほかに何が保持されるかを何も語らない。リゾルバの所在もどのクライアントが尋ねたかを語らないので、これらの主張を切り分けておくことが、レビューに耐える結論を生む。