如何确定原始数据包中IP头和TCP头的起始字节

如何确定原始数据包中IP头和TCP头的起始字节,tcp,udp,ip,libpcap,Tcp,Udp,Ip,Libpcap,我想使用libpcap捕获数据包 但由于以太网报头或802.11报头的长度可能会有所不同 IP报头的长度也可能不同, 如何确定IP头和TCP头的起始字节(指针) 此外,如何区分数据包是纯IP数据包、TCP数据包还是UDP数据包? 有什么API或方法可以做到这一点吗? 谢谢 使用libpcap时,您可以通过直接查看pcap文件头(用于脱机捕获)pcap\u文件头.linktype或通过调用pcap\u datalink()来确定链接层头的大小。大多数情况下,这将是LINKTYPE\u ETHERN

我想使用libpcap捕获数据包 但由于以太网报头或802.11报头的长度可能会有所不同 IP报头的长度也可能不同, 如何确定IP头和TCP头的起始字节(指针) 此外,如何区分数据包是纯IP数据包、TCP数据包还是UDP数据包? 有什么API或方法可以做到这一点吗?
谢谢

使用libpcap时,您可以通过直接查看pcap文件头(用于脱机捕获)
pcap\u文件头.linktype
或通过调用
pcap\u datalink()
来确定链接层头的大小。大多数情况下,这将是
LINKTYPE\u ETHERNET
。要确保数据包是IPv4,您可以强制转换到以太网报头并检查以太类型是否为
ethertype\u IP
(确保将其包装在
ntohs()中)
。我通常将bpf过滤器应用于我的pcap实例化,因此我从不担心这些问题。但是,要检查更高层协议,并假设您使用的是
pcap_dispatch()
,您可以按照以下方式编写回调:(libnet库对于其广泛的可移植数据包结构仍然很有用):

#包括
#包括
无效的
process_数据包(u_char*user,const struct pcap_pkthdr*头,const u_char*数据包)
{
结构libnet_ipv4_hdr*ip;
结构libnet_udp_hdr*tcp;
uint16_t ip_hl、udp_hl、标头_cruft;
ip=(结构libnet_ipv4_hdr*)(数据包+libnet_ETH_H);
ip_hl=ip->ip_hl ip_p)
{
案例IPPROTO_UDP:
udp=(结构libnet_udp_hdr*)(数据包+libnet_ETH_H+ip_hl);

udp_hl=tcp->th_off以太网报头的长度不能改变!在偏移量14处,您将找到IP数据包,然后从那里您可以找到IP报头的长度,并将其添加到14以获得tcp报头的偏移量。那么802.11报头呢?我从未在数据包捕获中看到过其中的一个,我对它不是很熟悉,但是它似乎有一个固定的大小(30字节+4字节的拖车),所以,这也不是问题。当我收到一个数据包时,我必须判断第二层报头的大小,因为它可能是以太网报头或802.11报头。但是在一个捕获文件中,数据包的类型都是相同的,而且!如果您正在使用libpcap/WinPcap读取脱机捕获,
pcap\u datalink()
将返回文件的链接层头类型,因此您可以使用相同的代码实时捕获和读取捕获文件。还要注意,
pcap\u datalink()
返回
DLT\u
值,而不是
LINKTYPE\u
值;在99 44/100%的情况下,它们具有相同的数值,但在某些情况下,它们没有(某些操作系统对特定的
DLT\uu
定义使用不同的数值,但这在捕获文件中不起作用,因为所有操作系统上的解释都需要相同)。
#include <libnet.h>
#include <pcap.h>

void
process_packet(u_char *user, const struct pcap_pkthdr *header, const u_char *packet)
{
    struct libnet_ipv4_hdr *ip;
    struct libnet_udp_hdr  *tcp;
    uint16_t ip_hl, udp_hl, header_cruft;

    ip     = (struct libnet_ipv4_hdr *)(packet + LIBNET_ETH_H);
    ip_hl  = ip->ip_hl << 2;

    switch (ip->ip_p)
    {
        case IPPROTO_UDP:
            udp    = (struct libnet_udp_hdr *)(packet + LIBNET_ETH_H + ip_hl);
            udp_hl = tcp->th_off << 2;
            header_cruft = LIBNET_ETH_H + ip_hl + tcp_hl;
            break;
        case IPPROTO_TCP:
            /** you get the idea */
            break;
        default:
            break;
    }