【问题标题】:Tcp payload extraction and correct ip addressTcp有效载荷提取和正确的IP地址
【发布时间】:2012-02-08 19:38:20
【问题描述】:

我正在尝试从数据包中提取 tcp 有效负载,这是捕获回调的最小情况:

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. 但是这里出了点问题,源IP地址和目的IP地址是一样的。

  2. 此外,我怎样才能打印出有效载荷?由于我不能直接将 unsigned char 数组显式转换为以 "\0" 结尾的 char 数组,因此可能会出错。

    192.168.56.1:48065 --> 192.168.56.1:80

    192.168.56.80:80 --> 192.168.56.80:48065

编辑

----------

感谢 Celeda,我通过分离 inet_ntoa 的调用解决了 IP 地址问题:

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

现在是第二部分,我正在使用:

cout &lt;&lt; hex &lt;&lt; buff &lt;&lt; endl;

对于 HTTP 协议,我没有看到类似 "GET /" 的东西,而是多个空行

编辑 2

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

我现在不太确定 TCP 选项,我会查看更多有关详细信息的文档, 但目前这个功能很好。

    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;

    }

【问题讨论】:

  • 对于第二部分,我不确定,也许buff 没有完全指向正确的地方。我看到你这样做了buff += sizeof (tcphdr),但也许你还需要跳过一些 TCP 选项。我也不懂 C++,所以我不确定 hex &lt;&lt; buff 究竟做了什么。然而我怀疑它需要一个以 NUL 结尾的字符串。我认为您需要使用一些将长度作为输入的函数,这样它就不会超出数据包的末尾。

标签: tcp pcap


【解决方案1】:
  1. inet_ntoa() 使用静态缓冲区。您通过调用两次来覆盖缓冲区。请改用inet_ntop()。

  2. 负载可能是二进制数据。你想怎么打印出来?作为十六进制转储或类似的东西?只需查看有效负载并将字节一次打印为十六进制,以获得简单的十六进制转储。或者,如果您确定它是可打印的数据,您可以使用任何函数(例如 fwrite())将其直接转储到输出,该函数可让您指定要写入的字符串的长度。

编辑问题中的其他信息

您在 HTTP 数据之前看到的“额外字符”听起来像是您试图将其解释为有效负载数据的 TCP 选项。当您将buff 指针跳过它时,请务必正确计算 TCP 标头的大小。它是 4 个字节 * th_off。当您使用它时,您应该使用ip_hl 对 IP 标头执行相同的操作,因为 IP 标头也不总是 20 字节。

之后,for 循环中的结束条件是错误的。首先,ip_off(片段偏移量)不会进入其中,其次,ip_hl 和 tcp_off 都以 4 字节为单位,而不是字节。

将您的代码与 Wireshark 如何解码同一数据包进行比较,您将能够轻松诊断任何进一步的差异。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-19
    • 2016-04-11
    • 1970-01-01
    • 2016-07-27
    • 2017-03-28
    • 2021-12-05
    相关资源
    最近更新 更多