【发布时间】:2020-09-03 12:52:27
【问题描述】:
我正在编写一个 C 程序,它构建一个以太网/IPv4/TCP 网络数据包,然后将数据包写入 PCAP 文件以供检查。我从SO post here. 构建我的代码 我的代码的第一个版本运行良好,但它是一个很大的main() 函数,不能移植到更大的程序中。
所以我重新组织了代码,以便将其移植到另一个程序中。我不想在这篇文章中讨论版本 1 和版本 2 之间的区别。但不用说,第 2 版效果很好,除了一个烦人的怪癖。当 Wireshark 打开第 1 版 PCAP 文件时,它看到我的第 2 层是以太网 II:
Frame 1: 154 bytes on wire (1232 bits), 154 bytes captured (1232 bits)
Ethernet II, Src: 64:96:c8:fa:fc:ff (64:96:c8:fa:fc:ff), Dst: Woonsang_04:05:06 (01:02:03:04:05:06)
Destination: Woonsang_04:05:06 (01:02:03:04:05:06)
Source: 64:96:c8:fa:fc:ff (64:96:c8:fa:fc:ff)
Type: IPv4 (0x0800)
Internet Protocol Version 4, Src: 10.10.10.10, Dst: 20.20.20.20
Transmission Control Protocol, Src Port: 22, Dst Port: 55206, Seq: 1, Ack: 1, Len: 100
SSH Protocol
但在第 2 版中,第 2 层标头变成了 802.3 以太网:
Frame 1: 154 bytes on wire (1232 bits), 134 bytes captured (1072 bits)
IEEE 802.3 Ethernet
Destination: Vibratio_1c:08:00 (00:09:70:1c:08:00)
Source: 45:00:23:28:06:cf (45:00:23:28:06:cf)
Length: 64
Trailer: 050401040204000001020506040400070602040704060202…
Logical-Link Control
Data (61 bytes)
[Packet size limited during capture: Ethernet truncated]
我不是网络专家,但我猜我的第 2 版 PCAP 文件在某个地方格式不正确。我应该不在其中有一个逻辑链接控制标题;我的代码认为它正在编写以太网 II / IPv4 / TCP 标头。在这一点上,我的直觉是 PCAP 数据包标头(处理 PCAP 文件中的每个数据包所必需的)或我的以太网标头不正确,不知何故。哪个会告诉 Wireshark “接下来的 X 字节是以太网 II 标头?”
这是我的代码,摘录:
PCAP 标头和以太网帧的结构直接来自 the before-mentioned SO post. 该帖子中的解决方案是使用pcap_sf_pkthdr 结构作为 PCAP 数据包标头:
// struct for PCAP Packet Header - Timestamp
struct pcap_timeval {
bpf_int32 tv_sec; // seconds
bpf_int32 tv_usec; // microseconds
};
// struct for PCAP Packet Header
struct pcap_sf_pkthdr {
struct pcap_timeval ts; // time stamp
bpf_u_int32 caplen; // length of portion present
bpf_u_int32 len; // length this packet (off wire)
};
以太网标头来自原帖:
// struct for the Ethernet header
struct ethernet {
u_char mac1[6];
u_char mac2[6];
u_short protocol; // will be ETHERTYPE_IP, for IPv4
};
这两种结构都没有太多内容,对吧?我真的不明白 Wireshark 是怎么看这个的,并且知道数据包的前 20 个字节是以太网。
以下是实际代码,略有删节:
#include <netinet/in.h> // for ETHERTYPE_IP
struct pcap_sf_pkthdr* allocatePCAPPacketHdr(struct pcap_sf_pkthdr* pcapPacketHdr ){
pcapPacketHdr = malloc( sizeof(struct pcap_sf_pkthdr) );
if( pcapPacketHdr == NULL ){
return NULL;
}
uint32_t frameSize = sizeof( struct ethernet) + …correctly computed here
bzero( pcapPacketHdr, sizeof( struct pcap_sf_pkthdr ) );
pcapPacketHdr->ts.tv_sec = 0; // for now
pcapPacketHdr->ts.tv_usec = 0; // for now
pcapPacketHdr->caplen = frameSize;
pcapPacketHdr->len = frameSize;
return pcapPacketHdr;
}
void* allocateL2Hdr( packetChecklist* pc, void* l2header ){
l2header = malloc( sizeof( struct ethernet ) );
if( l2header == NULL ){
return NULL;
}
bzero( ((struct ethernet*)l2header)->mac1, 6 );
bzero( ((struct ethernet*)l2header)->mac2, 6 );
// …MAC addresses filled in later…
((struct ethernet*)l2header)->protocol = ETHERTYPE_IP; // This is correctly set
return l2header;
}
...以及使用上述功能的代码...
struct pcap_sf_pkthdr* pcapPacketHdr;
pcapPacketHdr = allocatePCAPPacketHdr( pcapPacketHdr );
struct ethernet* l2header;
l2header = allocateL2Hdr( l2header );
稍后,代码填充这些结构并将它们连同 IPv4 标头、TCP 标头等写入文件。
但我认为我的问题是我真的不明白 Wireshark 应该如何知道我的以太网标头是以太网 II 而不是带有逻辑链路标头的 802.3 以太网。是否在 PCAP 数据包标头中进行了通信?或者在某个地方的以太网框架中?我希望得到建议。谢谢
【问题讨论】: