D. J. Bernstein [translated to Japanese by Yusuke Shinyama, 2006-01-28]
Internet publication
djbdns

(訳注: 翻訳を終えてから、前野さんによる翻訳 がすでにあったことに気がついた。)

ドメイン・ネーム・システムに関するノート (Notes on the Domain Name System)

私が書いた インターネット・メールインターネット・メールのメッセージヘッダ形式SMTPFTP などのリファレンスマニュアルを見て、 DNS にもこれらと同様の総合的なものを期待しているかもしれませんが、 これはそういうものではありません。ごめんなさい。

信用されているサーバ

DNS キャッシュ (RFC 1123 によれば、“完全なサービスをおこなうリゾルバ”) が www.w3.org のアドレスを知ろうとするとき、これは w3.org の DNS サーバか、 org の DNS サーバ、あるいは root DNS サーバにアクセスする可能性があります。

たとえば、2001年 1月現在、 w3.org の DNS サーバのひとつは w3csun1.cis.rl.ac.uk になっています。 このサーバは、 www.w3.org のアドレスをコントロールする能力をもっています。 このサーバは他のサーバをあふれさせ、それらが矛盾した情報を流さないようにできます。

この DNS キャッシュが w3csun1.cis.rl.ac.uk のアドレスを知ろようとするとき、 これは rl.ac.uk の DNS サーバか、ac.uk の DNS サーバ、 あるいは uk の DNS サーバ、もしくは root DNS サーバにアクセスする可能性があります。 たとえば、ac.uk の DNS サーバのひとつである ns.eu.net は、w3csun1.cis.rl.ac.uk のアドレスをコントロールする能力をもっています。 したがって、これは www.w3.org のアドレスを定義できる能力ももっていることになります。

同様に、 eu.net 以下にあるすべての名前、 すなわち ac.uk および w3.org 以下にあるすべての名前も sunic.sunet.se によってコントロールされています。 さらに、sunet.se 以下にあるすべての名前、 すなわち eu.netac.ukw3.org 以下にあるすべての名前も beer.pilsnet.sunet.se によってコントロールされています。 そして beer.pilsnet.sunet.se は石器時代のバージョンの BIND を走らせており、 インターネット上の誰でもこのマシンを乗っとることができることが知られています。

www.w3.org の管理者は、彼らの DNS サービスが beer.pilsnet.sunet.se やら、その他 世界じゅうに散らばっている 200台ものよくわからないコンピュータに依存していることを 知っているのでしょうか?

反対に、もし w3.org が自分のネームサーバに w3.orgドメイン以下に属する (in-bailiwick な) 名前、 たとえば a.ns.w3.orgb.ns.w3.orgc.ns.w3.orgd.ns.w3.org といった名前をつけていれば、 これは ac.uk やら eu.net やら sunet.se の サーバに依存するはめにはならなかったはずです。

私はこの種の問題を 2000年 1月に指摘しました。 このとき、これらの同じ 200台ほどのコンピュータは *.com も含め、現実にインターネット上のすべての 名前をコントロールできるようになっていました。 その後、.com サーバの名前はこの問題をなくすよう 修正されています。ほとんどの国別 TLD はまだ修正されていません。

毒入れ

RFC 1034 の名前解決アルゴリズムでは、インターネット上の どんなサーバでも yahoo.com の破壊、 あるいは乗っ取りをすることができます。 nasty.dom (いじわるドメイン) サーバがすべきことは、ただ www.nasty.domyahoo.com のサーバに委譲して、 これらのサーバに対し偽のアドレスを提供するだけです:

     www.nasty.dom NS ns1.yahoo.com
     www.nasty.dom NS ns2.dca.yahoo.com
     www.nasty.dom NS ns3.europe.yahoo.com
     www.nasty.dom NS ns5.dcx.yahoo.com
     ns1.yahoo.com A 1.2.3.4
     ns2.dca.yahoo.com A 1.2.3.4
     ns3.europe.yahoo.com A 1.2.3.4
     ns5.dcx.yahoo.com A 1.2.3.4

