前へ << DNS クライアントを作ってみよう (1) | DNS クライアントを作ってみよう (3) >> 次へ |
そこから Obsolete になっているものや、現在ではほとんど考慮しなくてもよくなったものを除いて 読むべきなのでしょうが、あいにくまともなリゾルバを作るつもりはありませんので、 当ページ管理者は RFC 1034、RFC 1035、RFC 1886 だけ読みました。
RFC を読むと照会と応答、いずれも以下のような構成になっているようです (「詳解 TCP/IP Vol.1 プロトコル」にならって、 ここでは「Query」を「照会」、「Response」を「応答」と表記することにします)。
1… …16bit | 17… …32bit |
(1)識別子 | (2)フラグ |
(3)質問数 | (4)回答 RR 数 |
(5)権威 RR 数 | (6)追加 RR 数 |
(7)質問レコード | |
(8)回答レコード | |
(9)権威レコード | |
(10)追加情報レコード |
(1)識別子 (16bit)
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
QR | OPCODE | AA | TC | RD | RA | Z | RCODE |
ビット | フィールド | 説明 | ||||||
第1bit | QR (Query/Response) | 0 なら照会、1 なら応答。 つまりクライアントは 0 を、サーバは 1 をセットする。 |
||||||
第2〜5bit | OPCODE | 0 なら標準照会 (standard query) 1 なら逆照会 (inverse query) 2 ならサーバステータス要求 (server status request) |
||||||
第6bit | AA (Authoritative Answer) | 回答に対する権威を持つなら 1。応答時にセットされる。 | ||||||
第7bit | TC (TrunCation) | 回答が長過ぎて、複数の UDP データグラムに分割されたなら 1 | ||||||
第8bit | RD (Recursion Desired) | 再帰照会か、反復照会か。普通は 1 (再帰照会) | ||||||
第9bit | RA (Recursion Available) | 再帰可能なら 1。応答時にセットされる。 | ||||||
第10〜12bit | 3bit とも 0 固定 (将来用にリザーブ) | |||||||
第13〜16bit | RCODE (Response code) | 応答結果。応答時にセットされる。
|
(3)質問数、(4)回答 RR 数、(5)権威 RR 数、(6)追加 RR 数 (各16bit)
(7)質問 (可変長)
1… …16bit | 17… …32bit |
(7.1)照会名 (可変長) | |
(7.2)照会タイプ | (7.3)照会クラス |
(7.1)照会名
照会名はラベルとデータが連なったもので、 ラベルはその後に続くデータの長さである。 最後のラベルは 0 である。
(7.2)照会タイプ
照会の際、どの種類の情報を求めているかを表す。主な照会タイプは以下の通り。
照会タイプ 数値 説明 A 1 ホストアドレス NS 2 権威あるネームサーバ CNAME 5 別名 (canonical name) PTR 12 逆引き用ポインタ MX 15 メールサーバ AAAA 28 IPv6 ホストアドレス ANY 255 任意のタイプ
(7.3)照会クラス
通常はインターネットを表す 1 を指定する。
そういうときは実際に流れるパケットの中身を見るのが一番です。 tcpdump を使ってもいいのですが、特にバイナリデータの場合は ethereal の GUI が向いています。
root になって ethereal を実行し、メニューから「Capture → Start」とします。
# ethereal
起動直後 | Capture → Start で キャプチャ開始 |
するともう一枚ウィンドウが開き、どの種類のパケットがいくつ流れたかが表示されます。
% dig www.jp.freebsd.orgで名前解決を行ってください。 右図のように UDP が 2 パケット流れたことが確認できるはずです。 そしたら「Stop」を押してキャプチャをストップします。
キャプチャを止めると右図のように流れたデータを確認することができます。
画面最下部のダンプは Ethernet 上を流れたフレームデータです。
画面中央部をクリックすることで、対応する画面下部のダンプが反転表示されます。
上図では画面中央の「Domain Name System (query)」をクリックしたので、
画面下部のダンプ表示は DNS の query の部分が反転表示されています。
いろんな部分をポチポチっとクリックしてみると、 Ethernet フレーム、 IP データグラム、 UDP データグラム、 DNS query から成り立っていることがわかります。
0000 00 10 38 0a 6b f0 00 90 99 16 bf 0a 08 00 45 00 ..8.k... ..?@..E. 0010 00 40 0f 06 00 00 40 11 ea 36 c0 a8 00 1f c0 a8 .@....@. .6As..As 0020 00 01 04 4e 00 35 00 2c 22 7c 00 02 01 00 00 01 ...N.5., "|...... 0030 00 00 00 00 00 00 03 77 77 77 02 6a 70 07 66 72 .......w ww.jp.fr 0040 65 65 62 73 64 03 6f 72 67 00 00 01 00 01 eebsd.or g.....また、画面中央部にはデータの解析結果が表示されます。これは便利。
Domain Name System (query) Transaction ID: 0x0002 (識別子は 0x00 0x02) □Flags: 0x0100 (Standard query) (ここがフラグ) 0... .... .... .... = Response: Message is a query (QR は 0、つまり照会) .000 0... .... .... = Opcode: Standard query (0) (OPCODE は標準照会) (第6bit の AA (Authoritative Answer) が省略されているが、照会時には 0 であることがわかる) .... ..0. .... .... = Truncated: Message is not truncated (TC は 0。このメッセージは分割されていない) .... ...1 .... .... = Recursion desired: Do query recursively (RD は 1、つまり再帰照会) (第9bit の RA (Recursion Available) が省略されているが、照会時には 0 であることがわかる) .... .... ...0 .... = Non-authenticated data OK: Non-authenticated data is unacceptable (権威のない回答はいらない) (って、ここ 0 固定のはずなんだけど、新しい RFC が出たのかな?) Questions: 1 (質問数は 1) Answer RRs: 0 (回答 RR 数はゼロ) Authority RRs: 0 (権威 RR 数はゼロ) Additional RRs: 0 (追加 RR 数はゼロ) □Queries □www.jp.freebsd.org: type A, class inet Name: www.jp.freebsd.org (ホスト名は www.jp.freebsd.org) Type: Host address (照会タイプはホストアドレス、つまり A レコードが欲しい) Class: inet (照会クラスは 1。つまりインターネット)(7.1) 照会名 については、さきほど
よーく観察すると、ホスト名をドットで区切って、区切りごとの長さを置いていることがわかります。
3 | w | w | w | 2 | j | p | 7 | f | r | e | e | b | s | d | 3 | o | r | g | 0 |
3バイト | 2バイト | 7バイト | 3バイト | 終端なので 0 |
X68000.startshop.co.jp ならば以下のようになります。
6 | X | 6 | 8 | 0 | 0 | 0 | 9 | s | t | a | r | t | s | h | o | p | 2 | c | o | 2 | j | p | 0 |
6バイト | 9バイト | 2バイト | 2バイト | 終端なので 0 |
照会と応答の構成 (再掲) | 解析した照会の構成 | |||||||||||||||||||||||||||
|
|
これまでは照会部分を表示するため画面上部ウィンドウの
「Standard Query」を見ていましたが、その下の「Standard Query Response」を選びます。
その状態が右の画面になります。
全体の構成を見ると、下図右のようになっていることがわかります。応答にも 質問が含まれていることに注意してください。
照会と応答の構成 (再掲) | 解析した応答の構成 | |||||||||||||||||||||||||||||||||||||||||||
|
|
実はこれはメッセージ圧縮と言われるものです。DNS はその性質上、 1回の問い合わせで同じドメイン名が何度も出てくることが多いです。
例えば以下のような質問を送ると、
質問: ドメイン名: www.jp.freebsd.org 質問: タイプ: 1 (A) 質問: クラス: 1 (INTERNET)以下のような応答が返ってきます (応答にも質問レコードが含まれていることに注意)。
質問: ドメイン名: www.jp.freebsd.org 質問: タイプ: 1 (A) 質問: クラス: 1 (INTERNET) 回答: ドメイン名: www.jp.freebsd.org 回答: タイプ: 1 (A) 回答: クラス: 1 (INTERNET) 回答: 生存時間(TTL): 3600 (秒) 回答: リソースデータ長: 4 (バイト) 回答: リソースデータ: 203.139.121.132下線部 (ひとつめ・ふたつめ) が全く同じ (どちらも www.jp.freebsd.org) であることに注意してください。 こういう場合、DNS サーバは 2番目に現れた www.jp.freebsd.org を圧縮します。 ただ、圧縮と言っても、LZ77 とかブロックソートといったコムツカシイ圧縮ではありません。
さきほどの「C0 28」を 2進数に直すと「11000000 00101000」となります。 最上位 2ビットが「11」になっていますが、これが圧縮の印です。
右図 (1) の x68000.startshop.co.jp は先に説明した通り、
(2) の x68000.startshop.co.jp は 0xC0 0x0C となっています。上位 2ビットを落とした「00 0C」がオフセット (10進数だと 12)、 応答の先頭は紫色の矢印の部分で、ここをゼロと数えると 12 バイト目は ちょうど (1) の部分の開始位置になります。
(3) の www2.startshop.co.jp の部分は、4www20xC0 0x13 となっています。このように最初は普通にドメイン名を示し、途中からポインタに変わるのもアリです。 上位 2ビットを落とした「00 13」がオフセット (10進数だと 19)、応答の先頭をゼロバイトとして 19バイト目は
(4) の www2.startshop.co.jp の部分は 0xC0 0x34、
上位 2ビットを落とした「00 34」がオフセット (10進数だと 52)、
応答の先頭をゼロバイトとして 52バイト目は
4www20xC0 0x13、
つまり (3) の位置ですね。ポインタで飛んだ先にポインタがあった場合、
さらにポインタをたどらないといけないわけです。
□Flags: 0x0100 (Standard query) (ここがフラグ) 1... .... .... .... = Response: Message is a query (QR は 1、つまり応答) .000 0... .... .... = Opcode: Standard query (0) (OPCODE は標準照会) .... .0.. .... .... = Authoritative: Server is not an authority for doman .... ..0. .... .... = Truncated: Message is not truncated (TC は 0。このメッセージは分割されていない) .... ...1 .... .... = Recursion desired: Do query recursively (RD は 1、つまり再帰照会) .... .... 1... .... = Recursion available: Server can do recursive queries(RA は 1。つまり再帰照会可能) .... .... .... 0000 = Reply code: No error (0)(RCODE は 0。つまりエラーなし)
1… …16bit | 17… …32bit |
ドメイン名 (可変長) | |
タイプ | クラス |
生存時間 (TTL) | |
リソースデータ長 | リソースデータ (可変長) |
タイプ AAAA の場合は、リソースデータには IPv6 アドレスが入っています。 リソースデータ長は 16 です。
タイプ MX の場合は、リソースデータには優先度 (Preference) が 2バイト、 その後にメールサーバのドメイン名が入っています。 リソースデータ長は「優先度 2バイト+ドメイン名部分の長さ」です。
タイプ NS、タイプ PTR、タイプ CNAME の場合は、 いずれもリソースデータにはドメイン名が入っています。 リソースデータ長は「ドメイン名部分の長さ」です。 ドメイン名は圧縮されている場合があります。
タイプ TXT の場合は、リソースデータにはテキストデータがそのまま入っています。
前へ << DNS クライアントを作ってみよう (1) | DNS クライアントを作ってみよう (3) >> 次へ |
ご意見・ご指摘は Twitter: @68user までお願いします。