72 class IPPacket 73 attr_accessor :id, :protocol, :daddr, :saddr, :payload 74 75 def initialize options 76 @id = options[ :id ] 77 @protocol = options[ :protocol ] 78 @daddr = options[ :daddr ] 79 @saddr = options[ :saddr ] 80 @payload = options[ :payload ] 81 @tot_len = 20 + payload.length 82 end 83 84 def pack 85 csum = get_checksum( 0, 0x4500 ) 86 header = [ 0x45, 0x00 ] # Version, IHL, ToS 87 88 csum = get_checksum( csum, @tot_len ) 89 header += [ @tot_len >> 8, @tot_len & 0xff ] # len 90 91 csum = get_checksum( csum, @id ) 92 header += [ @id >> 8, @id & 0xff ] # ID 93 94 csum = get_checksum( csum, 0x4000 ) 95 header += [ 0x40, 0x00 ] # Flags, Frag offset 96 97 csum = get_checksum( csum, 0x40 * 0x100 + @protocol ) 98 header += [ 0x40, @protocol ] # ttl, protocol 99 100 csum = get_checksum( csum, @saddr.to_i >> 16 ) 101 csum = get_checksum( csum, @saddr.to_i & 0xffff ) 102 csum = get_checksum( csum, @daddr.to_i >> 16 ) 103 csum = get_checksum( csum, @daddr.to_i & 0xffff ) 104 header += [ csum >> 8, csum & 0xff ] # checksum 105 header += @saddr.to_a + @daddr.to_a 106 107 header.pack( "C*" ) + @payload.pack 108 end 109 end 110 111 class ICMPPacket 112 attr_reader :payload, :length 113 114 def initialize type, code, payload 115 @type = type 116 @code = code 117 @payload = payload 118 @length = 4 + payload.length 119 end 120 121 def pack 122 @checksum = get_checksum( 0, @type * 0x100 + @code ) 123 124 words = @payload.pack( "C*" ).unpack( "n*" ) 125 words.each do | each | 126 @checksum = get_checksum( @checksum, each ) 127 end 128 129 [ @type, @code, @checksum ].pack( "C2n" ) + @payload.pack( "C*" ) 130 end 131 end 132 133 class ICMPEchoReply < ICMPPacket 134 def initialize payload 135 super( 0x00, 0x00, payload ) 136 end 137 end 138
72~82行目
IPパケットを作るクラスです。
73行目はアクセサの宣言をしています。
75行目のinitializeで引数を変数にセットしています。
@idには分割したIPパケットを復元する時に使用される識別子が入ります。
@protocolにはICMPやTCPといったをトランスポート層のプロトコルを識別する番号が入ります。
@daddrには宛先のIPアドレスが入ります。
@saddrには送信元のIPアドレスが入ります。
@payloadにはペイロード(転送したいデータ)が入ります。
@tot_lenにはIPヘッダーのバイト長の20と、ペイロードの長さを足した値が入ります。
73行目はアクセサの宣言をしています。
75行目のinitializeで引数を変数にセットしています。
@idには分割したIPパケットを復元する時に使用される識別子が入ります。
@protocolにはICMPやTCPといったをトランスポート層のプロトコルを識別する番号が入ります。
@daddrには宛先のIPアドレスが入ります。
@saddrには送信元のIPアドレスが入ります。
@payloadにはペイロード(転送したいデータ)が入ります。
@tot_lenにはIPヘッダーのバイト長の20と、ペイロードの長さを足した値が入ります。
84~109行目
IPパケットを作るメソッドです。
csum変数にはIPパケットのチェックサムが入ります。
header変数にはIPヘッダのフォーマットに合わせてデータを追加していきます。
86行目はバージョンとヘッダ長、サービス種別をheader変数に追加しています。
IPv4の場合、バージョンには固定で4が入ります。
ヘッダ長にはIPv4ヘッダの固定長部分の長さである20バイトを4バイトで割った数の5が入ります。
サービス種別はこのプログラムでは0x00が固定でセットされています。
89行目はデータ全長をheader変数に追加しています。
ここでは先頭から8け桁取り出すために8ビット右シフトし、末尾から8ビット取り出すために0xffで論理積をしています。
なぜこんなことをしているのか疑問でしたが、どうやらpackメソッドを使うのに8ビットずつの配列にする必要があるためだと思います。
91行目は識別子をheader変数に追加しています。
95行目はフラグと断片位置をheader変数に追加しています。
このプログラムではIPパケットを分割禁止にしています。
98行目はttlとプロトコルをheader変数に追加しています。
このプログラムではttlは64がセットされています。
100行目から104行目は、宛先IPアドレスと送信元IPアドレスからチェックサムの計算を行っています。
IPヘッダのフォーマットでは、チェックサムはプロトコルの次のフィールドなので、header変数にチェックサムの値を追加する前にチェックサムより後ろのフィールドの値でチェックサムの計算をしています。
104行目はチェックサムをheader変数に追加しています。
105行目は宛先IPアドスと送信元IPアドレスをheader変数に追加しています。
107行目でheader変数をバイナリに変換し、@payload変数をpackメソッドで変換して追加します。
csum変数にはIPパケットのチェックサムが入ります。
header変数にはIPヘッダのフォーマットに合わせてデータを追加していきます。
86行目はバージョンとヘッダ長、サービス種別をheader変数に追加しています。
IPv4の場合、バージョンには固定で4が入ります。
ヘッダ長にはIPv4ヘッダの固定長部分の長さである20バイトを4バイトで割った数の5が入ります。
サービス種別はこのプログラムでは0x00が固定でセットされています。
89行目はデータ全長をheader変数に追加しています。
ここでは先頭から8け桁取り出すために8ビット右シフトし、末尾から8ビット取り出すために0xffで論理積をしています。
なぜこんなことをしているのか疑問でしたが、どうやらpackメソッドを使うのに8ビットずつの配列にする必要があるためだと思います。
91行目は識別子をheader変数に追加しています。
95行目はフラグと断片位置をheader変数に追加しています。
このプログラムではIPパケットを分割禁止にしています。
98行目はttlとプロトコルをheader変数に追加しています。
このプログラムではttlは64がセットされています。
100行目から104行目は、宛先IPアドレスと送信元IPアドレスからチェックサムの計算を行っています。
IPヘッダのフォーマットでは、チェックサムはプロトコルの次のフィールドなので、header変数にチェックサムの値を追加する前にチェックサムより後ろのフィールドの値でチェックサムの計算をしています。
104行目はチェックサムをheader変数に追加しています。
105行目は宛先IPアドスと送信元IPアドレスをheader変数に追加しています。
107行目でheader変数をバイナリに変換し、@payload変数をpackメソッドで変換して追加します。
111~119行目
ICMPパケットを作るクラスです。
112行目はアクセサの宣言をしています。
114行目のinitializeで引数を変数にセットしています。
@typeには機能コードが入ります。
@codeには詳細な機能コードが入ります。
@payloadにはペイロード(転送したいデータ)が入ります。
@lengthにはICMPヘッダーのバイト長の4と、ペイロードの長さを足した値が入ります。
112行目はアクセサの宣言をしています。
114行目のinitializeで引数を変数にセットしています。
@typeには機能コードが入ります。
@codeには詳細な機能コードが入ります。
@payloadにはペイロード(転送したいデータ)が入ります。
@lengthにはICMPヘッダーのバイト長の4と、ペイロードの長さを足した値が入ります。
121~131行目
ICMPパケットを作るメソッドです。
@checksum変数にはチェックサムの値が入ります。
122行目の@checksum変数はget_checksumメソッドで@type変数と@code変数からチェックサムを求めています。
カッコ内の0x100は@type変数の値を256倍して16bitの先頭8bitに@type変数の値がくるようにします。
そこに@code変数の値を足し、こちらは末尾8bitが@code変数の値がくるようにします。
124行目は@payload変数の値をバイナリにし、unpackで16bitごとの配列にします。
その次のループでチェックサムを計算します。
129行目でICMPヘッダと@payload変数をバイナリにします。
@checksum変数にはチェックサムの値が入ります。
122行目の@checksum変数はget_checksumメソッドで@type変数と@code変数からチェックサムを求めています。
カッコ内の0x100は@type変数の値を256倍して16bitの先頭8bitに@type変数の値がくるようにします。
そこに@code変数の値を足し、こちらは末尾8bitが@code変数の値がくるようにします。
124行目は@payload変数の値をバイナリにし、unpackで16bitごとの配列にします。
その次のループでチェックサムを計算します。
129行目でICMPヘッダと@payload変数をバイナリにします。
133~137行目
ICMPリプライのパケットを作るクラスです。
ICMPPacketクラスを継承しています。
superでスーパークラスであるICMPPacketクラスのinitializeメソッドを呼び出します。
1つ目の引数はICMPのタイプでエコー応答の0、2つ目の引数はコードでエコー応答は固定で0が入ります。
ICMPPacketクラスを継承しています。
superでスーパークラスであるICMPPacketクラスのinitializeメソッドを呼び出します。
1つ目の引数はICMPのタイプでエコー応答の0、2つ目の引数はコードでエコー応答は固定で0が入ります。
今回はここまで。
router-utilsはあと少しで終わりです。
0 件のコメント:
コメントを投稿