DNS ワイヤーフォーマット

最終更新: 2025-05-29 15:04:54 +0800 +0800
原文は英語で書かれています。あなたはAI翻訳版を読んでいます。

DNS のクエリと応答は、12 バイトのヘッダーに続いて Question、Answer、 Authority、Additional の各セクションで構成されます。複数オクテットの整数 フィールドはすべてネットワークバイトオーダーを使用します。RFC 1035 は基本 フォーマットを定義しており、EDNS、DNSSEC、および後続の拡張は、基本ヘッダーを 変更せずにレコードとヘッダーのセマンティクスを追加します。

ヘッダー #

フィールドビット数目的
ID16クライアントが選択し、応答でエコーバックされる識別子
QR1クエリ(0)または応答(1)
Opcode4操作。QUERY はゼロ
AA1応答における権威ある回答の指示
TC1メッセージが切り詰められたことを示す
RD1クライアントが再帰処理を要求
RA1サーバーが再帰処理を提供
Z3予約済みの基本ビット。拡張では AD と CD を使用
RCODE4基本応答コード
QDCOUNT16Question の数
ANCOUNT16Answer レコード数
NSCOUNT16Authority レコード数
ARCOUNT16Additional レコード数

RD は、受信サーバーに再帰処理を実行するよう要求します。RA は、 サーバーが再帰処理を実行できることを通知します。AA は、応答サーバーが 回答に対して権威を持つことを示しますが、メッセージ内のすべてのレコードが 権威あるものだという意味ではありません。TC は、切り詰められた応答では 不十分な場合に、クライアントが TCP または別のサポートされているトランスポート で再試行する必要があることを通知します。

名前と Question #

ドメイン名はラベルの並びです。通常の各ラベルは 0 から 63 までのオクテット長 で始まり、長さ 0 のルートラベルが名前を終端します。

text
03 www 07 example 03 com 00

長さオクテットとルートラベルを含む完全なエンコード済みの名前は、255 オクテット に制限されます。Question には QNAME、16 ビットの QTYPE、16 ビットの QCLASS が含まれます。インターネットクラス(IN)の値は 1 です。

繰り返し現れるサフィックスを避けるため、名前では圧縮ポインターを使用できます。 ポインターの最初の 2 ビットは 11 で、残りの 14 ビットはメッセージ開始位置 からのオフセットです。ポインターは前方の位置だけを指せます。DNS メッセージは 信頼できない入力であるため、パーサーはポインターの深さに上限を設け、オフセット を検証し、ループを検出しなければなりません。

Resource Record #

Answer、Authority、Additional の各セクションには Resource Record が格納されます。

text
NAME | TYPE | CLASS | TTL | RDLENGTH | RDATA

TTL は 32 ビットフィールドとしてエンコードされ、RFC 2181 に基づき、実効範囲 が 0 から \(2^{31}-1\) までの非負のキャッシュ存続期間として扱われます。 RDLENGTH は、タイプ固有の RDATA バイト列の範囲を定めます。RRset は、同じ owner name、class、type を持つレコードの集合です。DNSSEC は個々のレコード ではなく RRset に署名します。

一般的な RDATA には、4 バイトの IPv4 アドレス(A)、16 バイトの IPv6 アドレス(AAAA)、ドメイン名(NS、CNAME、PTR)、および MX の preference と exchange name の組み合わせや SOA のタイマーなどの構造化された 値が含まれます。RDATA 内の名前も、適用される RFC が許可している場合は圧縮を 使用できます。

EDNS は Additional セクション内の OPT pseudo-record を使用して、UDP ペイロード サイズ、拡張 RCODE ビット、フラグ、およびオプションを通知します。EDNS が ネゴシエーション済みの場合、サーバーは UDP DNS が 512 バイトに制限されている と仮定してはなりません。ただし、クライアントは引き続き切り詰めに対応し、 再試行しなければなりません。

安全な解析 #

受信したデータグラムまたはストリームフレームだけを有効なバイト範囲として扱います。 各固定幅フィールド、ラベル、ポインター、または RDATA 値を読み取る前に、その フィールド全体が範囲内に収まることを検証します。セクションのカウントは信頼 できないため、指定されたレコード数を格納できない場合は停止します。

名前の伸長には 2 つの位置が必要です。1 つは呼び出し元が次に読み取るオフセット、 もう 1 つは名前の再構成に使用するポインター追跡後のオフセットです。ポインター のホップ数を数えるか、訪問済みオフセットを追跡してサイクルを拒否し、予約済みの ラベルプレフィックスを拒否し、63 オクテットのラベル制限と 255 オクテットの 伸長後の名前制限を適用します。また、メッセージ外部のポインター先を決して解釈 してはなりません。

TCP および TLS トランスポートでは、2 オクテットの長さプレフィックスが各 DNS メッセージをフレーム化しますが、DNS ヘッダーの一部ではありません。解析する前に、 その長さのバイトを正確に読み取ります。OPT レコードでは、TTL フィールドの拡張 RCODE と基本ヘッダーの RCODE を組み合わせ、各オプションを RDLENGTH と メッセージ範囲の両方の内部で解析します。

参考資料 #

コメント

GitHub で閲覧・コメントする(投稿にはログインが必要です)