/* The software in this package is distributed under the GNU General Public License version 2 (with a special exception described below). A copy of GNU General Public License (GPL) is included in this distribution, in the file COPYING.GPL. As a special exception, if other files instantiate templates or use macros or inline functions from this file, or you compile this file and link it with other works to produce a work based on this file, this file does not by itself cause the resulting work to be covered by the GNU General Public License. However the source code for this file must still be made available in accordance with section (3) of the GNU General Public License. This exception does not invalidate any other reasons why a work based on this file might be covered by the GNU General Public License. Christian Herdtweck, Intra2net AG 2015 */ #include "tools/pcap.h" #include //----------------------------------------------------------------------------- // Dump of data packets to pcap files //----------------------------------------------------------------------------- #pragma pack(push, 1) // exact fit -- no padding of data in structs void write_pcap_packet_data(const std::string &data, std::ostream &os, const time_t &capture_time) { std::size_t data_size = data.size(); // create a pcap header pcapfile_hdr_t pcapfile_hdr; pcapfile_hdr.magic_number = 0xa1b2c3d4; pcapfile_hdr.version_major = 2; pcapfile_hdr.version_minor = 4; pcapfile_hdr.thiszone = 0; pcapfile_hdr.sigfigs = 0; pcapfile_hdr.snaplen = data_size; pcapfile_hdr.network = 101; // LINKTYPE_RAW, according to // http://www.tcpdump.org/linktypes.html // create a record (packet) header pcaprec_hdr_t pcaprec_hdr; pcaprec_hdr.ts_sec = static_cast(capture_time); pcaprec_hdr.ts_usec = 0; // do not care about that precision pcaprec_hdr.incl_len = data_size; pcaprec_hdr.orig_len = data_size; // write data os.write( (char *)&pcapfile_hdr, sizeof(pcapfile_hdr_t) ); os.write( (char *)&pcaprec_hdr, sizeof( pcaprec_hdr_t) ); os << data; } //const uint32_t pcap_magic_number = 0xa1b2c3d4; const uint8_t pcap_magic_bytes[] = {0xa1, 0xb2, 0xc3, 0xd4}; // determine whether is raw data or pcap by peeking at first 4 bytes bool check_for_pcap_header(std::istream &input_stream) { int peek_idx; bool is_pcap = true; for (peek_idx=0; peek_idx<4; ++peek_idx) { int val = input_stream.get(); //GlobalLogger.debug() << "Peeked value " << std::hex << val; if (val != pcap_magic_bytes[3-peek_idx]) { is_pcap = false; break; } } for (int back_idx=peek_idx; back_idx > 0; --back_idx) input_stream.unget(); return is_pcap; } uint32_t consume_pcap_file_header(std::istream &input_stream) { char *buf = new char[pcap_file_header_size]; input_stream.read(buf, pcap_file_header_size); // interpret as pcap header pcapfile_hdr_t *header = (pcapfile_hdr_t*) reinterpret_cast(buf); // could do some checking whether this data actually looks like a valid // pcap header uint32_t result = header->network; delete[] buf; return result; } void consume_pcap_packet_header(std::istream &input_stream) { char *buf = new char[pcap_packet_header_size]; input_stream.read(buf, pcap_packet_header_size); // could do some checking whether this data actually looks like a // pcap header --> see ../icmp/icmppacketfactory.cpp delete[] buf; } void consume_pcap_ethernet_header(std::istream &input_stream) { char *buf = new char[pcap_ethernet_header_size]; input_stream.read(buf, pcap_ethernet_header_size); // could do some checking whether this data actually looks like a // pcap header --> see ../icmp/icmppacketfactory.cpp delete[] buf; } bool consume_single_packet_pcap(std::istream &input_stream) { bool is_pcap = check_for_pcap_header(input_stream); if (!is_pcap) return false; uint32_t packet_type = consume_pcap_file_header(input_stream); consume_pcap_packet_header(input_stream); if (packet_type == 1) consume_pcap_ethernet_header(input_stream); return true; } #pragma pack(pop) // restore old value