How to write pcap file from scratch, decorticating libpcap functions?

给你一囗甜甜゛ 提交于 2020-12-30 04:49:06

问题


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;
}

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

Here are the sources I found:

pcap_open_dead function: http://www.wand.net.nz/trac/libtrace/browser/lib/pcap_open_dead.c?rev=808a478a2459f3cf0e8bf927fcaad371138efb20

pcap_dump_open, pcap_dump and others: http://www.opensource.apple.com/source/libpcap/libpcap-2.1/libpcap/savefile.c

So, here is my thought:

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.

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.

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.

So here is what I did:

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);

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

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

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.

EDIT

Instead of using an uninitialized timeval, I did :

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

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

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

EDIT: corrected magic number to 0xa1b2c3d4


回答1:


struct pcap_pkthdr packet_header;

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.

What you need is:

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) */

};

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.

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.



来源:https://stackoverflow.com/questions/33522705/how-to-write-pcap-file-from-scratch-decorticating-libpcap-functions

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!