如何从头开始编写pcap文件,装饰libpcap函数? [英] How to write pcap file from scratch, decorticating libpcap functions?

查看:61
本文介绍了如何从头开始编写pcap文件,装饰libpcap函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个代码,它可以很好地用 libpcap 编写一个 pcap 文件(只有用于测试的以太网协议):

I've got this code which is working fine to write a pcap file (with just the Ethernet protocol for the test) with libpcap:

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 函数,所以我开始对上面使用的函数进行装饰.

But I wanted to try not using the pcap functions, so I started decorticating the functions used above.

以下是我找到的来源:

pcap_open_dead 函数:http://nofollowwww.wand.net.nz/trac/libtrace/browser/lib/pcap_open_dead.c?rev=808a478a2459f3cf0e8bf927fcaad371138efb20

pcap_open_dead function: 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_dump_open, pcap_dump and others: http://www.opensource.apple.com/source/libpcap/libpcap-2.1/libpcap/savefile.c

所以,这是我的想法:

pcap_open_dead 函数有点无用,只是实例化一个 pcap_t 结构(我不想在我的代码中使用它)并用参数填充它的值.

The pcap_open_dead function is kind of useless, just instanciating a pcap_t struct (which I don't want to use in my code) and filling its values with the parameters.

pcap_dump_open 返回一个 pcap_dumper_t(看起来就像一个 FILE*),它只是打开文件并在其中写入标头(如果我们不关心错误处理).顺便说一句,似乎它给了p->tzoff"作为 sf_write_header 的参数,它尚未在我的代码中初始化(并且仍在工作).关于链接类型,在我们的例子中它只是等于 1.

The pcap_dump_open, returning a pcap_dumper_t (which seems to be just like a FILE*), is just opening the file and writing the header in it (if we don't care about the errors handling). By the way, seems like its giving "p->tzoff" as parameter to sf_write_header, which has not been initialized in my code (and it's still working). About the linktype, in our case it's just equal to 1.

最后,pcap_dump 函数将 pcap_dumper_t 变量作为第一个参数,隐式转换为 u_char*,然后显式转换为 FILE*(为什么不从一开始就使用 FILE*?)然后把一个包头和一个包数据用fwrite写入文件.

Finally, the pcap_dump function take the pcap_dumper_t variable as first parameter, which is implicitly cast to u_char* then explicitly cast to FILE* (why not use a FILE* from the beginning?) Then it take a packet header and a packet data to write them into the file with fwrite.

这就是我所做的:

FILE *fd = fopen("test.pcap", "w");

struct pcap_file_header header;

header.magic = 0xa1b2c3d4;
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 结构中.

No need to use a pcap_t structure, I put the snaplen and linktype values directly in the pcap_file_header structure.

然后我像在 pcap 函数中一样使用 fwrite.

And then I use fwrite the same way they do in the pcap functions.

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

The header file is good, i'm able to open the file with wireshark if I just write the header in the file. But when I add the 2 last fwrite (to write the packet header and the packet), wireshark tells me:

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

我找不到我的错误在哪里,我也不知道他在哪里看到那么多字节.

I can't find where is my mistake, and I don't know where he's seeing that much bytes.

编辑

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

Instead of using an uninitialized timeval, I did :

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

现在它起作用了,但是您如何解释它在使用 pcap 函数时起作用了?ts"仍未初始化.

And now that's working, but how do you explain it was working when using the pcap functions? "ts" was still uninitialized.

这个timeval是什么意思?将其设置为零是否有意义?

And what's the meaning of this timeval? Does it make sense to set it to zero?

将幻数修正为 0xa1b2c3d4

corrected magic number to 0xa1b2c3d4

推荐答案

struct pcap_pkthdr packet_header;

这是提供给程序的数据包头的格式.它不一定是存储在文件中的数据包头的格式;它包含一个 struct timeval,其大小根据 time_t 是 32 位还是 64 位而不同.

That's the format of a packet header as it's provided to a program. It is not necessarily the format of a packet header as it's stored in the file; it contains a struct timeval, whose size differs depending on whether a time_t is 32 bits or 64 bits.

你需要的是:

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 结构写入文件将在任何系统上产生无效的 pcap 文件,其中 tv_sectv_usec 字段为 struct timeval 不是 32 位;在任何 64 位系统上都可能是这种情况.在这种情况下,您很可能会收到诸如损坏或损坏"错误之类的错误.

and use struct pcap_sf_pkthdr instead. Writing struct pcap_pkthdr structures to a file will produce invalid pcap files on any system where the tv_sec or tv_usec field of struct timeval isn't 32 bits; that will probably be the case on any 64-bit system. In that case, you may well get errors like the "damaged or corrupt" error you saw.

至于时间戳的含义是什么,在实际的捕获中,它表示捕获代码路径的任何部分看到数据包的时间,它是时间戳的近似值,它是时间的近似值数据包到达机器捕获它.这是一个 UN*X 时间戳,所以 tv_sec 是自 1970 年 1 月 1 日 00:00:00 UTC 以来的秒数,而 tv_usec 是自 1970 年 1 月 1 日以来的微秒数那一秒.

As for what the meaning of the time stamp is, in an actual capture it represents the time at which the packet was seen by whatever part of the capture code path time stamped it, which is an approximation to the time at which the packet arrived at the machine capturing it. It's a UN*X time stamp, so tv_sec is a count of seconds since January 1, 1970, 00:00:00 UTC, and tv_usec is a count of microseconds since that second.

这篇关于如何从头开始编写pcap文件,装饰libpcap函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