さて、この nasty.dom サーバはキャッシュが www.nasty.dom について問い合わせてくるのを待ちます (あるいは、人々に問い合わせるよう宣伝します)。 キャッシュが答えを受け取ったとき、キャッシュは RFC 1034 に従って ニセの yahoo.com アドレスを今後の参照のために保存します。 これ以降の yahoo.com に関する問い合わせは間違った方向へ向けられます。

キャッシュの毒入れは 1990年には広く知られていました。 しかしこれは単に信頼性の問題で、ずさんな管理の結果だとしか認識されていませんでした。 munnari.oz.au を古い IP アドレスでバックアップサーバにしていた人は、 偶発的にキャッシュに毒入れをしてしまい、munnari.oz.au に きちんとアクセスする方法を失ってしまっていたでしょう。

Vixie の最初の BIND リリース、1992年のバージョン 4.9 では、 “信用性 (credibility)”機能を売り物にしていました。 これは偶発的な毒入れのうちもっとも深刻なケースをなんとか防ぐことはできました。 セキュリティの見地からみれば、Vixie の“信用性”はがらくたです。 これは上にあげた yahoo.com の攻撃すら止めることはできません。

すべての毒入れを除去する方法は明らかです。 キャッシュは yahoo.com に関する情報のうち、 yahoo.com サーバと com サーバ、 および root サーバ以外からのものを無視すればよいのです。 これは悪意ある毒入れを防ぎ、したがって偶発的な毒入れも防ぎます。 これで問題は解決です。

BIND は 1997年になって、ようやくこの毒入れ除去ルールを採用しました。 キャッシュへの毒入れがポピュラーな攻撃方法になったあとでです。 Vixie は時代遅れになった彼の“信用性”ルールを破棄したでしょうか? いいえ。2000年 1月現在、これらはいまだに BIND 8.2.2-P5 に入っており、 今まで以上に支離滅裂になっています。たとえば、もしもレコードに “additional セクションの信用性”があって、誰かがそれらのレコードに対して 問い合わせを発行したとき、BIND はそれらのレコードの TTL を 5% だけ 減少させるようになっています。 これ以外のルールのうち、いくつかは RFC 2181 に載りました。

私は 2000年 1月に、あるドメインがそのすべての DNS サーバ名を変更したとき (たとえば、ISP を変えるなどしたとき)、攻撃者は簡単に BIND の“信用性”ルールを悪用してそのドメインへのアクセスを破壊できることを bugtraq メイリングリストで指摘しました。 私はこのことを namedroppers メイリングリストでも指摘しようとしましたが、 私の投稿は Randy Bush によって検閲され削除されました

dnscache は additional レコードを差別しません。 正当なレコードは、それが 1パケット中の additional レコードであれ 次のパケットの answer レコードであれ受け付けられます。 タイミングはセマンティクスに影響しません。

制限された親

RFC 1034 では、親サーバは子サーバのすべての NS レコードを返すと仮定しています。

しかし実際には、親サーバによっては返す NS レコードの数を制限しています。 ある親サーバでは更新の手続きに非常な困難がともないます。 そして、長いあいだ .com の最大手レジストラは、NS レコードが すでに別のホスト名として登録されている IPアドレスのホスト名を 返すことを、さしたる意味もなく拒否してきました。

そのため、子サーバが親サーバよりも多くの NSレコードを返すということが、 しょっちゅうあります。これによってキャッシュは親が返してきた NS レコードを、 子が返してきた NS レコードで置き換えることになります。 もし、これらの NSレコード (とそれに関連するアドレス) が 期限切れになるのが、その答えが期限切れになったあとならば、 キャッシュは新しい答えを検索するのにこの完全な NS の一覧を使ことができ、 その時点での新鮮な NS リストを手にすることができるでしょう。 負荷はこれらすべてのサーバ間で分散されます。 もっとも親サーバがもっと多くのサーバを返していれば、 さらに均一になったでしょうが。

