DNS の仕組み入門 - 名前解決・レコード種別・TTL とキャッシュを理解する

DNS の仕組み入門 - 名前解決・レコード種別・TTL とキャッシュを理解する

作成日:
読了:23
更新日:

Web サイトにアクセスするとき、私たちは example.com のようなドメイン名を打ち込みますが、実際に通信するには 93.184.x.x のようなIP アドレスが必要です。この変換をしているのが DNS(Domain Name System / ドメインネームシステム)です。「インターネットの電話帳」とよく例えられますが、その実体は世界中に分散した巨大な階層型データベースです。

この記事では、DNS の名前解決の仕組みを、一次ソースである RFC 1034 / 1035 をはじめとする各 RFC や IANA の情報を軸に整理します。レコード種別、解決の流れ、TTL とキャッシュ、そして DNSSEC や DoH/DoT といった近年の話題までを、Web 開発者・インフラ担当者向けに一通り押さえます。

DNS は階層型の分散データベース

DNS の中核となる概念は RFC 1034 で定義されています。ドメイン名の空間は木構造(ツリー)として表現され、各ノードに付いたラベルを、ノードからルートまでたどって連結したものがドメイン名になります。

  • ラベルは1個あたり最大63オクテット
  • ドメイン名全体は最大255オクテット

この木のいちばん上にあるのがルート(名前を持たない、空ラベルのノード)です。www.example.com. という表記の末尾のドット(.)がルートを表します。普段は省略しますが、これが完全修飾ドメイン名(FQDN)の正式な形です。

階層をたどると次のようになります。

Loading diagram...
  • ルート: 最上位。どの TLD がどこにあるかを知っている
  • TLD(Top Level Domain / トップレベルドメイン): comnetorg や、jpuk などの国別(ccTLD)
  • 権威サーバー(authoritative server): example.com のように、実際のレコードの正解を持っているサーバー

ゾーンと権威

RFC 1034 では、名前空間のある部分について「正解」を持っているサーバーを権威(authority)と呼び、権威情報を管理する単位をゾーン(zone)と呼びます。「ドメイン」が木構造上の部分木全体を指すのに対し、「ゾーン」は1つの組織が実際に管理する範囲を指す、という違いがあります。たとえば example.com のゾーンを管理しつつ、sub.example.com を別ゾーンとして切り出して別の組織に委任(delegation)する、といったことができます。

NOTE

ルートゾーンに「正解」を提供する権威サーバー群がルートサーバーです。IANA によれば、ルートサーバーは a から m までの13系統の識別子(letter)で運用されており、Verisign、USC、Cogent、NASA、ISC、RIPE NCC、ICANN、WIDE Project など複数の組織が分担しています。「13台しかない」という誤解がありますが、実際には各系統が anycast によって世界中の多数の物理サーバーに展開されており、IANA も「世界中の数百のサーバーからなるネットワーク」だと説明しています。13というのは、後述の DNS メッセージサイズの制約に由来する識別子の数です。

名前解決に登場する2種類のリゾルバ

名前解決を担うのがリゾルバ(resolver)です。役割の異なる2種類があります。

種類役割
スタブリゾルバアプリ・OS に組み込まれた最小限のリゾルバ。自分では解決せず、再帰リゾルバに丸投げするOS の名前解決機能、ブラウザ
再帰リゾルバ(フルサービスリゾルバ)スタブから依頼を受け、ルートから順にたどって最終的な答えを取得し、キャッシュも持つISP の DNS、8.8.8.81.1.1.1 など

普段アプリが行うのは、スタブリゾルバから再帰リゾルバへの再帰問い合わせ(recursive query)です。「最後まで解決して答えだけ返して」という依頼です。一方、再帰リゾルバが権威サーバー群に対して行うのは反復問い合わせ(iterative query)で、「知らなければ次にどこへ聞けばよいか教えて」というやり取りを繰り返します。

RFC 1034 でも、データグラム(UDP)アクセスでは反復方式が好まれるとされ、再帰モードはサーバーが任意で提供する機能だと位置づけられています。

名前解決の流れ(キャッシュが空の場合)

www.example.com を初めて解決する場合、再帰リゾルバは次のように動きます。

Loading diagram...

ポイントは、再帰リゾルバがルートから順に下に降りていくことと、途中のサーバーは「最終的な答え」ではなく「次に聞くべきサーバー(委任先の NS)」を返す、という点です。最終的な答えを返すのは、そのゾーンに対して権威を持つサーバーだけです。

2回目以降は、リゾルバが持つキャッシュから即座に答えられるため、ルートまで毎回たどることはありません。これが DNS のスケーラビリティを支えています。

リソースレコード(RR)の基本

