1

さて、私はネットワークから直接パケットを取り出し、そこから 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 があるので、不足しているとは思いません。 ?

4

1 に答える 1

11
stream->streamData = new u_char(len);

これにより、 に初期化された単一の文字が割り当てられlenます。

配列を割り当てるには、次を使用します。

stream->streamData = new u_char[len];

そして、あなたがそれを解放する場所はいつでも:

delete [] stream->streamData;

編集:

stream->streamData[len] = offset(pkt)[0]; //Fails, scary

配列が正しく割り当てられたとしても、これは未定義の動作です。アクセスする有効なインデックスは 0 からlen それ以外です。

于 2009-11-25T20:24:37.473 に答える