daisy
daisy

Reputation: 23501

Tcp payload extraction and correct ip address

I'm trying to extract tcp payload from a packet , and here's a minimal case of capture callback:

void capture_callback (u_char *hdr , const struct pcap_pkthdr* pkthdr , const u_char* buff)
{
    struct ether_header *eptr = (struct ether_header *) buff;
    buff += sizeof (ether_header); /* jump over ethernet header: 14 bytes */

    if ( ntohs (eptr->ether_type) == ETHERTYPE_IP )
    {
        struct ip *iph;
        struct tcphdr *tcp_header;

        iph = (struct ip *) buff;
        buff += sizeof (ip); /* jump over ip header */

        if ( iph->ip_p == IPPROTO_TCP )
        {
            tcp_header = (struct tcphdr *) buff;
            buff += sizeof (tcphdr); /* jump over tcp header */

            cout << inet_ntoa (iph->ip_src) << ":" << ntohs (tcp_header->th_sport) <<
                        " --> " << inet_ntoa(iph->ip_dst) << ":" << ntohs (tcp_header->th_dport) << endl;

        }

    }
}
  1. But something went wrong here , source and destination IP address are the same.

  2. And besides , how can i print out payload ? Since i can't just convert a unsigned char array to a char array explicitly, which ends on "\0" , it might get wrong.

    192.168.56.1:48065 --> 192.168.56.1:80

    192.168.56.80:80 --> 192.168.56.80:48065

EDIT

---------------------

THanks to Celeda , i solved the ip address issue by separating the call of inet_ntoa:

    cout << "IP: " << inet_ntoa (iph->ip_src) << ":" << ntohs (tcp_header->th_sport) <<
                " --> ";
    cout << inet_ntoa(iph->ip_dst) << ":" << ntohs (tcp_header->th_dport) << endl;

And now the second part , i'm using:

cout << hex << buff << endl;

For HTTP protocol , and i'm not seeing anything like "GET /" , but multiple blank line

EDIT 2

--------------------------

I'm not so sure about TCP options for now , i'll check more documents about details , but for now this functions well.

    if ( iph->ip_p == IPPROTO_TCP )
    {
        tcp_header = (struct tcphdr *) buff;
        buff += tcp_header->th_off * 4;

        cout << "IP: " << inet_ntoa (iph->ip_src) << ":" << ntohs (tcp_header->th_sport) <<
                    " --> ";
        cout << inet_ntoa(iph->ip_dst) << ":" << ntohs (tcp_header->th_dport) << endl;

        for ( int i = 0 ; i < iph->ip_len - iph->ip_off * 4; i ++ )
        {
            if ( isascii (buff[i]) )
            {
                cout << buff[i];
            }
        }
        cout << endl << "-----------" << endl;

    }

Upvotes: 0

Views: 1916

Answers (1)

Celada
Celada

Reputation: 22261

  1. inet_ntoa() uses a static buffer. You are overwriting the buffer by calling it twice. Use inet_ntop() instead.

  2. The payload might be binary data. How do you want to print it out? As a hex dump or something like that? Just look over the payload and print the bytes as hex one at a time for a simplistic hex dump. Or if you are sure that it's printable data you can dump it directly to the output with any function such as fwrite() that lets you specify the length of the string to write.

EDIT FOR ADDITIONAL INFORMATION IN THE QUESTION

The "extra characters" you see before the HTTP data sound like TCP options you are trying to interpret as payload data. Be sure to calculate the size of the TCP header correctly when you jump the buff pointer over it. It's 4 bytes * th_off. While you're at it, you should do the same for the IP header using ip_hl because the IP header is not always 20 bytes either.

Afterwards, the ending condition in your for loop is wrong. First, ip_off (the fragment offset) doesn't enter into it, and, second, both ip_hl and tcp_off are measured in units of 4 bytes, not in bytes.

Compare what you're getting with your code with how Wireshark decodes the same packet and you will be able to easily diagnose any further discrepancy.

Upvotes: 1

Related Questions