>>3325 ken > 何故、16ビットと書いてあるのに第15ビットまでの説明までしか > ないのでしょうか? http://x68000.startshop.co.jp/~68user/net/resolver-2.html#flag のところですね。わたくしの誤りです。RCODE が 3ビットとなって いますが、正しくは4ビットです。近いうちに直します。 # 表の部分で「1……15bit」とあるところも、「1……16bit」の # 誤りですね。 > 質問数、回答数、権威数などはpackするときにネットワークバイト > オーダに変換しているのに、IDとフラグを変換しないのは何故でしょうか? http://x68000.startshop.co.jp/~68user/net/resolver-3.html#4 の以下の部分ですね (一部略)。 sub make_query { my ($type, $class) = @_; # 識別子設定 my $id = pack('B16', '0000000000000000'); # フラグを構成する各要素を設定 my $qr = QR::Query; # 0:質問 my $opcode = OPCODE::StandardQuery; # 0:標準照会 my $aa = 0; # Authoritative Answer (応答時にセット) # フラグ (0 と 1 の文字列) my $flg_binary = sprintf("%d%04d%d%d%d%d%03d%d", $qr, $opcode, $aa, (略)); # フラグ (2バイトのバイナリ) my $flg = pack("B16", $flg_binary); # 質問数のみ 1。回答数、権威数、追加情報数はいずれも 0。 my $question_count = pack('n', 1); my $response_count = pack('n', 0); # foo.example.com というホスト名を 3foo7example3com という形に変換。 my $query_name = &make_domain($query_host); # リクエストは「識別子+フラグ+質問数+回答数+権威数+追加情報数+質問」からなる。 my $request = $id.$flg.$question_count.$response_count.$auth_count.$ext_count.$question; return $request; } ID やフラグは pack('B16') でバイナリデータに変換していますが、 その際に順番が入れ替わることはありません。 pack('B16', '1111000000000011') は順序を保持したまま 1111000000000011 となります。 0000001111110000 となることはありません。 ただし数値の場合は、Short 値を作ろうとして素直に my $question_count = pack('s', 1); などとしてしまうと、リトルエンディアンな Intel 系では 0x01 0x00、 ビッグエンディアンな Motorola・Sparc 系では 0x00 0x01 となって しまいます。よってこの場合は my $question_count = pack('n', 1); と n を使って、どの環境でも 0x00 0x01 となるようにするわけです。 > データを受信した時、細かく言うと$restにはどういった順番でデータが > 入っているのでしょうか? 以下、http://x68000.startshop.co.jp/~68user/net/sample/resolver-1.pl の sub parse_response 関数の説明をします。 my ($id, $flg, $question_count, $response_count, $auth_count, $ext_count, $rest) = unpack('nnnnnna*', $org_dgram); の時点では、$rest には「(7)質問レコード以降のデータ」(回答レコード・権威 レコード・追加情報レコードも含む) が入っています。 データの順序は http://x68000.startshop.co.jp/~68user/net/resolver-2.html#4 の「解析した応答の構成」の順のとおりです。 $rest の先頭のデータは「(7)質問レコード」ですが、「(7)質問レコード」は (7.1)照会名 (可変長) (7.2)照会タイプ (7.3)照会クラス から成り立っていますので、$rest の先頭データは「(7.1)照会名」であるとも 言えます。 その後、 foreach my $count ($question_count){ my $domain; # この時点で $rest の先頭データは「(7.1)照会名」 ($domain, $rest) = get_domain($rest, $org_dgram); # この時点で $rest の先頭データは「(7.2)照会タイプ」 my ($type, $class) = unpack('nn', $rest); # ↑「(7.2)照会タイプ」と「(7.3)照会クラス」を取り出す。 substr($rest, 0, 4) = ''; # ↑取り出した「(7.2)照会タイプ」と「(7.3)照会クラス」を削る。 printf "質問: ドメイン名: %s\n", $domain; printf "質問: タイプ: %d (%s)\n", $type, TYPE::getName($type); printf "質問: クラス: %d (%s)\n", $class, CLASS::getName($class); print $hr_line; } といったふうに、$rest の先頭部分から順に、データを取り出す⇒削る という処理を繰り返します。 質問部分を読み終わると、$rest にはリソースレコード (回答・権威・追加情報) が 残っています。リソースレコードは ドメイン名 (可変長) タイプ クラス 生存時間 (TTL) リソースデータ長 リソースデータ (可変長) から成っていますので、 foreach (1 .. $count){ my $domain; ($domain, $rest) = get_domain($rest, $org_dgram); # ↑ここでドメインを切り出す。 my ($type, $class, $ttl, $rdata_length) = unpack('nnNn', $rest); # ↑タイプ・クラス・生存時間・リソースデータ長を取り出す。 substr($rest, 0, 10) = ''; # ↑タイプ・クラス・生存時間・リソースデータ長の分を削る。 my ($rdata) = substr($rest, 0, $rdata_length); substr($rest, 0, $rdata_length) = ''; # ↑リソースデータ取得 } と、ここでもやはり「データを先頭から取り出し、削る」の繰り返している わけです。 |