在环回上捕获数据包

时间:2016-09-05 09:37:36

标签: c++ macos endianness libpcap

这个代码在Ubuntu 16.04上完全正常,当我通过loopback接口抛出UDP字节时,打印正确的值(ETHERTYPE_IP):

#include <pcap.h>
#include <iostream>
#include <net/ethernet.h>

int main(int argc,char **argv)
{
    char errbuf[PCAP_ERRBUF_SIZE];
    auto pcap = pcap_open_live("lo0", BUFSIZ, 0, 1000, errbuf);

    pcap_loop(pcap,0, [] (u_char *self, const struct pcap_pkthdr *header,
                          const u_char *packet) {
        auto eth = (struct ether_header *) packet;
        auto eth_type = ntohs(eth->ether_type);
        std::cout << "eth_type: " << std::hex << eth_type << std::endl;
    }, nullptr);

    return 0;
}

netcat的:

➜  ~ nc -uv -l 54321
Listening on [0.0.0.0] (family 0, port 54321)

➜  ~ nc -4u localhost 54321
hello

节目输出:

➜  ~ sudo ./a.out
eth_type: 800

然而,在OS X 10.11.5上,它打印 eth_type:4011 。有趣的是它适用于 en1 适配器。

为什么loopback和非loopback适配器之间存在这样的差异?在两者上捕获数据包的正确方法是什么?

更新 tcpdump也有效:

➜  ~ sudo tcpdump -i lo0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo0, link-type NULL (BSD loopback), capture size 262144 bytes
15:09:00.160664 IP localhost.54321 > localhost.63543: UDP, length 4

1 个答案:

答案 0 :(得分:1)

由于链接类型不是以太网,标头不包含ether_header的合适数据。

在使用pcap_open_live获取句柄后添加此代码以查看链接层标题类型:

if (pcap_datalink(pcap) != DLT_EN10MB) {
    fprintf(stderr, "Device doesn't provide Ethernet headers - link type was %d\n", pcap_datalink(pcap));
    return 1;
}

运行此指示lo0的linktype值为0,DLT_NULL。文档说明这意味着&#34; BSD环回封装;链路层头是一个4字节的字段,按主机字节顺序,包含来自socket.h的PF_值,用于数据包的网络层协议。&#34;

实际上,当我查看ether_dhost字段的前4个字节时,我看到值2,对应于PF_INET。最后,如果您尝试区分UDP数据包,这对您没什么帮助。

您可以在此处找到更多文档:http://www.tcpdump.org/linktypes.html