DNS が保持するデータの単位がリソースレコード(Resource Record / RR)です。RFC 1034 によれば、各 RR は次の要素を持ちます。

  • owner(所有者名): そのレコードが属するドメイン名
  • type(型): A、MX など、レコードの種類
  • class(クラス): ほぼ常に IN(Internet)
  • TTL: そのレコードをキャッシュしてよい秒数
  • RDATA: 型ごとの実データ(IP アドレスやホスト名など)

TTL について RFC 1034 は「主にリゾルバが RR をキャッシュする際に使う、生存時間」と定義しています。TTL とキャッシュは後ほど詳しく扱います。

主なレコード種別

実務で出会うレコード種別を整理します。型コードや定義 RFC も併記します。

種別役割主な定義
Aドメイン名を IPv4 アドレスに対応づけるRFC 1035
AAAAドメイン名を IPv6 アドレスに対応づける(型28、128ビット)RFC 3596
CNAME別名(alias)。owner を別の正規名に転送するRFC 1034 / 1035
NSそのゾーンの権威ネームサーバーを示す。委任に使うRFC 1035
SOAゾーンの起点。シリアル番号や各種タイマー、ネガティブキャッシュ TTL を持つRFC 1035 / 2308
MXメールの宛先サーバー(preference 値付き)RFC 1035
TXT任意のテキスト。SPF/DKIM/ドメイン所有確認などに使われるRFC 1035
PTR逆引き。IP アドレスからドメイン名を引くRFC 1035
CAAどの認証局(CA)に証明書発行を許すかを宣言するRFC 8659
SRVサービスの場所(ホスト・ポート)を示す。priority/weight/port/targetRFC 2782

いくつか補足します。

  • CNAME には重要な制約があります。RFC 1034 は CNAME を「owner を別名として扱う」と定義しており、原則として1つの名前に CNAME と他のレコードを同居させられません。とくにゾーン頂点(apex、example.com そのもの)には SOA や NS が必須なので、apex に CNAME は置けません。
  • CAA(RFC 8659)は、ドメイン名の保有者が「この証明書はこの CA からだけ発行を許す」と宣言できるレコードで、CA が誤発行を減らすための仕組みです。
  • SRV(RFC 2782、型33)は _Service._Proto.Name という名前で、priority・weight・port・target を返します。weight と port はそれぞれ0〜65535の範囲です。
  • PTR による逆引きは、in-addr.arpa(IPv4)/ip6.arpa(IPv6)という特別なドメイン以下で管理されます。

ゾーンファイルの例

権威サーバーに置くゾーンの設定(ゾーンファイル)の抜粋イメージです。RFC 2606 で予約されている example.com を使います。

example.com のゾーンファイル(抜粋)
$ORIGIN example.com.
$TTL 3600
@   IN  SOA ns1.example.com. admin.example.com. (
            2026063001  ; serial
            7200        ; refresh
            3600        ; retry
            1209600     ; expire
            300 )       ; minimum (ネガティブキャッシュ TTL)
@       IN  NS    ns1.example.com.
@       IN  NS    ns2.example.com.
@       IN  A     93.184.216.34
@       IN  AAAA  2606:2800:21f:cb07:6820:80da:af6b:8b2c
www     IN  CNAME example.com.
@       IN  MX    10 mail.example.com.
@       IN  TXT   "v=spf1 include:_spf.example.com -all"
@       IN  CAA   0 issue "letsencrypt.org"

SOA の serial はゾーンの版数で、セカンダリ(スレーブ)が更新を検知するのに使います。minimum(ここでは300秒)は、後述のネガティブキャッシュの TTL に使われます。

TTL とキャッシュ

DNS のパフォーマンスと整合性は TTL(Time To Live)で制御されます。リゾルバは取得したレコードを TTL の秒数だけキャッシュし、その間は同じ問い合わせに対して権威サーバーへ聞き直さず即答します。TTL が経過するとキャッシュは破棄され、次回は再取得します。

実務上の勘所は次のとおりです。

  • TTL を短くすると、レコード変更(サーバー移転など)が速く反映されますが、問い合わせ回数が増えます。
  • TTL を長くすると、キャッシュが効いて高速・低負荷ですが、変更の反映が遅れます。
  • 移転の前にあらかじめ TTL を短くしておく(例: 数日前に300秒へ下げる)と、切り替え当日の浸透を速くできます。切り替え後に元へ戻します。

このキャッシュの考え方は HTTP/CDN のキャッシュ制御とよく似ています。レイヤーは違いますが「TTL で鮮度と負荷のトレードオフを取る」点は共通なので、CDN キャッシュと s-maxage の実践ガイド も合わせて読むと理解が深まります。

ネガティブキャッシュ(RFC 2308)

