DNS の否定応答とフルリゾルバへのネガティブキャッシュの組み込み

DNSのリソースレコードと名前解決

DNS ではドメイン名に関する情報としてリソースレコード(RR) を管理します. RR には ドメイン名、タイプ、クラス、生存期間を示す TTL、RDATA と呼ばれるタイプに応じた目的のデータが含まれています. 名前解決では問い合わせ内容となる (ドメイン名, タイプ, クラス) から RR を決定します.

例えば、ドメイン名 "example.com" の IPv4 アドレスを解決するなら、 ("example.com", A, IN) に対する RR を決定します. タイプ A は IPv4 アドレス用で、クラス IN はインターネットシステムをあらわします. 対応する RR の RDATA には IPv4 アドレスが入っています. 通常の運用ではクラスは IN を指定して利用され、他の値は一般的には使われていません. なので実際にはドメイン名とタイプが RR へ対応付けられることになります.

解決の結果となる RR は一つとはかぎらず、複数でもかまいません. 結果の RR が一つも無いこともあります.

DNSの否定応答とネガティブキャッシュ

DNS の否定応答には種類があり、SERVFAIL のような正常な結果が得られていないものと、 NODATA や NXDOMAIN といった正常な結果が得られているものがあります.

SERVFAIL は、なんらかの理由でシステムから、問い合わせに対する正常な結果を返せない状況です. NODATA は、そのドメイン名とタイプに対する RR は一つも無いけれども、同じドメイン名で別のタイプに対する RR が存在する場合です. NXDOMAIN は、どのようなタイプを指定したとしても、そのドメイン名に対する RR が一つも無い場合です.

DNS のネガティブキャッシュでは正常な結果が得られている NODATA と NXDOMAIN をキャッシュの対象とし、SERVFAIL は対象としません. 1 問い合わせに対する結果の RR が一つも無いという情報をキャッシュすることで、フルリゾルバの検索の回数を減らすことができます.

フルリゾルバのキャッシュとネガティブキャッシュの組み込み

開発中の Haskell によるフルリゾルバの実装では、優先度付きキューでキャッシュを実現していました. (Domain, TYPE, CLASS) をキー、[RData] を値、無効化時刻を優先度としています.

キャッシュ書き込み時には TTL と現在時刻から無効化時刻を計算して、優先度として書き込みます. キャッシュ読み出し時には無効化時刻と現在時刻から TTL を逆算することで、 [ResourceRecord] を復元できます.

ここに、ネガティブキャッシュを加えます.2

フルリゾルバの返答においても、ネガティブキャッシュの TTL をクライアント側へ知らせるために SOA とともに返すのが一般的です. キャッシュの情報から SOA を復元する必要があるため、優先度付きキューの値を [RData] から Either Domain [RData] へと変更しました.3 Right の場合が通常のキャッシュで、Left の場合がネガティブキャッシュです. Domain にはゾーンのドメイン名を入れておくことで、SOA を復元することができます.

キャッシュ書き込み時には、権威サーバからの SOA RR の TTL 値と MININUM フィールドのうちの小さい方を TTL として採用し、計算した無効化時刻を優先度として、 Left 付きのゾーンのドメイン名を書き込みます. キャッシュ読み出し時には、ゾーンのドメイン名から SOA を復元する他は、無効化時刻と現在時刻から TTL を逆算するのは通常のキャッシュと同様です.

NODATA の場合は、問い合わせの TYPE をそのままキーとして利用します. NXDOMAIN の場合は、問い合わせの TYPE 以外についても、RR が存在しないことを表現するため、Private Use の空間として定義されている4 TYPE の値を内部的に割り当てます. そうすることで、タイプに依らずにネガティブキャッシュを共有することができます.


  1. https://datatracker.ietf.org/doc/html/rfc2308#section-7
  2. ネガティブキャッシュ実装当時の変更内容 https://github.com/khibino/dns-resolver/compare/tag/empty-with-soa...tag/negative-cache
  3. 実装当時の型は、キャッシュ用の型への変換の都合で異なっています. ここではより整理された同型の定義をもとに説明しています.
  4. Private Use の空間は RFC6895 https://datatracker.ietf.org/doc/html/rfc6895#section-3.1 で定義される