不幸にも BIND 8.2 は、この新鮮な NS のリストをキャッシュしません。 古いリストが期限切れになると、BIND は親サーバにアクセスし、 ふたたび不完全な NS リストを取得します。

注意: 上記の“信用性”ルールのため、 子サーバの NS レコードは親サーバの NS レコードを包含している必要があります。 さもないと攻撃者は BIND が子サーバへのアクセスを破壊できてしまいます。

グルーなしの状態 (gluelessness)

あなたは DNS キャッシュです。 www.espn.tv のアドレスを知りたいとしましょう。 あなたは、偶然 .tv DNS サーバのアドレスを知っていたとします。 そこであなたはそのサーバに www.espn.tv のアドレスを尋ねます。 すると、このサーバが言うには 「知りません。でも .espn.tv には 2つの DNS サーバがあるということは知っています。 ns-1.disney.corpns-2.disney.corp です。 彼らに尋いてみてください」

そこであなたは ns-1.disney.corp に尋ねます。 でも、 ns-1.disney.corp のアドレスは何でしょう? あなたは元々の質問をいったん脇においておき、 ns-1.disney.corp のアドレスを探します。 あなたは、偶然 .corp DNS サーバのアドレスを知っていました。 そこで、そのサーバに ns-1.disney.corp のアドレスを尋ねます。 すると、このサーバが言うには 「知りません。でも .disney.corp には 2つの DNS サーバがあるということは知っています。 zone.espn.tvnight.espn.tv です。 彼らに尋いてみてください」

結論: あなたは espn.tv にも、 disney.corp にも到達できません。

zone.espn.tv.espn.tv の DNS サーバであった場合、 .tv サーバは zone.espn.tv への グルー (glue) を提供すべきだったのです。 これは zone.espn.tv の IP アドレスのことです。 こうすれば、あなたは zone.espn.tv にアクセスできたでしょう。 RFC 1034 では、そのドメインの下に属する (in-bailiwick な) 名前を参照する場合、 とくにグルーは必要であるとしています。 (“グルー”といえばこの場合のみをさすという人もいます)

しかし、そのドメインの下に属さない (out-of-bailiwick な) 名前を参照する場合、 RFC 1034 ではグルーは必要ないと言っています。 RFC 1537 も同じことを言っています。 RFC 1912 も同じことを言っています。 comp.protocols.tcp-ip.domains FAQ には、 「グルーレコードは必要ありません。実際のところ、 それをつけるのは非常に悪い考えです」と書いてあります。 (この FAQ は偶発的な毒入れに関する古くなった参考文献です、上記参照。) DNS サーバの実装によっては、あるドメインの下に属さない (out-of-bailiwick な) グルーはデフォルトで無視するようになっています。 したがって、グルーのないドメイン espn.tv および disney.corp は このルールに従います --- つまり、結局どちらもまだ到達可能にはなりません。

循環のないときでさえ、これは問題になります。以下の状況で、 BIND キャッシュが www.espn.tv を検索すると仮定してみてください:

     espn.tv NS ns-1.disney.corp
     espn.tv NS ns-2.disney.corp

     disney.corp NS ns-1.disney.corp
     disney.corp NS ns-2.disney.corp
ns-1.disney.corp に対するグルーなしの委譲を見つけると、 BIND は www.espn.tv に対する問い合わせを忘れてしまい、 ns-1.disney.corp に対する “sysquery” を開始します。 これは www.espn.tv の検索がリトライされるまでの間に、 ns-1.disney.corp のアドレスがキャッシュされているだろうと期待してのことです (BIND 開発者はこのバグを『検索非再開 (no query restart)』と呼んでいます)。 クライアントは通常 5回以上のリトライはしないため、 4レベル以上にわたってグルーのないドメインに対する初回の検索は失敗することになるでしょう。 3レベル以上にわたってグルーのないドメインの場合、初回の検索は 失敗する確率がとても高く、成功したとしても非常に遅いものになります。

