さて、私はネットワークから直接パケットを取り出し、そこから TCP ストリームを抽出しています。
簡単に言えば、これはさまざまなヘッダーを取り除くことを意味します (例: eth->IP->TCP->ストリーム データ)。
最終的にすべてのヘッダーを通過したときに呼び出される関数で、奇妙なエラーが発生しています。
/*Meta is a pointer to the IP header, pkt is a pointer to the TCP header*/
virtual const u_char* processPacket(const u_char* pkt, const u_char* meta) {
//Extract IP info from meta.
iphdr* metaHdr = (iphdr*)meta;
//Form TCP header from the current offset, hdr.
const tcphdr* hdr = (const tcphdr*)pkt;
//Do pointer math to figure out the size of the stream data.
u_int32_t len = ntohs(metaHdr->tot_len) - metaHdr->ihl*4 - hdr->doff*4;
if(len > 0)
{
//Store TCP stream data in a queue, mapped to it's IP source.
TCPStream* stream = new TCPStream();
stream->seqNumber = ntohl(hdr->seq);
stream->streamData = new u_char(len);
//memcpy(stream->streamData, offset(pkt), len);
for(u_int32_t i = 0; i < len; i++)
{
printf("k%i-%i",len, i); //Used to figure out when the segfault occurs.
stream->streamData[i] = offset(pkt)[i]; //Offset returns a pointer to the data under the TCP header
}
//streams[metaHdr->saddr].push(stream);
}
return offset(pkt);
};
TCP ストリームは、パケットのデータのコピーを指す単純なu_int32_t
およびです。u_char*
そのため、memcpy を使用していたときに segfault が発生しました。
明らかに、ポインタが無効であるか、長さを台無しにしていました。
この特定のパケットの場合、データの長さは 1380 バイト (Wireshark で確認) であるため、len は正しく計算されます。
わかりましたので、ポインターを台無しにする必要があります (NULL ではありません)。次の実験を行いました。
stream->streamData[0] = offset(pkt)[0]; //Works
stream->streamData[0] = offset(pkt)[len]; //Works, odd.
stream->streamData[len] = offset(pkt)[0]; //Fails, scary
stream->streamData[len] = offset(pkt)[len]; //Fails
したがって、streamData (具体的にはインデックス 1236) に逆参照しすぎると、segfault が発生します。ただし、streamData は次のようにインスタンス化されます。
stream->streamData = new u_char(len);
i=0 で streamData の反復処理を開始するので、大量のデータをスキップすることはありません。streamData はそのままなu_char*
のでoffset(pkt)
、u_char*
型を台無しにすることはありません。
これは、3000 以上の他のパケットを正常に反復した後、特定のパケットで失敗します。ダンプ ファイルは 27 メガバイトで、4 ギガの RAM があるので、不足しているとは思いません。 ?