「存在しない」という事実もキャッシュされます。これをネガティブキャッシュと呼び、RFC 2308 が定めています。存在しない名前への応答(NXDOMAIN)や、名前はあるが該当型がない応答(NODATA)を毎回権威まで聞きに行くのは無駄なので、一定時間キャッシュします。

そのキャッシュ時間(TTL)は、SOA レコードの MINIMUM フィールドと SOA 自身の TTL のうち小さいほうで決まります。RFC 2308 は、かつて多義的だった SOA の MINIMUM フィールドを「ネガティブ応答に使う TTL」として再定義しました。先ほどのゾーンファイル例で minimum 300 としていたのがこれにあたります。

NOTE

新しいレコードを追加した直後にうまく引けないとき、ネガティブキャッシュが原因のことがあります。直前に「存在しない」と答えられた結果が、MINIMUM の秒数だけ各リゾルバにキャッシュされているためです。

DNS メッセージとポート53、UDP/TCP

DNS の通信はポート53を使い、UDP と TCP の両方を用います。

  • 通常の問い合わせは UDP が既定です。1往復で軽量に終わります。
  • TCP が使われるのは、応答が大きい場合や、信頼性・順序保証が要る場合です。代表例はゾーン転送(AXFR/IXFR)と、UDP 応答が大きすぎて切り詰め(truncation)が起きたケースです。

オリジナルの DNS(RFC 1035)では、UDP メッセージは512バイトまでという制限がありました。これを超える応答は切り詰められ、ヘッダの TC(truncated)ビットが立ちます。TC ビットを見たクライアントは、TCP で再問い合わせします。なお RFC 7766 は、汎用 DNS 実装は UDP と TCP の両方をサポートしなければならない(MUST)と定めています。「DNS は UDP だけ」というのは誤りで、TCP も必須です。

EDNS0(RFC 6891)

512バイト制限は、DNSSEC の署名や複数の IPv6 アドレスを返す現代の用途には小さすぎます。これを拡張するのが EDNS0(Extension Mechanisms for DNS、RFC 6891)です。

EDNS0 は OPT 疑似レコード(型41)を問い合わせに含めることで、「自分はこのサイズまでの UDP 応答を受け取れる」とクライアント側の最大ペイロードサイズを通知します。これにより、512バイトを超える応答も TCP に切り替えずに UDP で受け取りやすくなります。OPT レコードはキャッシュされず、その1回のやり取りのための制御情報を運ぶ、という点が特徴です。

DNSSEC: 改ざん検知のための署名(RFC 4033 ほか)

素の DNS には、応答が本物か検証する仕組みがありません。これを補うのが DNSSEC(DNS Security Extensions)で、RFC 4033 / 4034 / 4035 が中核です。

RFC 4033 は DNSSEC を「DNS にデータ起源認証(data origin authentication)とデータ完全性(data integrity)を加えるもの」と定義しています。重要なのは、DNSSEC は暗号化(秘匿性)の仕組みではないことです。RFC 4033 自身が「機密性やアクセス制御を提供するものではない」と明言しています。あくまで「この応答は改ざんされておらず、正規のゾーンから来た」ことを公開鍵署名で検証する仕組みです。

DNSSEC が導入する主なレコードは次のとおりです。

種別役割
RRSIGレコードセットに対する署名
DNSKEYゾーンの公開鍵
DS親ゾーンに置く、子の鍵のハッシュ(委任署名)
NSEC「存在しないこと」を認証付きで示す

検証は信頼の連鎖(chain of trust)で行われます。リゾルバはルートの鍵(トラストアンカー)を起点に、DS -> DNSKEY の連鎖を下へたどり、各委任を検証しながら目的のゾーンまで到達します。

WARNING

DNSSEC は秘匿性を提供しません。問い合わせ内容そのものを盗聴から守りたい場合は、別レイヤーである後述の DoH/DoT が必要です。両者は目的が異なるので混同しないでください。

DoH と DoT: 問い合わせの暗号化

素の DNS は平文で流れるため、経路上の第三者に問い合わせ内容が見えてしまいます。これを暗号化するのが DoTDoH です。

  • DoT(DNS over TLS、RFC 7858): DNS の通信を TLS で包みます。専用のポート853を使います。TLS により経路上の盗聴・改ざんを防ぎます。
  • DoH(DNS over HTTPS、RFC 8484): DNS の問い合わせ・応答を HTTPS に載せます。application/dns-message というメディアタイプを使い、GET/POST の両メソッドに対応します。ポート443で他の Web トラフィックに紛れるため、観測・妨害がより困難になります。

どちらも目的は問い合わせ内容のプライバシー保護と経路上での改ざん防止です。DNSSEC が「データの真正性(改ざん検知)」を担うのに対し、DoH/DoT は「通信の秘匿性」を担う、という役割分担で覚えると整理できます。なお TLS によるホスト名検証など、TLS 自体の落とし穴については Node.js の TLS ホスト名検証バイパス も参考になります。