私は、2000年にこう書きました。 「私の知るかぎりでは、グルーがないためにインターネットから喪失したドメインはまだないようです」 「しかし、グルーのないドメインは徐々に増えており、 私はグルーのない DNS サーバがある、グルーのないドメインを発見しています。 キャッシュが許容できる“グルーなし度 (gluelessness)”はどの程度でしょうか? 現在のところ、dnscache では 3レベルにわたってグルーがなくても許しています。 これは今のところ十分のようですが、将来にわたっても十分でしょうか?」

その後、私は www.monty.de のことを知りました。 これはあまりに多くのレベルにわたってグルーがなく、 BIND キャッシュでは完全に到達不可能だったのです:

     monty.de NS ns.norplex.net
     monty.de NS ns2.norplex.net

     norplex.net NS vserver.neptun11.de
     norplex.net NS ns1.mars11.de

     neptun11.de NS ns.germany.net
     neptun11.de NS ns2.germany.net

     mars11.de NS ns1.neptun11.de
     mars11.de NS www.gilching.de

     gilching.de NS ecrc.de
     gilching.de NS name.muenchen.roses.de
dnscachewww.monty.de のアドレスを発見できましたが、 そのためには様々なサーバに対して 14回もの クエリが必要でした。

私はすべての DNS サーバはそのドメインの下に属する (in-bailiwick な) 名前を使うことをすすめます。外部の DNS サーバにも内側の名前をつけ、 アドレスレコードは外側の名前から内側の名前へ自動的にコピーするべきです (なんらかの信頼できるメカニズムを使うことが望ましい)。

本来 DNS の NS レコードおよび MX レコードは、名前ではなくアドレスを持つように 設計されるべきだったのです。 DNS 応答の “additional セクション”は取り除くべきでした。 RFC 1035 では、 NS および MX の間接参照は 『アドレスの一貫性を保証する (insure [sic] consistency)』と書かれています。 これは正しいですが、こういった間接参照はサーバで処理するべきであって、 クライアントが処理すべきものではありません。 (これに関連することとして、聞くところによると Microsoft Exchange Server 2000 では CNAME レコードを指している MX レコードを 返せないそうです。この問題は最初のサービス・パックで解消されました)

この見地から A6 と DNAME についての議論を別のページにまとめてあります。

期限の切れたグルー

ときたま、いくつかの DNS サーバの Aレコードの期限がすべて切れて、 キャッシュから削除されることがあります。 たとえそのサーバがもともとグルーなし状態ではなかったときでもです:

     aol.com NS dns-01.ns.aol.com
     aol.com NS dns-02.ns.aol.com
通常これが意味するのは、この A レコードに付随する NS レコードのほうが短い TTL を持っていて、キャッシュが これらのサーバに十分早いうちにアクセスしなかったということです。 (もしこのキャッシュが BIND 8.2 なら、Aレコードはどのみち更新されません。 そして攻撃者はたとえこれらが元々はマッチしていたときでも 強制的に TTL を下げることが可能です。)

この状況では、RFC 1034 の名前解決アルゴリズムは失敗します。 RFC 1034 によれば、キャッシュが yb.mx.aol.com のアドレスを知ろうとするとき、 これは「ローカルに使用可能なネームサーバの資源レコード (RR)」中で、「もっともよいサーバ」を探し、 dns-01.ns.aol.comdns-02.ns.aol.com の名前を取得します。 そして dns-01.ns.aol.comdns-02.ns.aol.com の 「アドレスを検索するための並列したリゾルバ・プロセス」を開始するとしています。 これらのリゾルバ・プロセスは「もっともよいサーバ」などの中から検索します。 このキャッシュは忍耐の続くかぎりループし、その後あきらめることになります。

