テレビのアニメはどこから来る? / 第45話

第45話:イトは、三つの赤ランプを同じ修理で直さなかった|DNSエラーは何が違う?

ピコルート第45話。三つの通信失敗を同じDNSエラーだと思ったイトが、NXDOMAIN・SERVFAIL・timeoutの証拠を分け、それぞれ別の原因を直します。

NXDOMAINとSERVFAILtimeoutはRCODEではない正確な問い合わせ条件DNS応答の証拠10分更新

第44話で、イトは古いcacheとauthoritative answerを別々のtrayへ置いた。

同じaddressでも、返した場所と時刻が違えば、意味も違う。

そのtrayを片づけていると、検証台の奥で赤いlampが三つ点いた。

どのprojectorにも、festival pageが映っていない。

左のlaneにも、中央のlaneにも、右のlaneにも、同じ札が下がっている。

DNS error

「三つとも、名前が見つからないんだ」

イトは三本の修理leverを、一枚の真鍮barでつないだ。

一つを倒せば、三つのDNS設定へ同じaddressを書き込める。

rehearsal開始まで、あと四分。

イトはguessed A recordを入力し、bulk writeの蓋へ手をかけた。

同じ赤でも、同じ失敗とは限らない

ピコはbulk writeを止めなかった。

代わりに、三つのlaneの受け皿を照らした。

左と中央には、DNS responseの封筒が落ちている。

右の受け皿は空だった。

イト

でも、画面は全部同じように開かないよ

ピコ

画面の結果が同じでも、DNSから返事が来た失敗と、時間内に返事を観測できなかった失敗は分けられるよ

イト

赤lampの名前だけでは、直す場所を決められない?

ピコ

うん。まず、何をどこへ聞いて、どんなresponseを受け取ったかを残そう

この話で使うのは、外のInternetへつながっていない閉じた学習fixtureだ。

festival.example以下の名前も、serverも、故障も、lessonのために用意されている。

実在するpublic DNSの障害原因を再現したものではない。

まず、問い合わせそのものを固定する

DNSの結果を見る前に、イトはquery cardへ条件を書いた。

「同じsiteを調べたつもり」では足りない。

stage.festival.exampleへのA queryと、www.festival.exampleへのAAAA queryは、別の質問だ。

質問が違えば、answerが違っても不思議ではない。

responseが来たら、headerのRCODEだけでなく、AA bit、answer / authority / additional sectionも同じ証拠cardへ残す。

responseが来なければ、存在しないRCODEを想像で書かず、何秒待ってresponseを観測できなかったかを残す。

左の封筒:NXDOMAIN

左のlaneで、イトは同じqueryをもう一度送った。

QNAME: stgae.festival.example
QTYPE: A
response: received
RCODE: NXDOMAIN
AA: 1

RFC 1035のRCODE 3はName Error、現在よく呼ばれる名前ではNXDOMAINだ。

authoritative serverから返るNXDOMAINは、そのqueryで指定したnameが存在しないことを示す。

ただし、NXDOMAINだけを見て「人が綴りを間違えた」とまでは決められない。

本当に登録されていないnameでも、古いlinkでも、fixtureの故障でも、観測されるresponseはNXDOMAINになり得る。

今回、綴りの入れ替わりを示したのはRCODEではない。

rehearsal task cardには、exact hostとしてstage.festival.exampleと書かれていた。

イトが送ったのは、stgae.festival.exampleだった。

二枚を重ねて、初めてfixture固有の原因が見つかる。

RFC 2308では、NXDOMAINのようなnegative responseも、SOAを使った決められた時間の範囲でcacheされ得る。

一度綴りを直しても、別のcache layerに以前のnegative answerが残る場合がある。

だから、直した時刻と、どのresolverへ再queryしたかも捨てない。

「名前はあるが、その種類のdataがない」は別

ピコは、NXDOMAIN封筒の横に薄い見本を置いた。

RCODE: NOERROR
requested RRset: no answer

これはNXDOMAINと同じではない。

name自体は存在していても、求めたQTYPEのresource recordがないresponseはあり得る。

たとえばA recordはなく、別の種類のrecordだけがある場合だ。

このようなnegative answerはNODATAと呼ばれる。

「answer sectionが空だからnameも存在しない」とは決めない。

この見本は三laneの故障には使わない。

NXDOMAINと空のanswer sectionを同じ箱へ入れないための境界だけを残す。

中央の封筒:SERVFAIL

中央のlaneにも、responseは来ていた。

QNAME: stream.festival.example
QTYPE: A
response: received
RCODE: SERVFAIL

RCODE 2のSERVFAILは、serverがqueryを処理できなかったresponseだ。

「そのnameは存在しない」というanswerではない。

validation、依存先、内部処理など、失敗の背景には複数の可能性がある。

SERVFAILだけを見て、原因を一つに決めない。

このfixtureでは、responseをSERVFAILとして分類したあとにだけ、debug panelを開ける。

panelの内側で、上流dependencyのplugが外れていた。

それは今回の閉じたfixtureが意図的に作った原因であって、「SERVFAILなら必ず上流plug」と覚える規則ではない。

RFC 8914のExtended DNS Errors(EDE)があれば、粗いRCODEへ追加のcontextが添えられることもある。

けれど、EDEは常に付くわけではない。

途中で失われることもあり、付いていてもsecurity checkを迂回してよいという自動命令ではない。

右の空tray:timeout

右のlaneでは、待ち時間が過ぎてもDNS responseを観測できなかった。

QNAME: live.festival.example
QTYPE: A
response: not observed
elapsed: fixture limit reached

