Commit | Line | Data |
---|---|---|
688d4b27 CH |
1 | /* |
2 | The software in this package is distributed under the GNU General | |
3 | Public License version 2 (with a special exception described below). | |
4 | ||
5 | A copy of GNU General Public License (GPL) is included in this distribution, | |
6 | in the file COPYING.GPL. | |
7 | ||
8 | As a special exception, if other files instantiate templates or use macros | |
9 | or inline functions from this file, or you compile this file and link it | |
10 | with other works to produce a work based on this file, this file | |
11 | does not by itself cause the resulting work to be covered | |
12 | by the GNU General Public License. | |
13 | ||
14 | However the source code for this file must still be made available | |
15 | in accordance with section (3) of the GNU General Public License. | |
16 | ||
17 | This exception does not invalidate any other reasons why a work based | |
18 | on this file might be covered by the GNU General Public License. | |
19 | ||
20 | Christian Herdtweck, Intra2net AG 2015 | |
21 | */ | |
22 | ||
23 | #include "tools/pcap.h" | |
24 | #include <cstdio> | |
25 | ||
26 | //----------------------------------------------------------------------------- | |
27 | // Dump of data packets to pcap files | |
28 | //----------------------------------------------------------------------------- | |
29 | #pragma pack(push, 1) // exact fit -- no padding of data in structs | |
30 | ||
31 | void write_pcap_packet_data(const std::string &data, | |
32 | FILE *fp, | |
33 | const time_t &capture_time) | |
34 | { | |
35 | std::size_t data_size = data.size(); | |
36 | ||
37 | // create a pcap header | |
38 | pcapfile_hdr_t pcap_hdr; | |
39 | pcap_hdr.magic_number = 0xa1b2c3d4; | |
40 | pcap_hdr.version_major = 2; | |
41 | pcap_hdr.version_minor = 4; | |
42 | pcap_hdr.thiszone = 0; | |
43 | pcap_hdr.sigfigs = 0; | |
44 | pcap_hdr.snaplen = data_size; | |
45 | pcap_hdr.network = 101; // LINKTYPE_RAW, according to | |
46 | // http://www.tcpdump.org/linktypes.html | |
47 | ||
48 | // create a record (packet) header | |
49 | pcaprec_hdr_t pcaprec_hdr; | |
50 | pcaprec_hdr.ts_sec = static_cast<uint32_t>(capture_time); | |
51 | pcaprec_hdr.ts_usec = 0; // do not care about that precision | |
52 | pcaprec_hdr.incl_len = data_size; | |
53 | pcaprec_hdr.orig_len = data_size; | |
54 | ||
55 | // write data | |
56 | fwrite(&pcap_hdr, sizeof(pcapfile_hdr_t), 1, fp); | |
57 | fwrite(&pcaprec_hdr, sizeof(pcaprec_hdr_t), 1, fp); | |
58 | fwrite(data.c_str(), sizeof(char), data_size, fp); | |
59 | } | |
60 | ||
61 | //const uint32_t pcap_magic_number = 0xa1b2c3d4; | |
62 | const uint8_t pcap_magic_bytes[] = {0xa1, 0xb2, 0xc3, 0xd4}; | |
63 | ||
64 | // pcap file header is 5 x uint32 + 2 x uint16 --> 24 bytes | |
65 | const std::streamsize pcap_file_header_size = sizeof(pcapfile_hdr_t); | |
66 | ||
67 | // pcap file header is 4 x uint32 --> 16 bytes | |
68 | const std::streamsize pcap_packet_header_size = sizeof(pcaprec_hdr_t); | |
69 | ||
70 | // pcap ethernet header is 2 x 6 byte + 2 byte --> 14 bytes | |
71 | const std::streamsize pcap_ethernet_header_size = sizeof(pcapeth_hdr_t); | |
72 | ||
73 | // determine whether is raw data or pcap by peeking at first 4 bytes | |
74 | bool check_for_pcap_header(std::istream &input_stream) | |
75 | { | |
76 | int peek_idx; | |
77 | bool is_pcap = true; | |
78 | for (peek_idx=0; peek_idx<4; ++peek_idx) | |
79 | { | |
80 | int val = input_stream.get(); | |
81 | //GlobalLogger.debug() << "Peeked value " << std::hex << val; | |
82 | if (val != pcap_magic_bytes[3-peek_idx]) | |
83 | { | |
84 | is_pcap = false; | |
85 | break; | |
86 | } | |
87 | } | |
88 | for (int back_idx=peek_idx; back_idx > 0; --back_idx) | |
89 | input_stream.unget(); | |
90 | return is_pcap; | |
91 | } | |
92 | ||
93 | uint32_t consume_pcap_file_header(std::istream &input_stream) | |
94 | { | |
95 | char *buf = new char[pcap_file_header_size]; | |
96 | input_stream.read(buf, pcap_file_header_size); | |
97 | ||
98 | // interpret as pcap header | |
99 | pcapfile_hdr_t *header = (pcapfile_hdr_t*) reinterpret_cast<uint8_t*>(buf); | |
100 | // could do some checking whether this data actually looks like a valid | |
101 | // pcap header | |
102 | ||
103 | uint32_t result = header->network; | |
104 | delete[] buf; | |
105 | return result; | |
106 | } | |
107 | ||
108 | void consume_pcap_packet_header(std::istream &input_stream) | |
109 | { | |
110 | char *buf = new char[pcap_packet_header_size]; | |
111 | input_stream.read(buf, pcap_packet_header_size); | |
112 | // could do some checking whether this data actually looks like a | |
113 | // pcap header --> see ../icmp/icmppacketfactory.cpp | |
114 | delete[] buf; | |
115 | } | |
116 | ||
117 | ||
118 | void consume_pcap_ethernet_header(std::istream &input_stream) | |
119 | { | |
120 | char *buf = new char[pcap_ethernet_header_size]; | |
121 | input_stream.read(buf, pcap_ethernet_header_size); | |
122 | // could do some checking whether this data actually looks like a | |
123 | // pcap header --> see ../icmp/icmppacketfactory.cpp | |
124 | delete[] buf; | |
125 | } | |
126 | ||
127 | bool consume_single_packet_pcap(std::istream &input_stream) | |
128 | { | |
129 | bool is_pcap = check_for_pcap_header(input_stream); | |
130 | if (!is_pcap) | |
131 | return false; | |
132 | ||
133 | uint32_t packet_type = consume_pcap_file_header(input_stream); | |
134 | consume_pcap_packet_header(input_stream); | |
135 | if (packet_type == 1) | |
136 | consume_pcap_ethernet_header(input_stream); | |
137 | ||
138 | return true; | |
139 | } | |
140 | ||
141 | ||
142 | #pragma pack(pop) // restore old value | |
143 |