私のPythonプログラムは、rawソケットからICMP宛先到達不能メッセージを受信しています。ソケットは次のコードで作成されます。
socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
ICMP宛先到達不能メッセージには、元のパケットの一部のコピーが含まれます。私が経験している問題は、埋め込まれたIPv4ヘッダーの2バイトの合計長フィールドが、ソケットから受信するときにバイトが交換されることです。これが原因で、私のプログラムのチェックサムチェックに失敗します。パケットは次のコードで受信されます。
packet, sockaddr = socket_.recvfrom(bufsize)
チェックサムテストが失敗していることに気付いたとき、tcpdumpを使用してパケットを検査しました。次に例を示します。
11:54:36.377352 IP (tos 0xc0, ttl 64, id 36894, offset 0, flags [none], proto ICMP (1), length 112)
10.200.200.200 > 10.175.211.104: ICMP host 10.175.211.13 unreachable, length 92
IP (tos 0x0, ttl 63, id 49898, offset 0, flags [none], proto ICMP (1), length 84)
10.175.211.104 > 10.175.211.13: ICMP echo request, id 29449, seq 6, length 64
0x0000: 45c0 0070 901e 0000 4001 3807 0ac8 c8c8
0x0010: 0aaf d368 0301 fcfe 0000 0000 4500 0054
0x0020: c2ea 0000 3f01 fcea 0aaf d368 0aaf d30d
0x0030: 0800 403f 7309 0006 9b43 7718 e292 a89a
0x0040: 28cf 5283 dc65 8219 2778 837b 6c54 92f4
0x0050: 5092 e976 568c 6681 2afc 2b82 628d d0f6
0x0060: 2fa7 3493 1f48 9fdb ed98 2f53 da0e 87a6
次に、Pythonコードからパケットを印刷しました。これは、tcpdumpの例からの同じパケットです。
45,c0,5c,0,90,1e,0,0,40,1,38,7,a,c8,c8,c8,
a,af,d3,68,3,1,fc,fe,0,0,0,0,45,0,54,0,
c2,ea,0,0,3f,1,fc,ea,a,af,d3,68,a,af,d3,d,
8,0,40,3f,73,9,0,6,9b,43,77,18,e2,92,a8,9a,
28,cf,52,83,dc,65,82,19,27,78,83,7b,6c,54,92,f4,
50,92,e9,76,56,8c,66,81,2a,fc,2b,82,62,8d,d0,f6,
2f,a7,34,93,1f,48,9f,db,ed,98,2f,53,da,e,87,a6,
埋め込まれたヘッダーの全長フィールドは、2行目の最後の2バイトです。tcpdumpからの0054と私のプログラムからの5400。外部IPヘッダーのtotal-lengthフィールドも間違っています(tcpdumpの0070に対して5c00)。
私は走っています...
Python 2.6.1(r261:67515、2010年6月24日、21:47:49)[GCC 4.2.1(Apple Inc.ビルド5646)] on darwin
tcpdumpからのICMP宛先到達不能パケットのチェックサムフィールドは正しいです。fcfeの値があります。これは、outIPヘッダーのないパケットです。
0x0010: 0301 fcfe 0000 0000 4500 0054
0x0020: c2ea 0000 3f01 fcea 0aaf d368 0aaf d30d
0x0030: 0800 403f 7309 0006 9b43 7718 e292 a89a
0x0040: 28cf 5283 dc65 8219 2778 837b 6c54 92f4
0x0050: 5092 e976 568c 6681 2afc 2b82 628d d0f6
0x0060: 2fa7 3493 1f48 9fdb ed98 2f53 da0e 87a6
私を混乱させるのは、全長フィールドのみがネットワークバイトオーダーに対して修正されることです。他のマルチバイトフィールドは変更されず、Pythonプログラムと同じように出力されます。たとえば、全長の後の2バイトは、tcpdumpと印刷出力の両方でc2eaの値を持つ識別フィールドを構成します。チェックサムをチェックする目的でどのフィールドを交換する必要があるかをどのように判断できますか?