如何确定原始数据包中IP头和TCP头的起始字节
Posted
技术标签:
【中文标题】如何确定原始数据包中IP头和TCP头的起始字节【英文标题】:how to determine the starting byte of IP Header and TCP header in a raw packet 【发布时间】:2013-03-04 01:12:45 【问题描述】:我想用libpcap抓包 但由于以太网标头或 802.11 标头的长度可能会有所不同 IP头的长度也可能不同, 如何确定 IP 标头和 TCP 标头的起始字节(指针) 另外,如何区分一个数据包是纯IP数据包、TCP数据包还是UDP数据包? 是否有任何 API 或方法可以做到这一点? 谢谢!
【问题讨论】:
以太网头的长度不能变化!在偏移量 14 处,您将找到 IP 数据包,然后从那里您可以找到 IP 标头的长度并将其添加到 14 以获得 TCP 标头的偏移量。 那么 802.11 标头呢? 我从来没有在数据包捕获中看到过其中的一个,我也不是很熟悉它,但它似乎有一个固定的大小(30 字节 + 4 字节的预告片),所以,也不是问题。 当我收到一个数据包时,我必须判断第二层包头的大小,因为它可能是以太网包头或802.11包头。 但是在单个捕获文件中,数据包都是相同类型的,the header tells you which one it is! 【参考方案1】:当您使用 libpcap 时,您可以通过直接查看 pcap 文件头(对于离线捕获)pcap_file_header.linktype
或(对于实时和离线捕获)调用 @ 来确定链接层头的大小987654322@。大多数情况下,这将是LINKTYPE_ETHERNET
。为确保数据包是 IPv4,您可以转换为以太网标头并检查以确保以太网类型为 ETHERTYPE_IP
(确保将其包装在 ntohs()
内。我通常将 bpf 过滤器应用于我的 pcap 实例化,所以我从不担心但是,要检查更高层协议并假设您使用的是pcap_dispatch()
,您可以按照以下方式编写回调:(libnet 库对于其广泛的可移植数据包结构仍然有用):
#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;
【讨论】:
如果您使用 libpcap/WinPcap 读取离线捕获,pcap_datalink()
将返回文件的链接层标头类型,因此您可以使用相同的代码进行实时捕获和读取捕获文件.
还要注意pcap_datalink()
返回DLT_
值,而不是LINKTYPE_
值;在 99 44/100% 的情况下,它们具有相同的数值,但在某些情况下,它们没有(某些操作系统对特定的 DLT_
定义使用不同的数值,但这在捕获文件中不起作用,所有操作系统的解释都必须相同)。以上是关于如何确定原始数据包中IP头和TCP头的起始字节的主要内容,如果未能解决你的问题,请参考以下文章