如何从头开始编写pcap文件,去除libpcap函数?

时间:2015-11-04 13:04:45

标签: c pcap libpcap

我已经使用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*)&ethernet);
  pcap_close(pd);
  pcap_dump_close(pdumper);
  return 0;
}

但是我想尝试不使用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 *),只是打开文件并在其中写入标题(如果我们不关心错误处理)。顺便说一句,似乎它的贡献" p-> tzoff"作为sf_write_header的参数,它尚未在我的代码中初始化(并且它仍在工作)。 关于linktype,在我们的例子中它只等于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*)&ethernet, sizeof(struct ethernet), 1, fd);
close(fd);

不需要使用pcap_t结构,我将snaplen和linktype值直接放在pcap_file_header结构中。

然后我以与pcap函数相同的方式使用fwrite。

头文件很好,如果我只是在文件中写标题,我可以用wireshark打开文件。 但当我添加最后一个fwrite(写入数据包头和数据包)时,wireshark告诉我:

The capture file appears to be damaged or corrupt.
(pcap: File has 4195245-byte packet, bigger than maximum of 65535)

我无法找到我的错误,而且我不知道他在哪里看到那么多字节。

修改

我没有使用未初始化的时间段,而是:

packet_header.ts = (struct timeval){0};

现在它正在工作,但是你怎么解释它在使用pcap功能时有效? " TS"还是没有初始化。

这个时间段的含义是什么?将它设置为零是否有意义?

1 个答案:

答案 0 :(得分:4)

  

struct pcap_pkthdr packet_header;

这是提供给程序的数据包标题的格式。 必然是包头的格式,因为它存储在文件中;它包含struct timeval,其大小根据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) */

};

并改为使用struct pcap_sf_pkthdr。将struct pcap_pkthdr结构写入文件将在tv_sec的{​​{1}}或tv_usec字段不是32位的任何系统上生成无效的pcap文件;任何64位系统都可能出现这种情况。在这种情况下,你可能会遇到像#34;损坏或损坏的错误。你看到的错误。

关于时间戳的含义是什么,在实际捕获中它表示数据包被捕获代码路径的任何部分看到时间的时间,这是时间的近似值。数据包到达捕获它的机器。它是UN * X时间戳,因此struct timeval是自1970年1月1日00:00:00 UTC以来的秒数,tv_sec是自该秒以来的微秒数。