dig で実際に確認する

手元で挙動を確かめるには dig コマンドが便利です。A レコードを引く例です(出力は実行環境により異なります)。

A レコードを引く
dig example.com A +noall +answer
出力例
example.com.        3600    IN      A       93.184.216.34

左から owner、TTL、class(IN)、type(A)、RDATA の順です。TTL は問い合わせのたびに、キャッシュ残り秒数に応じて減っていきます。

特定の権威サーバーへ直接聞いたり、解決の経路をたどったりもできます。

解決経路をたどる(委任を順にたどる)
dig example.com A +trace
ネームサーバー(NS)を確認する
dig example.com NS +short
出力例
ns1.example.com.
ns2.example.com.

MX や CAA、ネガティブ応答(存在しない名前)も同様に確認できます。

存在しない名前 -> NXDOMAIN を確認
dig nonexistent.example.com A

応答の status: NXDOMAIN と、Authority セクションに返る SOA を見れば、ネガティブキャッシュがどの TTL で効くかが読み取れます。

まとめ

  • DNS は木構造の分散データベース。ルート -> TLD -> 権威サーバーの階層をたどり、「ゾーン」という単位で権威が管理される
  • 解決は2種類のリゾルバで進む。アプリはスタブリゾルバから再帰リゾルバへ再帰問い合わせし、再帰リゾルバはルートから反復問い合わせで答えにたどり着く
  • データの単位はRRA/AAAA/CNAME/NS/SOA/MX/TXT/PTR/CAA/SRV など型ごとに役割が違う。apex に CNAME は置けない
  • TTL でキャッシュし、鮮度と負荷のトレードオフを取る。「存在しない」もネガティブキャッシュ(RFC 2308、SOA の MINIMUM)される
  • 通信はポート53、UDP/TCP 両対応(RFC 7766)。512バイト超は TC ビットで TCP 再送、または EDNS0(RFC 6891)で UDP のまま拡張
  • DNSSEC(RFC 4033)は改ざん検知(真正性)DoT(RFC 7858)/DoH(RFC 8484)は通信の暗号化(秘匿性)。目的が異なる

DNS は普段は意識しませんが、トラブル時には「キャッシュなのか、権威の設定なのか、委任なのか」を切り分ける力が効きます。dig で1枚ずつ層をはがして確認できるようになると、名前解決のトラブルは怖くなくなります。

参考リンク

Webhook 受信側のベストプラクティス - 署名検証・リトライ・冪等性・順序

Webhook 受信側のベストプラクティス - 署名検証・リトライ・冪等性・順序

9

Webhook を安全・堅牢に受け取るための設計を実務目線で整理します。HMAC-SHA256 による署名検証とリプレイ攻撃対策(タイムスタンプ)、生のボディで検証する理由、定数時間比較、at-least-once 配信を前提にした冪等な処理、保証されない配信順序への備え、まず素早く 2xx を返して非同期処理する受信パターン、未知イベントの扱い、シークレットのローテーションや CSRF 除外まで、Stripe・GitHub・Standard Webhooks を一次ソースにまとめます。

Cookie・セッション・SameSite の基礎 - Secure / HttpOnly と CSRF・CORS の関係

Cookie・セッション・SameSite の基礎 - Secure / HttpOnly と CSRF・CORS の関係

11

Web認証の土台となる Cookie・セッション・SameSite を実務目線で整理します。Set-Cookie の属性(Expires/Max-Age・Domain/Path)、Secure と HttpOnly が防ぐ脅威、SameSite の Strict/Lax/None の違いと None に Secure が要る理由、サーバー側セッションとログイン後の ID 再生成、SameSite だけで CSRF を防ぎきれない理由、クロスオリジンで Cookie を送る CORS の条件、__Host-/__Secure- プレフィックスまで、MDN・RFC 6265bis・OWASP を一次ソースにまとめます。

CORS の仕組みとハマりどころ - プリフライト・credentials・Allow-Origin を理解する

CORS の仕組みとハマりどころ - プリフライト・credentials・Allow-Origin を理解する

10

CORS(オリジン間リソース共有)を実務目線で整理します。同一オリジンポリシーとの関係、単純リクエストとプリフライト(OPTIONS)の条件、Access-Control-Allow-Origin などの各ヘッダ、credentials 付きで * が使えない理由、Vary: Origin とキャッシュ、そして「No Access-Control-Allow-Origin header」エラーの意味と対処まで、MDN と WHATWG Fetch Standard を一次ソースにまとめます。CORS はブラウザの仕組みであって認可ではない、という勘所も。