さいわいにも、実際のキャッシュは別のアルゴリズムを使っています。 dnscache は root から開始し、グルーなしのレベルが 2段階以上続いた場合 キャッシュされた NS レコードを無視します。聞くところによると、 BIND はすべてのグルーへの問い合わせを root から始めるようです。

エイリアス (alias)

あるキャッシュが www.espn.tv に関する情報を得たいとしましょう。 もしこれが www.espn.tv の CNAME レコードを発見し、それが www.espn.go.com を指していたとすると、これはまた最初に戻って www.espn.go.com に対して同じ情報を探さなくてはなりません。 www.espn.tvwww.espn.go.comエイリアス (alias) なのです。

RFC 1034 では、エイリアスは別のエイリアスを参照“すべきではない”と述べています。 しかし現実には、もし管理者が www.espn.go.com のエイリアスを設定して それを espn.go.com にしたとき、彼はおそらく www.espn.tv を 変更しなければならないとは覚えていないでしょう -- でももし www.espn.tv が 動かなくなったら、ユーザは叫び声を上げます。 「CNAME の連鎖は追うべきである」と RFC 1034 では言っています。

グルーなしの状態と同じく、エイリアスは DNS クライアントに 余計な時間とメモリを浪費させます。キャッシュが許容できる エイリアスの数はどれくらいなのでしょうか? 現在のところ、 dnscache は 4レベルまでのエイリアスを許可しています。 これは今のところ十分のようですが、将来にわたっても十分でしょうか?

私はすべての CNAME レコードは削除することをすすめます。 DNS はエイリアスを使わずに設計されるべきだったのです。

クラスレスな in-addr.arpa の委譲

ある ISP がある顧客に IP アドレス 1.2.3.100, 1.2.3.101 および 1.2.3.102 を 割り当てたとしましょう。そして顧客はこれらのアドレスに対して逆引きを 設定したいとします。ISP は単に、以下の 3つの名前 100.3.2.1.in-addr.arpa 101.3.2.1.in-addr.arpa および 102.3.2.1.in-addr.arpa を顧客の DNS サーバに委譲すればいいだけです。

しかし実際には、かわりに ISP は CNAME レコードを使うかもしれません。 ISP は 100.3.2.1.in-addr.arpa100.cust37.3.2.1.in-addr.arpa のエイリアスにします。 101102 に対しても同様にします。 そして ISP は cust37.3.2.1.in-addr.arpa を 顧客の DNS サーバに委譲します。 RFC 2317 によるといくつかの古いバージョンの BIND はこれを処理できないとしていますが、 これ自体は正当な設定です。

なぜ ISP はこのような余分な複雑さを持ち込むのでしょうか?   答え: 単純なやり方では、顧客が BIND を走らせている場合、 顧客は 100101 および 102 の レコードを 3つの別々のファイルに格納しなければならないからです。 このこみいったやり方を使うと、顧客はこれらのレコードを 単一のファイルに格納できます。

このような状況では、私は CNAME を削除し、 顧客はもっとましな DNS サーバにアップグレードすることをすすめます。

DNS サーバを選ぶ

あるキャッシュが、.com のサーバに対して問い合わせを送るとします。 これは .com サーバ群のアドレス一覧をもっています。 どのサーバに最初にコンタクトすべきでしょう?

dnscache は負荷をなるべく効率的に分散するため、 単純にランダムなサーバを選びます。 BIND は問い合わせに対する各々のサーバのラウンドトリップ時間を さまざまなボーナスやペナルティつきで評価し、“ベストな”サーバに すべての問い合わせを送ります。

シミュレーション結果によると、じょじょに頻繁になってきている (2000年 3月現在) .com サーバの過負荷は BIND の送信アルゴリズムによって引き起こされていた可能性があります。

5種類の DNS 応答

