我有这段代码,可以很好地用libpcap编写一个pcap文件(仅用于测试的以太网协议):
struct ethernet {
u_char mac1[6];
u_char mac2[6];
u_short protocol;
};
int main() {
pcap_t *pd;
pcap_dumper_t *pdumper;
pd = pcap_open_dead(DLT_EN10MB, 65535);
pdumper = pcap_dump_open(pd, "test.pcap");
struct pcap_pkthdr packet_header;
struct timeval ts;
packet_header.ts = ts;
packet_header.caplen = sizeof(struct ethernet);
packet_header.len = sizeof(struct ethernet);
struct ethernet ethernet;
bzero(ethernet.mac1, 6);
bzero(ethernet.mac2, 6);
ethernet.protocol = 8977; // randomly choose
pcap_dump((u_char*)pdumper, &packet_header, (const u_char*)ðernet);
pcap_close(pd);
pcap_dump_close(pdumper);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是我想尝试不使用pcap函数,所以我开始修饰上面使用的函数。
这是我发现的来源:
pcap_open_dead函数:http ://www.wand.net.nz/trac/libtrace/browser/lib/pcap_open_dead.c?rev=808a478a2459f3cf0e8bf927fcaad371138efb20
pcap_dump_open,pcap_dump等:http : //www.opensource.apple.com/source/libpcap/libpcap-2.1/libpcap/savefile.c
所以,这是我的想法:
pcap_open_dead函数是无用的,只是实例化一个pcap_t结构(我不想在我的代码中使用)并用参数填充其值。
pcap_dump_open返回一个pcap_dumper_t(似乎就像一个FILE *),只是打开文件并在其中写入标题(如果我们不关心错误处理的话)。顺便说一句,似乎它给sf_write_header提供了“ p-> tzoff”作为参数,该参数尚未在我的代码中初始化(并且仍在工作)。关于链接类型,在我们的例子中,它等于1。
最后,pcap_dump函数将pcap_dumper_t变量作为第一个参数,该变量隐式转换为u_char *,然后显式转换为FILE *(为什么从一开始就不使用FILE *?)然后,它使用包头和包数据进行写入他们用fwrite到文件中。
所以这就是我所做的:
FILE *fd = fopen("test.pcap", "w");
struct pcap_file_header header;
header.magic = 0xa1b2cd34;
header.version_major = 2;
header.version_minor = 4;
header.thiszone = 0;
header.sigfigs = 0;
header.snaplen = 65535;
header.linktype = DLT_EN10MB;
struct pcap_pkthdr packet_header;
struct timeval ts;
packet_header.ts = ts;
packet_header.caplen = sizeof(struct ethernet);
packet_header.len = sizeof(struct ethernet);
struct ethernet ethernet;
bzero(ethernet.mac1, 6);
bzero(ethernet.mac2, 6);
ethernet.protocol = 8977;
fwrite((char*)&header, sizeof(header), 1, fd);
fwrite((char*)&packet_header, sizeof(struct pcap_pkthdr), 1, fd);
fwrite((char*)ðernet, sizeof(struct ethernet), 1, fd);
close(fd);
Run Code Online (Sandbox Code Playgroud)
无需使用pcap_t结构,我将snaplen和linktype值直接放在pcap_file_header结构中。
然后,我使用fwrite就像在pcap函数中一样。
头文件很好,如果我只是在文件中写头,我就能用wireshark打开文件。但是,当我添加最后2个fwrite(写入数据包头和数据包)时,wireshark告诉我:
The capture file appears to be damaged or corrupt.
(pcap: File has 4195245-byte packet, bigger than maximum of 65535)
Run Code Online (Sandbox Code Playgroud)
我找不到我的错误在哪里,也不知道他在哪里看到那么多字节。
编辑
我没有使用未初始化的时间周期,而是这样做了:
packet_header.ts = (struct timeval){0};
Run Code Online (Sandbox Code Playgroud)
现在可以正常工作了,但是当使用pcap函数时如何解释它正常工作呢?“ ts”仍未初始化。
这个时间间隔是什么意思?将其设置为零有意义吗?
小智 5
struct pcap_pkthdr packet_header;
这就是提供给程序的数据包头的格式。这是不必需,因为它是存储在文件中的数据包报头的格式; 它包含一个struct timeval,其大小取决于a time_t是32位还是64位。
您需要的是:
struct pcap_timeval {
bpf_int32 tv_sec; /* seconds */
bpf_int32 tv_usec; /* microseconds */
};
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) */
Run Code Online (Sandbox Code Playgroud)
};
并struct pcap_sf_pkthdr改为使用。将struct pcap_pkthdr结构写入文件将在tv_secor的tv_usec字段struct timeval不是32位的任何系统上生成无效的pcap文件。在任何64位系统上可能都是这种情况。在这种情况下,您很可能会遇到类似“损坏或损坏”的错误。
至于时间戳的含义,在实际捕获中,它表示通过捕获代码路径标记其时间戳的任何部分看到数据包的时间,这近似于数据包到达的时间机器捕获它。它是一个UN * X时间戳,所以tv_sec是自1970年1月1日UTC 00:00:00以来的秒数,tv_usec也是自该秒以来的微秒数。