補足などと言えるほど理解していないかもですが、確認したことをメモしておきます。
例えば"abc123"という文字列をunpack("C*")すると[97, 98, 99, 49, 50, 51]という配列が返ってきます。
配列の数字は文字コードのようです。aの文字コードは97、1の文字コードは49です。
(pack.rb)
p "abc123".unpack("C*")]
$ ruby pack.rb [97, 98, 99, 49, 50, 51]
次に、unpack("C*")の後にpack("C*").unpack("n*")を追加すると、配列をバイナリにし、その後ビッグエンディアンの16bit 符号なし整数にします。
p "abc123".unpack("C*").pack("C*").unpack("n*")
$ ruby pack.rb [24930, 25393, 12851]
これはどうなったのかというと、配列の1つ目の24930は97と98をくっつけたものです。
(10進数)→(2進数)
24930→110000101100010
97→1100001
98→1100010
桁を揃えて結合すると同じ値になります
24930→0110000101100010
97,98→0110000101100010
99と49、50と51も同様です。
packのテンプレートの"C"が8bit 符号なし整数なので、丁度配列2つ分です。
24930→110000101100010
97→1100001
98→1100010
桁を揃えて結合すると同じ値になります
24930→0110000101100010
97,98→0110000101100010
99と49、50と51も同様です。
packのテンプレートの"C"が8bit 符号なし整数なので、丁度配列2つ分です。
続いて、テンプレート文字の"n"は何なのか。
16進数の0xffをpackしてみます。
p [0xff].pack("n*")
$ ruby pack.rb "\000\377"
0xffの8進数表現になりました。
他の数も試してみます。
p [0x01ff].pack("n*") p [0x0102ff].pack("n*")
$ ruby pack.rb "\001\377" "\002\377"
どうやら8ビットずつを8進数で表示したようです。
0x0102ffは後ろから16ビットだけが変換されたようで、数字が大きいと切られてしまうみたいですね。
router-utilsのソースで見てみます。
例えばICMPEchoReplyクラスの↓この辺など。
124 words = @payload.pack( "C*" ).unpack( "n*" ) 125 words.each do | each | 126 @checksum = get_checksum( @checksum, each ) 127 end
呼び出し元にさかのぼっていくと元データはmessage.dataです。
message.dataはネットワークに流れるデータなのでバイナリなのでしょう。
unpack("C*")で8bit 符号なし整数の配列にしています。
152 payload = message.data.unpack( "C*" )[ offset .. message.data.length - 1 ] 153 icmp = ICMPEchoReply.new( payload )
その後、(124行目)ICMPEchoReplyクラスでpack("C*")を実行して再びバイナリに変換し、unpack("n*")でビッグエンディアンの16bit 符号なし整数に変換しています。
IPヘッダやICMPヘッダのチェックサム(get_checksumメソッドで計算)は16ビットずつ計算していくので、unpack("n*")で16bitに変換して配列をループで処理しているようです。
以上になります。
0 件のコメント:
コメントを投稿