trayにRCODE封筒はない。

timeoutは、DNS messageのRCODEではないからだ。

packet lossかもしれない。

経路やfilteringかもしれない。

serverが応答していないのかもしれない。

指定したtransportや待ち方に問題があるのかもしれない。

「返事を観測できなかった」だけでは、その先を一つに決められない。

このfixtureには、lane内部だけを見られる透明な点検窓がある。

query条件とelapsed timeを記録したあとで窓を開けると、transport shutterが閉じていた。

これも今回だけの追加証拠だ。

timeoutという言葉だけが、shutterを見つけたわけではない。

browserの文言を、そのままRCODEにしない

三台のprojectorには、どれも似た「server addressを見つけられない」という画面が出ている。

しかし、browserの表示は利用者向けの要約だ。

OS、browser、resolver、networkのどこで失敗を受け取ったかにより、表現やまとめ方は変わり得る。

画面の文言を、そのままprotocol上のRCODEだとは扱わない。

RFC 9499が整理するDNS用語に戻り、実際のqueryとresponseを観測する。

なお、RCODE 5のREFUSEDが返る場合は、serverがpolicy上そのqueryの処理を拒否したresponseだ。

これもNXDOMAINとは違い、nameの不存在を意味しない。

イトの前に、三つの選択肢が浮かぶ

rehearsal開始まで、あと二分。

bulk writeの蓋が赤く点滅した。

一枚の真鍮barは、まだ三本の修理leverをつないでいる。

A 三つのnameへ、guessed A recordをまとめて書く

NXDOMAIN、SERVFAIL、timeoutの違いを消したまま、authoritative dataへ変更を加える。

原因がDNS recordにないlaneまで書き換え、元の証拠もchange historyも濁らせる。

B 三つのprojectorで、reloadを連打する

browser画面が変わるのを待つだけでは、query先、response、RCODE、elapsed timeが残らない。

直ったとしても、何が変わったのか分からない。

C 同じ修理を外し、response封筒と空trayを分ける

三laneそれぞれのexact QNAME / QTYPE / targetを固定する。

responseが来たlaneではRCODEとsectionsを残す。

来なかったlaneではelapsed timeを残す。

そのうえで、fixture固有の追加証拠に合う修理だけを行う。

ピコはbulk writeの蓋から手を離した。

「選ぶのは、イトだよ」

イトはguessed A recordを消した。

「同じ赤lampでも、同じ返事とは限らない」

イトはCを選んだ。

三本の修理leverを横切るsame-fix barを、自分の手で外した。

左へNXDOMAINの封筒。

中央へSERVFAILの封筒。

右へ、elapsed timeだけが残る空のtimeout tray。

三枚のquery cardは、別々のlaneへ置いた。

イトが三本の赤lamp付きlaneを横切る一本の真鍮barを外し、左のname treeが途切れたresponse封筒、中央の止まったgear付きresponse封筒、右の砂時計だけが残る空のtimeout trayを別々に観察している
同じ「pageが開かない」でも、responseが返った失敗と、responseを観測できなかった失敗を同じ修理leverで動かさない。

三つの修理が、別々に動く

イトは左のquery cardとtask cardを並べた。

stgaeとstage。

authoritative dataへguessed recordは足さず、applicationが送るhostをstage.festival.exampleへ直す。

同じresolverへ、修正時刻を付けて再queryした。

今度はA answerが返り、左のtest lampがgreenへ変わった。

中央では、SERVFAIL封筒を残したままdebug panelを開く。

外れていたfixtureの上流dependencyだけを接続し直す。

同じqueryをretryすると、NOERRORとA answerが返った。

中央のlampもgreenになる。

右では、空のtimeout trayを捨てない。

点検窓で閉じたshutterを確認してから、イトがtransport shutterを開ける。

同じtargetへ同じqueryを送り、同じfixture limitまで観測した。

今度はresponse封筒がtrayへ落ちた。

右のlampもgreenへ変わる。

三台のprojectorに、それぞれ違うfestival pageが映った。

bulk DNS overwriteは、一度も実行されていない。

赤lampではなく、残った証拠を見る

rehearsal clockが止まった。

イトはgreen lampだけを見て、三つのtrayを重ねなかった。

左には、綴りを直す前のNXDOMAIN封筒とexact query card。

中央には、dependencyを戻す前のSERVFAIL封筒。

右には、responseの代わりにelapsed timeを記録した空tray。

外した真鍮barは、壁のhookに掛けたままだ。

一つの赤い札から一つの原因を当てる道具としては、もう使わない。

responseが返った失敗と、返事を観測できなかった失敗を分ける。

exact query evidenceを残し、原因を一つに絞れる追加証拠が揃うまでは、同じ修理を一括で走らせない。

「error名は、修理の答えじゃない」

イトは三枚の証拠cardを、別々の透明pocketへ差し込んだ。

そのとき、左のprojectorへ新しい画面が出た。

addressは得られている。

serverからresponseも返っている。

でも、指定したpageだけが見つからない。

次回:serverまで届いたのに、部屋がない

今度の札には、DNSのRCODEではない数字があった。

404

「これは、名前を見つけられなかった赤lampとは違う」

イトはDNSの三つのtrayを閉じ、server図書館の扉を開けた。

次回、ピコルート第46話。

イトは、届いた404をDNSへ戻さなかった|Not Foundはどこから返る?

この物語を、解説で深める

第45話で生まれた疑問を、解説記事で少し深く見ていきます。物語で感じた不思議さを残したまま、言葉と仕組みを順番に整理しましょう。

DNSエラーとは|名前解決で止まる原因と確認手順を読む