digを読む順序
一言でいうと
digの出力は、上から読むのではなく、status → flags → 各セクションの順に読みます。この順序を守れば、1つの応答で原因が分かれます。
なぜ必要なのか
「DNSが使えない」という報告には、少なくとも5つの異なる状況が混ざっています。名前がそもそもないもの、そのタイプのレコードだけがないもの、リゾルバーが答えを作れないもの、サーバーが答えることを拒否するもの、そしてキャッシュが古いもの。この5つは、対応がすべて違います。そしてdigの出力を1回見れば、5つのうちどれなのかが確定します。
どう動くのか
まず応答コードを見てみましょう。
| status | ANSWER | 実際の意味 | よくある原因 | 次にすること |
|---|---|---|---|---|
| NOERROR | 1個以上 | 名前とタイプがどちらも存在 | 正常 | 次の層へ |
| NOERROR | 0個 | 名前はあるが、そのタイプがない | Aはあり、AAAAはない。CNAMEだけがあり、参照先が未作成 | タイプを変えて再確認 |
| NXDOMAIN | — | 権威サーバーが、その名前自体がないと確定 | タイプミス、未作成、searchドメインが付いた名前 | 権威サーバーに直接問い合わせ |
| SERVFAIL | — | リゾルバーが答えを作れない | DNSSEC検証の失敗、上位の無応答、ゾーンのロード失敗 | リゾルバーのログ |
| REFUSED | — | サーバーに処理する意思がない | 再帰の不許可、ACL、ゾーンを持っていない | 問い合わせ先が正しいか |
NOERRORなのにANSWER: 0の場合が、最も紛らわしいです。名前はあるのに、そのレコードタイプだけがないのです。IPv6だけがない場合や、CNAMEは設定したのに参照先のAレコードを作っていない状況が、これに当たります。
次がflagsです。
aa: 権威のある応答です。この文字がなければ、キャッシュから来た応答です。tc: 切り詰められました。TCPで問い合わせ直す必要があります。rd/ra: 再帰の要求 / 再帰の可否ad/cd: DNSSEC検証に合格 / 検証を無効にして問い合わせ
目的別の組み合わせを使い慣れておくと便利です。
dig +short A example.com # 값만
dig +noall +answer example.com # 답변 섹션만 (TTL·타입 포함)
dig +noall +authority +additional example.com
dig @1.1.1.1 example.com # 특정 서버에 직접
dig +norecurse @10.0.0.53 example.com # 캐시에 있는지만 확인
dig -x 8.8.8.8 # 역방향
dig -t MX example.com
dig +tcp example.com
dig +time=2 +tries=1 example.com
dig +trace example.com # 루트부터 위임 추적
+traceには落とし穴があります。+traceはルートから各段階を直接問い合わせるため、手元のリゾルバーを迂回します。そのため「+traceは正常なのにアプリケーションは失敗する」がよくあり、そのときの犯人は権威サーバーではなくリゾルバー区間です。
TTLとネガティブキャッシング
同じ問い合わせをリゾルバーに繰り返すと、TTLが減っていくのが見えます。一方、権威サーバーに直接尋ねると、常に元の設定値が出ます。この違いが、「キャッシュから来たのか」を判別するいちばん簡単な方法です。
存在しない名前の結果もキャッシュされます。ネガティブキャッシュの時間は、SOAのMINIMUMフィールドとSOAレコード自身のTTLのうち小さいほうの値です。そのため、レコードを新しく作ったのに、しばらくNXDOMAINが続くことが起きます。「作ったのになぜ反映されないのか」の答えは、たいていこれです。
resolv.confの数字
nameserver 10.0.0.2
search prod.svc.cluster.local svc.cluster.local cluster.local
options ndots:5 timeout:2 attempts:3 rotate
nameserverは最大3つまでしか使われません。timeoutは既定で5秒(最大30)、attemptsは既定で2回(最大5)です。最初のネームサーバーが落ちていると、ユーザーは既定値のまま5秒を体感します。タイムアウトと試行回数を減らさなければ、冗長化があっても意味がありません。ndots:nは「ドットがn個未満なら、先にsearchドメインを付けてみる」というルールです。既定は1、最大は15です。
Kubernetesのndots:5は有名な落とし穴です。api.stripe.comはドットが2つなので5より小さく、searchドメイン4つを先にすべて付けて試したあとで、ようやく元の名前を問い合わせます。A/AAAAのペアで数えると、問い合わせ10件のうち8件が、NXDOMAINを受け取るために出ていきます。ただし、よくある助言とは違い、ndotsを1に下げるとクラスターが壊れます。payments.prodのようなネームスペースをまたぐ呼び出しが、すべて失敗するからです。安全な下限は2です。急ぐときは、名前の末尾にドットを1つ付けて(api.stripe.com.)FQDNであることを明示すれば、searchを飛ばします。
現場での姿
UDP 53だけが開いているファイアウォール。普段は何も問題がありません。応答が小さいからです。ところがレコードが増えたり、DNSSEC署名が付いたりして応答が512バイトを超えた瞬間、その名前だけが解決されなくなります。「特定のドメイン1つだけが使えない」という報告の原因が、ここにある場合があります。dig +notcp +bufsize=512で再現し、;; MSG SIZE rcvd:を見ます。
キャッシュを丸ごと消してはいけません。rndc flushは手っ取り早い方法ですが、その後の数分間、上位への問い合わせが急増します。問題になった名前だけをrndc flushname api.example.comで消すのが定石です。
次のラボですること
digでA/MX/NS/TXTを取り出し、TTLが減っていくのを観察し、逆引きを行い、NXDOMAIN応答からネガティブキャッシュの時間を計算します。最後に、hostsエントリを入れてgetentとdigの答えが分かれるのを表にして提出します。