このページの目次
DNS プロトコルと解決
インターネットの「電話帳」——ルートサーバーから再帰解決器、権威サーバーまで、1回のDNSクエリで数十回の委譲追跡が発生する可能性があります。edns0、any cast、ネガティブキャッシュなどのメカニズムにより、DNSは1日あたり数兆回のクエリでも利用可能となっています。
概要
DNSはインターネットの「電話帳」——人間が読みやすいドメイン名をIPアドレスに変換します。1983年に設計され(RFC 882/883)、分散型かつ階層化されたアーキテクチャによりインターネット規模へのスケーラビリティを実現しています:ルートからTLD、権威サーバーまで、各層は自らの名前空間のみを担当します。再帰解決器は「重い作業」——スタブクライアントに代わって、ルートから回答までの一連のプロセスを完了します。DNSは元々セキュリティ設計のないプロトコル(UDP平文)でしたが、後のDNSSECや暗号化転送(DoT/DoH/DoQ)はこの欠点を補完するために導入されました。
DNS クエリフロー
3つのクエリタイプ:
- Recursive (RD=1): 解決器がクライアントに代わって全程再帰 (stub → recursive)
- Iterative: 1回で referral または answer を返す (recursive → authoritative)
- Inverse: PTR クエリ (IP → name、ほとんど使用されない)
DNS ワイヤーフォーマット
DNS メッセージ (TCP または UDP):
ヘッダー (12 バイト):
トランザクションID (2B): ランダム、リクエスト ⇔ 応答のマッチング用
フラグ (2B):
QR (bit 0): 0=Query, 1=Response
OPCODE (bits 1-4): 0=Standard, 1=Inverse, 2=Status, 4=Notify, 5=Update
AA (bit 5): 権威回答 (Authoritative Answer)
TC (bit 6): 切り捨て (TCP を使用)
RD (bit 7): 再帰要求 (Recursion Desired)
RA (bit 8): 再帰利用可能 (Recursion Available)
Z (bits 9-11): 0 (予約済み)
RCODE (bits 12-15): 0=NoError, 1=FormErr, 2=SrvFail, 3=NXDomain, 5=Refused
QDCOUNT (2B): クエリ数
ANCOUNT (2B): 回答数
NSCOUNT (2B): 権威レコード数
ARCOUNT (2B): 追加レコード数
Question Section (可変長):
QNAME: ラベル形式 (以下参照)
QTYPE (2B): 1=A, 28=AAAA, 5=CNAME, 15=MX, 2=NS, 6=SOA, 33=SRV, ...
QCLASS (2B): 1=IN (Internet)
Answer/Authority/Additional Sections (可変長):
各 RR:
NAME: ラベル形式 (通常圧縮済み — 以前の名称へのポインタ)
TYPE (2B)
CLASS (2B): 1=IN
TTL (4B): キャッシュ有効期間 (秒)
RDLENGTH (2B): RDATA 長
RDATA: 型固有
ラベル形式と圧縮
ラベルエンコーディング:
[長さ 1B][ラベルデータ ...] → 長さ + データ、各ラベルは独立
最後のラベル: length=0 (ルート、空ラベル)
例: www.example.com → 0x03 'w' 'w' 'w' 0x07 'e' 'x' 'a' 'm' 'p' 'l' 'e' 0x03 'c' 'o' 'm' 0x00
DNS 圧縮 (スペース節約):
長さバイトの上位 2 bits = 11 → これはポインタ (ラベルではない!)
ポインタ = 下位 14 bits のオフセット (DNS メッセージ先頭からの相対位置)
例: 0xC0 0x0C → オフセット 12 を指す (最初の question の QNAME)
これにより、同じメッセージ内で以前出現したドメイン名を繰り返し参照可能
→ "example.com" が QNAME、A レコードの NAME、NS レコードの RDATA に出現 → 3回の参照 → 約 12+12+12 = 36 バイト節約
主要なレコードタイプ
A (type 1): RDATA = 4バイト IPv4 アドレス
AAAA (type 28): RDATA = 16バイト IPv6 アドレス
CNAME (type 5): RDATA = 正式名称 (ラベル形式) — エイリアス解決
→ 制限: CNAME は他のタイプと共存できない (RRSIG/NSEC を除く)
つまり: www.example.com が CNAME の場合、A レコードを同時に持つことはできない
MX (type 15): RDATA = 優先度 (2B) + 交換先 (ラベル形式)
→ 優先度: 低い優先度値 = 高い優先度
SOA (type 6): RDATA = mname + rname + serial + refresh + retry + expire + minimum TTL
→ ゾーンの権威情報: serial はゾーン転送のバージョン比較に使用
NS (type 2): RDATA = ネームサーバー (ラベル形式) — このゾーンを権威するネームサーバー
SRV (type 33): RDATA = 優先度 + 重み + ポート + ターゲット
→ _service._proto.name → 対象ホスト:ポート
例: _sip._tcp.example.com SRV 10 60 5060 sipserver.example.com
PTR (type 12): RDATA = 名前 (ラベル形式) — 逆引き (IP → 名前)
→ IPv4 は in-addr.arpa、IPv6 は ip6.arpa
TXT (type 16): RDATA = 1つ以上のテキスト文字列 (長さプレフィックス付き)
→ SPF, DKIM, DMARC、認証トークン
CAA (type 257): RDATA = フラグ + タグ + 値
→ どの CA がこのドメインの証明書を発行できるかを制限
→ 例: 0 issue "letsencrypt.org" → Let's Encrypt のみが署名可能
EDNS0 (RFC 6891)
従来の DNS の制限: UDP ペイロード最大 512B → 大きな応答 (DNSSEC RRSIG) には TCP フォールバックが必要
EDNS0: Additional section に OPT擬似RRを追加:
NAME=0 (ルート), TYPE=41 (OPT), CLASS=UDP ペイロードサイズ, TTL=フラグ+RCODE
UDP ペイロードサイズ: 受信側が処理できる最大 UDP 応答サイズを通知 (通常 1232 または 4096)
→ TCP フォールバックの回数を削減
DNSSEC OK (DO bit): クライアントが DNSSEC をサポート → サーバーは RRSIG を付与すべき
フラグ: DNSSEC OK (DO bit 15)
AFXR (ゾーン転送)
AXFR (完全ゾーン転送):
主に使用される: primary → secondary ネームサーバー間の同期
TCP 接続 (ゾーン転送は 512B を超える可能性がある):
secondary: AXFR リクエスト (type 252, class IN) → primary
primary: ゾーン内の全 RR を返す (SOA ... SOA、先頭と末尾に SOA)
IXFR (増分ゾーン転送、RFC 1995):
変更分のみ転送 (SOA serial に基づく)
参考
- RFC: 1034, 1035, 6891, 3596 (AAAA), 2782 (SRV), 6844 (CAA)
- ツール:
dig +trace,drill,kdig,delv,tcpdump -nn port 53 - ソースコード: glibc
resolv/,systemd-resolved
キーワード: DNS, A/AAAA/MX/NS/SOA/SRV/CNAME/TXT/CAA, 再帰解決器, EDNS0, ラベル圧縮, ゾーン転送