问题
I am trying to write a .pcap file, which is something that can be used in Wireshark. In order to do that, I have a couple of structs with various data types I need to write to a file. (see code)
So, I create the struct instances, fill in the data, use FILE* fp = fopen("test.pcap","w"), and then I'm unsure how to properly write it to the file. I believe I should use memcpy but I'm not sure of the best way to do it. I have mostly resorted to C++ libraries in the past to do this. Any suggestions?
typedef struct pcap_hdr_s {
uint32_t magic_number; /* magic number */
uint16_t version_major; /* major version number */
uint16_t version_minor; /* minor version number */
int32_t thiszone; /* GMT to local correction */
uint32_t sigfigs; /* accuracy of timestamps */
uint32_t snaplen; /* max length of captured packets, in octets */
uint32_t network; /* data link type */
} pcap_hdr_t;
typedef struct pcaprec_hdr_s {
uint32_t ts_sec; /* timestamp seconds */
uint32_t ts_usec; /* timestamp microseconds */
uint32_t incl_len; /* number of octets of packet saved in file */
uint32_t orig_len; /* actual length of packet */
} pcaprec_hdr_t;
typedef struct ethernet_hdr_s {
uint8_t dst[6]; /* destination host address */
uint8_t src[6]; /* source host address */
uint16_t type; /* IP? ARP? RARP? etc */
} ethernet_hdr_t;
typedef struct ip_hdr_s {
uint8_t ip_hl:4, /* both fields are 4 bits */
ip_v:4;
uint8_t ip_tos;
uint16_t ip_len;
uint16_t ip_id;
uint16_t ip_off;
uint8_t ip_ttl;
uint8_t ip_p;
uint16_t ip_sum;
uint32_t ip_src;
uint32_t ip_dst;
}ip_hdr_t;
typedef struct udp_header
{
uint16_t src;
uint16_t dst;
uint16_t length;
uint16_t checksum;
} udp_header_t;
回答1:
Use fwrite(). You need to check this info but I think .pcap files are written in binary mode.
Example:
pcaprec_hdr_t pcaprec_hdr;
// fill pcaprec_hdr with valid info
FILE* pFile = NULL;
pFile = fopen ("myfile.pcap" , "wb"); // open for writing in binary mode
fwrite (&pcaprec_hdr, 1, sizeof(pcaprec_hdr_t) , pFile);
fclose(pFile);
回答2:
Use libpcap or WinPcap - pcap_open_dead()
to get a "fake" pcap_t
to use with pcap_dump_open()
to specify the link-layer header type (for Ethernet, use DLT_EN10MB
) and snapshot length (use 65535), pcap_dump_open()
to open the file for writing, pcap_dump()
to write out a packet, and pcap_dump_close()
to close the file. MUCH easier than directly using fopen()
, fwrite()
, and fclose()
(which are what libpcap/WinPcap use "under the hood").
And, yes, you have to get the byte order in the packets correct. The byte order depends on the protocol; for the type
field in the Ethernet header, and for all multi-byte fields in IP, TCP, and UDP headers, they have to be in big-endian order. (The magic number in the pcap file is irrelevant to this - it only indicates the byte order of the fields in the file header and the per-packet record header, NOT the byte order of the fields in the packet, as well as, due to the way it's implemented in Linux, the meta-data at the beginning of packets in Linux USB captures. The packet data is supposed to look exactly as it would "on the wire".)
回答3:
Here's my understanding of what Guy Harris is suggesting. So, as per Kyslik's request, we have:
#include <libpcap/pcap.h>
/* Ethernet/IP/SCTP INIT chunk */
static const unsigned char pkt1[82] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00, /* ......E. */
0x00, 0x44, 0x55, 0xb1, 0x00, 0x00, 0x40, 0x84, /* .DU...@. */
0x26, 0x83, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, /* &....... */
0x00, 0x01, 0x00, 0x01, 0x1f, 0x90, 0x00, 0x00, /* ........ */
0x00, 0x00, 0x68, 0xe5, 0x88, 0x1b, 0x01, 0x00, /* ..h..... */
0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, /* .$...... */
0xa0, 0x00, 0x00, 0x04, 0xff, 0xff, 0x00, 0x00, /* ........ */
0x16, 0x2e, 0x80, 0x00, 0x00, 0x04, 0xc0, 0x00, /* ........ */
0x00, 0x04, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x05, /* ........ */
0x00, 0x00 /* .. */
};
int main(int argc, char *argv[]) {
pcap_t *handle = pcap_open_dead(DLT_EN10MB, 1 << 16);
pcap_dumper_t *dumper = pcap_dump_open(handle, "/tmp/pktcap/cap.pcap");
struct pcap_pkthdr pcap_hdr;
pcap_hdr.caplen = sizeof(pkt1);
pcap_hdr.len = pcap_hdr.caplen;
pcap_dump((u_char *)dumper, &pcap_hdr, pkt1);
pcap_dump_close(dumper);
return 0;
}
来源:https://stackoverflow.com/questions/7309773/c-writing-structs-to-a-file-pcap