DNS のクエリと応答は、12 バイトのヘッダーに続いて Question、Answer、 Authority、Additional の各セクションで構成されます。複数オクテットの整数 フィールドはすべてネットワークバイトオーダーを使用します。RFC 1035 は基本 フォーマットを定義しており、EDNS、DNSSEC、および後続の拡張は、基本ヘッダーを 変更せずにレコードとヘッダーのセマンティクスを追加します。
ヘッダー #
| フィールド | ビット数 | 目的 |
|---|---|---|
| ID | 16 | クライアントが選択し、応答でエコーバックされる識別子 |
| QR | 1 | クエリ(0)または応答(1) |
| Opcode | 4 | 操作。QUERY はゼロ |
| AA | 1 | 応答における権威ある回答の指示 |
| TC | 1 | メッセージが切り詰められたことを示す |
| RD | 1 | クライアントが再帰処理を要求 |
| RA | 1 | サーバーが再帰処理を提供 |
| Z | 3 | 予約済みの基本ビット。拡張では AD と CD を使用 |
| RCODE | 4 | 基本応答コード |
| QDCOUNT | 16 | Question の数 |
| ANCOUNT | 16 | Answer レコード数 |
| NSCOUNT | 16 | Authority レコード数 |
| ARCOUNT | 16 | Additional レコード数 |
RD は、受信サーバーに再帰処理を実行するよう要求します。RA は、
サーバーが再帰処理を実行できることを通知します。AA は、応答サーバーが
回答に対して権威を持つことを示しますが、メッセージ内のすべてのレコードが
権威あるものだという意味ではありません。TC は、切り詰められた応答では
不十分な場合に、クライアントが TCP または別のサポートされているトランスポート
で再試行する必要があることを通知します。
名前と Question #
ドメイン名はラベルの並びです。通常の各ラベルは 0 から 63 までのオクテット長 で始まり、長さ 0 のルートラベルが名前を終端します。
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 が格納されます。
NAME | TYPE | CLASS | TTL | RDLENGTH | RDATATTL は 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 で閲覧・コメントする(投稿にはログインが必要です)