キャッシュが通常の DNS 応答を受け取ったとき、 これは以下の 5つの情報のうち、正確にどれかひとつを知ることになります:

  1. 「問い合わせた名前は回答されなかった。なぜならその名前がエイリアスだったから。 あなたは問い合わせる名前を変えてリトライしなければならない」 これは応答の answer セクションがその名前に対する CNAME レコードを含んでいて、 なおかつ CNAME が問い合わせのタイプにはマッチしない場合にあてはまります。
  2. 「問い合わせた名前には、その問い合わせに該当するレコードはなく、 それ以外のいかなるタイプのレコードも存在しないことが保証されている」 これは応答のコードが NXDOMAIN で なおかつ 1. が相当しない場合にあてはまります。 この情報をキャッシュできる時間は、 もし応答の authority セクションのなかに SOA レコードがあれば、 その値によって決まります。
  3. 「問い合わせた名前には、その問い合わせに該当するひとつ以上のレコードが存在する」 これは応答の answer セクションに、問い合わせた名前と型に該当する ひとつ以上のレコードが存在し、 なおかつ 1. が相当せず、 なおかつ 2. が相当しない場合にあてはまります。
  4. 「問い合わせた名前は回答されなかった。なぜならそのサーバは答えを知らないから。 あなたは他のサーバに問い合わせなければならない」 これは応答の authority セクションに NS レコードが存在し、 なおかつ その authority セクションが SOA レコードを含んでおらず、 なおかつ 1. が相当せず、 なおかつ 2. が相当せず、 なおかつ 3. が相当しない場合にあてはまります。 「他のサーバ」は authority セクションの NS レコードによって示されます。
  5. 「問い合わせた名前には、その問い合わせに該当するレコードはなかった。 だがこれは別のレコードなら持っている可能性がある」 これは 1. が相当せず、 なおかつ 2. が相当せず、 なおかつ 3. が相当せず、 なおかつ 4. が相当しない場合にあてはまります。 この情報をキャッシュできる時間は、 もし応答の authority セクションのなかに SOA レコードがあれば、 その値によって決まります。

この手続きは信じられないほどの、バグの入りやすい、 非常に少量の情報に対する解析手続きを必要とします。 根本的な問題は、DNS が人間を対象にしたフォーマットで 情報を宣言するように設計されおり、きわめて重要な操作を 可能なかぎり簡単なかたちで行えるようには設計されていないことです。

