ネットワークエンジニアから着物屋さんとして独立しました。ネットショップのIT面を中心にお伝えします

RubyでTCP/IPのチェックサムを計算する

»

 Tremaでは低レイヤーにばかり関心が集まっているのか、TCPの細かな状態を取得・変化させる機能がまだ実装されていないようです。わたしが目指しているのは高レイヤーでのパケット書き換えなので、どうしてもTCP/IPのチェックサムを再計算する必要があります。

 以前の記事「Windows計算機でTCPチェックサムを計算する方法」では手作業で算出する方法を解説しましたが、今回はその方法をRubyで実装しました。Rubyでその計算を行うモジュール/メソッドです。

 16進数でデータを引数に渡して、結果も16進数で受け取ります。 TCPチェックサムの作成のためには擬似IPヘッダを作成する必要があり、そのためのメソッドが「mk_pseudo_ip_hdr」です。送信元&送信先IPとTCPヘッダ長を引数に取ります。「mk_checksum」メソッドでは、擬似IPヘッダとTCPヘッダとTCPデータを連結した16進数を引数に取ります。戻り値も16進数です。

 「mk_checksum」メソッドはIPチェックサム作成にも使えます。IPヘッダだけを16進数で取得し、既存のIPチェックサムを0パディングし、当メソッドの引数に入れると16進数でチェックサムが得られます。 以下がソースコードです。コピペしてお使いください。

module PacketInfo
	def mk_pseudo_ip_hdr src_ip, dst_ip, tcp_hdr_data_length
		# Expect instance of IP class in src_ip and dst_ip
		# Expect Integer in tcp_hdr_data_length

		pseudo_ip_hdr = ''
		for i2 in [src_ip, dst_ip]
			for i in [0, 1, 2, 3]
				pseudo_ip_hdr << i2.to_a[i].to_s(16).rjust(2, '0')
			end
		end
		pseudo_ip_hdr << '0006'
		#info "tcp_hdr_data_length: " + tcp_hdr_data_length.to_s
		pseudo_ip_hdr <<  tcp_hdr_data_length.to_s(16).rjust(4, '0')
		#info "pseudo_ip_hdr: " + pseudo_ip_hdr
	end

	def mk_checksum data_hex
		# Expect pseudo ip header + tcp header + tcp data in data_hex, in case of TCP
		#info "mk_checksum data_hex: \n" + data_hex

		checksum = 0
		for i in 0..(data_hex.length/4) do #/
			data_hex_sliced = data_hex.slice(4*i, 4)
			data_hex_sliced = data_hex_sliced.ljust(4, '0')
			checksum = checksum + data_hex_sliced.hex
			#print data_hex_sliced + " + "
		end
		#info ""
		#info "checksum: 0x" + checksum.to_s(16)

		while checksum.to_s(16).length > 4 do
			#info "checksum has more than 5 digits. Will cut it off."
			checksum_left = checksum.to_s(16).slice(0, checksum.to_s(16).length - 4)
			#info "checksum_left: " + checksum_left
			checksum_right = checksum.to_s(16).slice((checksum.to_s(16).length - 4)..-1)
			#info "checksum_right: " + checksum_right

			checksum = checksum_left.hex + checksum_right.hex
		end
		checksum = checksum ^ 0xffff
		#info "checksum: 0x" + checksum.to_s(16)
		return checksum
	end
end


Comment(0)

コメント

コメントを投稿する