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*)ðernet);
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*)ðernet, 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
ts
is uninitialized. Perhaps it's unintentionally set to 0xffffffff which is also in the wrong place in your structure. – Jonathon Reinhart