NXDOMAIN に関する警告: RFC 1034 および RFC 1035 からは、 NXDOMAIN はその問い合わせのドメインのすべてのサブドメインも存在しないことを 表していることは明白です。 たとえば、もしキャッシュが ns.heaven.af.mil で NXDOMAIN を受け取ったら、 それは a.ns.heaven.af.milb.ns.heaven.af.mil も 存在しないと結論してよいことになります。 もしサーバが a.ns.heaven.af.mil あるいは b.ns.heaven.af.mil の レコードは持っているが、ns.heaven.af.mil に対するレコードは持っていない場合、 サーバは NXDOMAIN ではなく zero-records (#5) 応答を返します。 しかし、RFC 2308 では、 ドメインが存在しているときでさえ 問い合わせの名前に対応するいかなる型のレコードも存在しないことを示すために NXDOMAIN を返すことを許しています。 そのため相互運用性のためには上のような結論を出さないことが重要になるのです。

切り捨て

512バイト以下の DNS パケットは UDP を経由して送信されます。 65535バイト以下の DNS パケットは TCP を経由して送信されます。

DNS クライアントと DNS キャッシュは (つねに 512バイトにおさまる) 問い合わせを UDP で送るところからはじめます。 応答は UDP で返されます。もしその応答がひとつの UDP パケットに 収まらない場合、その内容は切り捨てられ、その UDP パケット先頭にある TC ビットが立てられます。TCP をサポートするクライアントあるいはキャッシュは その TC ビットを見て、問い合わせ要求を再度 TCP で送信します。

RFC 1035 では、この「切り捨て」が何を意味するのか正確には明らかにしていません。 あきらかな解釈は、パケットを正確に 512 バイトで終わらせることでしょう。 しかし、これは相互運用上の問題をひき起こします。 とくに、Squid キャッシュはパケットがレコードの間で切れていると クラッシュしてしまうのです。BIND は最初のレコードが 512バイトを 越えたところでパケットを終わらせます。 dnscache ではすべてレコードの前でパケットを終わらせます。

圧縮

DNS パケットは、つけ焼き刃的な圧縮アルゴリズムを使っています。 ドメイン名の一部は ときどき 前のドメイン名を参照する 2バイトのポインタになります。正確な規則は、 ある名前はそれが応答の所有者の名前か、 NS データの名前か、 CNAME データの名前か、 PTR データの名前か、 MX データの名前か、あるいは SOA データのどれかの名前である場合に圧縮されるというものです。

DNS の圧縮における問題のひとつは、 これを解析するのに必要なコードの多さです。 これらすべての名前を信頼性あるやり方でつきとめるのは、 かなりの作業量を要します。これは DNS キャッシュには 本来必要なかったもののはずです。 LZ77 圧縮方式のほうがずっと簡単に実装できたでしょう。

DNS の圧縮におけるもうひとつの問題は、 これを生成するのに必要なコードの多さです。 (RFC 1035 では、サーバは自分の応答を圧縮しなくてもよいと述べていますが、 キャッシュは有名サイトのアドレス検索によって DNS UDP パケットの列が噴き出ないよう、 圧縮を実装しなくてはなりません。) 圧縮側は、圧縮すべき名前を見つけるだけでなく、 そのパケットの前にあった圧縮の対象となる名前を追跡していなければならないのです。 RFC 1035 は正確にどの対象が許されているのか明らかにしていません。 (ほとんどのバージョンの BIND は、圧縮された名前以外にポインタを使いません。 検索した名前のサフィックスは入りません。 dnscache は検索した名前のサフィックスにポインタを使っています。)

DNS の圧縮におけるさらなる問題は、 これが必ずしも効率的ではないということです。 現在のデータに対しては LZ77 のほうが明らかに優れており、 将来ポピュラーになるかもしれない新しいレコード型に対しては ずっと優れています。(BIND バージョン 4.9.* から 8.1.2 は、 RP や SRV などの新しいレコード型に対しても圧縮をおこなっており、 これは RFC 1035 のひどい違反でした。 これらの名前は、新しい型についてなにも知らないキャッシュでは展開されません。 これは相互運用に深刻な被害をもたらしています。)

大文字小文字の非区別

むかしむかし、今ではもうどうでもよい理由により、 ホスト名が大文字でタイプされることがしょっちゅうありました。 あるユーザは IBM.COM とタイプするかもしれないし、 別のユーザは ibm.com とタイプするかもしれません。 どちらでも同じホストが発見できると期待していました。

経験をつんだプログラマであればホスト名を小文字で格納し、 大文字から小文字への変換をユーザ・インタフェイスの一部でおこなったでしょう。 こうするとホスト名の比較は単純なバイナリ比較になります。

しかし DNS は、経験をつんだプログラマによっては設計されませんでした。 DNS クライアントは、ユーザがタイプしたのとまったく同じホスト名を 大文字から小文字への変換をせずに、そのまま送ります。 DNS サーバは、ホスト名によっては、 システム管理者がタイプした名前を 大文字から小文字への変換をせずに、そのまま送ります。 すべての実装者は大文字小文字の扱いで余計な時間を費やすはめになりました。

DNS プロトコルでは、任意の長さのホスト名を許しています。 この柔軟性は、もしこの設計者が大文字小文字で余計なことをしなければ、 いくつかの応用、とりわけ in-addr.arpa では役に立っていたことでしょう。 現状では、DNS におけるバイナリの名前は事実上、 役に立たないものになっています。

レコードの集合

あるドメインのメールサーバ (mail exchanger) のリストは分割できないものです。 もしこれが切り捨てられたら、メールは宛て先不明になってしまいます。 これ以外のリスト、たとえば DNS サーバの一覧やアドレスの一覧なども、 切り捨てによる被害はこれよりずっと少ないですが、同じように分割できません。

不幸にも、DNS パケットでは メールサーバのリストは複数の MX レコードに分割されてしまいます。 MX レコードの間に他のレコードが入ってしまうことさえあります (* に対するクエリでは、これはしょっちゅう起こります)。 キャッシュは、できれば大きなパケットに対しても遅くなりすぎないような方法で レコードの一覧をソートし、結果をそれぞれ完全なレコードの集合に 仕分けする必要があります。

クラス

それぞれの DNS レコードは、なんらかの“クラス”に属しています。 DNS では 65536種類の異なるクラスが使えます。 理論的には、ある名前は異なるクラスに複数の NS レコードを持ち、 同じドメインを異なるクラスの異なるサーバに委譲することができます。

レコードの問い合わせは、ふつう特定のクラスに対して要求します。 RFC 1034 ではすべてのクラスに対してレコードを検索することを許していますが、 これは意味がありません。 もし実際に複数のクラスが使われているとしたら、 それらが同じサーバ上にあることはほとんどありえないからです。 クライアントは自分が探しているクラスを知っているので、 クラスを指定することができます。 RFC 1123 の 6.1.2.2節では、“インターネット”クラスに対しては これを必須とし、すべてのクラスに対してこのことを推奨しています。

RFC 1034 では、クラスによって 「異なるタイプのアドレス形式を並列に使用することが可能になる」としていますが、 これは意味がありません。 もし DNS が複数のアドレス形式で使われるとしたなら、 DNS サーバはアドレスを複数の形式で提供したいと思うでしょう。 しかし、その DNS サーバはただひとつのクラスにしか対応できないのです。 アドレス形式の拡張は、アドレスのデータ自身によって提供されるべきでした。

dnscache では、“インターネット”以外のクラスに対する 問い合わせは無視しています。

さまざまな実装上のバグ

RFC 2308 によれば、クライアントによっては NS レコードが authority セクションにあると、 NXDOMAIN と“レコードなし”の応答をまちがえて参照として扱ってしまいます。 さらに、クライアントによっては、AA ビットのない NXDOMAIN 応答を まちがえて捨ててしまいます。

Ultrix 版の BIND は AD+CD のセットで問い合わせを送っています。

あるクライアントが X についてキャッシュに尋ねたとき、 そのキャッシュがすでに X CNAME Y であることを知っていて、 なおかつ Y についてサーバに問い合わせなければならない場合、 クライアントはこの BIND キャッシュからいんちきな応答を受けとることになります。 このキャッシュは Y に関する問い合わせとともにサーバの Y に関する応答を クライアントに転送します。 このバグは BIND 8.2.3 で修正されました。

少なくともひとつのサーバが、すべての A以外の問い合わせに対して NXDOMAIN をまちがえて生成してしまっています。 それがたとえ存在しているドメインであってもです。

     % date
     Sat Nov  2 15:45:22 CST 2002
     % dnsq any www.css.vtext.com njbdcss.vtext.com
     255 www.css.vtext.com:
     35 bytes, 1+0+0+0 records, response, nxdomain
     query: 255 www.css.vtext.com
     % dnsq aaaa www.css.vtext.com njbdcss.vtext.com
     28 www.css.vtext.com:
     35 bytes, 1+0+0+0 records, response, nxdomain
     query: 28 www.css.vtext.com
     % dnsq a www.css.vtext.com njbdcss.vtext.com
     1 www.css.vtext.com:
     51 bytes, 1+1+0+0 records, response, authoritative, noerror
     query: 1 www.css.vtext.com
     answer: www.css.vtext.com 0 A 66.174.3.10
     % 
もしクライアントが A の前に AAAA を検索していたら、 NXDOMAIN がキャッシュされてしまい、A に対する検索は失敗してしまうでしょう。