Mac 10.6.8 でソケットを使ってプログラミングしています。パケットを受信すると、常に IP ヘッダーから始まります。Wireshark を使用して着信パケットを分析してきましたが、マシンのソケット実装が IP ヘッダーの「合計長」フィールドを一貫して変更することに気付きました。具体的には、IP ヘッダーの長さを減算し、バイトを (ネットワークからホストの順序に) 逆にします。
たとえば、Wireshark によって報告された IP ヘッダーの先頭は次のとおりです。
45 c0 00 38 ...
それは次のように分解されます。
- 4 ビット (0x4): IP バージョン: 4
- 4 ビット (0x5): IP ヘッダー長: 5 ワード (20 バイト)
- 8 ビット (0xc0): 差別化サービス フラグ
- 16 ビット (0x0038): 全長: 56 バイト
ただし、recvfrom
同じパケットで満たされたバッファーの内容を出力すると、別の LED が表示されます。
ssize_t recvbytes = recvfrom(sock->fd, buffer, size, /*flags=*/0,
(struct sockaddr*)src, &src_len);
戻り値
45 c0 24 00 ...
- 4 ビット (0x4): IP バージョン: 4
- 4 ビット (0x5): IP ヘッダー長: 5 ワード (20 バイト)
- 8 ビット (0xc0): 差別化サービス フラグ
- 16 ビット (0x2400): 全長: 9216 バイト (?!)
バッファにアクセスする前に、ソケットの実装が全長を読み取り、IP ヘッダーの長さを差し引いてから、ネットワークの順序 (ビッグ エンディアン) ではなく、ホストの順序 (私のマシンではリトル エンディアン) で書き戻していることがわかりました。 . この例では、次のことを意味します。
- 全長を読む: 0x0038 = 56
- ヘッダーの長さを引きます: 56 - 20 = 36
- ホスト順に書き戻す: 36 = 0x0024 (ビッグ エンディアン) = 0x2400 (リトル エンディアン = 私のマシンのホスト順)
問題は悪化します。最も外側の IP ヘッダーの全長を変更するだけではありません。また、内部 IP ヘッダーの全長フィールドも変更します。たとえば、ICMP の「時間超過」メッセージに埋め込まれているもの (ドロップされたパケットの元の IP ヘッダーを含む必要があります)。さらに面白いことに、内部ヘッダーから IP ヘッダーの長さを差し引くことはありません。バイト順を逆にするだけです。
これは他の誰かに起こっていますか?それは私が知らない標準の一部ですか?マシンのソケット実装を修正して、パケットの改ざんを停止する方法はありますか? Wireshark はこの問題をどのように回避できますか?
ご検討いただきありがとうございます。
編集: 私のコードと Makefile はGitHubで入手できます。IP チェックサムを検証できるfixip_osx
関数を作成しました。
https://github.com/thejohnfreeman/netutils/blob/master/lib/ip.c
void fixip_osx(struct ip* ip) {
/* Something on my Mac subtracts the header length from `ip_len` and stores
* it in host order (little endian). */
u16_t ip_hdrlen = ip->ip_hl << 2;
u16_t ip_totlen = ip->ip_len + ip_hdrlen;
ip->ip_len = htons(ip_totlen);
}
ただし、ペイロードに別の IP ヘッダーが含まれている場合、ICMP チェックサムを検証することは依然として問題です。
問題は、Clang 3.2 (トランクからビルド) または GCC 4.7 (MacPorts ポート) でコンパイルするかどうかに関係なく存在するため、ソケットの実装 (Mac OS にパッケージ化されている) または Mac OS X 自体に問題があると思います。