C – 将结构写入文件(.pcap)

我正在尝试编写.pcap文件,这可以在Wireshark中使用。 为了做到这一点,我有几个结构,我需要写入文件的各种数据类型。 (见代码)

所以,我创建结构实例,填写数据,使用FILE * fp = fopen(“test.pcap”,“w”),然后我不确定如何正确地将它写入文件。 我相信我应该使用memcpy,但我不确定最好的方法。 我过去主要使用C ++库来执行此操作。 有什么建议?

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; 

使用fwrite() 。 您需要检查此信息,但我认为.pcap文件是以二进制模式编写的。

例:

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

使用libpcap或WinPcap – pcap_open_dead()获取“伪” pcap_tpcap_dump_open()一起使用以指定链路层头类型(对于以太网,使用DLT_EN10MB )和快照长度(使用65535), pcap_dump_open()打开用于写入的文件,用于写出数据包的pcap_dump_close()用于关闭文件的pcap_dump_close() 。 比直接使用fopen()fwrite()fclose() (这是libpcap / WinPcap在“引擎盖下”使用fopen()更容易。

并且,是的,您必须使数据包中的字节顺序正确。 字节顺序取决于协议; 对于以太网报头中的type字段,以及IP,TCP和UDP报头中的所有多字节字段,它们必须采用大端顺序。 (pcap文件中的幻数与此无关 – 它仅指示文件头和每个数据包记录头中字段的字节顺序,而不是数据包中字段的字节顺序,以及到期对于它在Linux中实现的方式,Linux USB中数据包开始时的元数据捕获。数据包数据应该与“在线”完全一样。)

这是我对Guy Harris所暗示的理解。 因此,根据Kyslik的要求,我们有:

 #include  /* 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; }