Windows計算機でTCPチェックサムを計算する方法
こんにちは。今回はTrema/SDNな話題ではありませんが、それにちょっと関連した手作りTransmission Control Protocol(TCP)の話です。
■■ Windowsの計算機でTCPチェックサムを計算する方法 ■■
下記のようなTCP SYNのパケットのTCPチェックサムを計算機で算出する方法について解説します。
5 0.950136 10.0.0.30 10.0.0.100 TCP 70 53896 > http [SYN] Seq=0 Win=5840 Len=0 MSS=1460 SACK_PERM=1 WS=1
Internet Protocol Version 4, Src: 10.0.0.30 (10.0.0.30), Dst: 10.0.0.100 (10.0.0.100)
Transmission Control Protocol, Src Port: 53896 (53896), Dst Port: http (80), Seq: 0, Len: 0
Checksum: 0xd257 [validation disabled]
このパケットでは16進数で「0xd257」とあります。これを算出していきます。
■■■ TCPヘッダ作成 ■■■
まずは、TCPヘッダを作成します。
TCPヘッダ全体をWireshark→右クリック→Copy→Bytes→Hex Streamします。
d28800506b16338000000000800216d0d2570000020405b40101040201030300 ↑この辺りです。
上の16進数の並びのうち、チェックサム「d257」が含まれていますね?
それを「0000」に置換したものがこちら。
d28800506b16338000000000800216d000000000020405b40101040201030300
TCPを作るOSにとっては、これがチェックサム作成前の状態です。シーケンス番号やポート番号などはすでにそろった上で、最後にチェックサムが作成されるのです。
■■■ 疑似ヘッダ作成 ■■■
疑似ヘッダはTCPヘッダのマネをすることかのように聞こえますが、IPヘッダの情報を使って独自の形式でヘッダを作ってしまうことです。実際のIPヘッダとは長さ/内容が違います。
下記IPヘッダ値をWireshark→右クリック→Copy→Bytes→Hex Streamして、情報を取得していきます。
Source: 10.0.0.30 (10.0.0.30) → 0a00001e Destination: 10.0.0.100 (10.0.0.100) → 0a000064 Protocol: TCP (6) → 06
そしてTCPヘッダ長+TCPデータ長を算出します。この例ではSYNパケットでありデータはないのでヘッダ長のみ取り出します。
Wiresharkより「Header length: 32 bytes」。ここが一番ハマりポイントです。32バイトを16進数で表現すると“8”です。上の16進数だと、「d2 88 00 50 6b 16 33 80 00 00 00 00 80」の中の最後の“8”です。
Wiresharkなどは便宜上1バイトごとに区切るため16進数2文字セットになっているので、“80”にも見えますが、実は1バイトではなく4ビット長の値なので、左側の“8”しか使わないということです。
しかし、単純に8イコール8バイトかと言うとそうではなくて、Wikipedia - Transmission Control Protocol によると、「ヘッダ長(4ビット)- TCPヘッダのサイズを32ビットワード単位で表す」です。
つまり8×4バイト(32ビット)である32バイト、がTCPヘッダ長だということです。
さらに、ここから32バイトを16進数で表現するため、32を10進数→16進数変換して“20”になります。
ということで、疑似ヘッダをようやく組み合わせる段階です。
0a00001e + 0a000064 + 00(チェックサム作成前のため0で埋めます) + 06 + 0020
つなげると、
0a00001e0a00006400060020
となり、疑似ヘッダ完成です。
■■■ 疑似ヘッダとTCPヘッダを組み合わせる ■■■
疑似ヘッダ 0a00001e0a00006400060020
TCPヘッダ d28800506b16338000000000800216d000000000020405b40101040201030300
これらをつなげて
0a00001e0a00006400060020d28800506b16338000000000800216d000000000020405b40101040201030300
となります。
■■■ 全て足し算、桁あふれも足し算、そしてxor ■■■
2バイトごと(4文字ごと)に " + " を挿入して、計算機に流し込めるようにします。
0a00 + 001e + 0a00 + 0064 + 0006 + 0020 + d288 + 0050 + 6b16 + 3380 + 0000 + 0000 + 8002 + 16d0 + 0000 + 0000 + 0204 + 05b4 + 0101 + 0402 + 0103 + 0300
これをマウスで選択しコピーし、Windowsのスタートボタン→すべてのプログラム→アクセサリ→電卓で計算機ソフトを開きます。
16進数で計算できるように、電卓のメニューの表示→プログラマを選択し、この状態でペーストして「= (イコール)」を押します。
22DA6
という結果が返ってくるはずです。
このうち右側4ケタ「2DA6」と左側の5桁目以降を足します。
2DA6 + 2
これを電卓にコピペしてイコールを押すと、
2DA8
と出ます。これのxorを取ります。
XOR(排他的論理和)については wikipedia に解説があります。
2DA8 xor ffff
ということですが、電卓には2DA8をコピペ、xor押下、ffffをコピペ、イコール押下です。
すると、「D257」が出ます。
Checksum: 0xd257 [validation disabled]
と同じになりますね。これで完了です。
■■■ 送信側・受信側での使い方 ■■■
受信側であればチェックサムの位置に入っている値と、今作った値が一致しているか確認します。
送信側であればチェックサムの位置に入れた値 "0000" を、今作った値に置き換えると、
d28800506b16338000000000800216d0d2570000020405b40101040201030300
となり、これを送信します。