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, | |
d291ad16 | 32 | std::ostream &os, |
688d4b27 CH |
33 | const time_t &capture_time) |
34 | { | |
35 | std::size_t data_size = data.size(); | |
36 | ||
37 | // create a pcap header | |
d291ad16 CH |
38 | pcapfile_hdr_t pcapfile_hdr; |
39 | pcapfile_hdr.magic_number = 0xa1b2c3d4; | |
40 | pcapfile_hdr.version_major = 2; | |
41 | pcapfile_hdr.version_minor = 4; | |
42 | pcapfile_hdr.thiszone = 0; | |
43 | pcapfile_hdr.sigfigs = 0; | |
44 | pcapfile_hdr.snaplen = data_size; | |
45 | pcapfile_hdr.network = 101; // LINKTYPE_RAW, according to | |
688d4b27 CH |
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 | |
d291ad16 CH |
56 | os.write( (char *)&pcapfile_hdr, sizeof(pcapfile_hdr_t) ); |
57 | os.write( (char *)&pcaprec_hdr, sizeof( pcaprec_hdr_t) ); | |
58 | os << data; | |
688d4b27 CH |
59 | } |
60 | ||
61 | //const uint32_t pcap_magic_number = 0xa1b2c3d4; | |
62 | const uint8_t pcap_magic_bytes[] = {0xa1, 0xb2, 0xc3, 0xd4}; | |
63 | ||
688d4b27 CH |
64 | // determine whether is raw data or pcap by peeking at first 4 bytes |
65 | bool check_for_pcap_header(std::istream &input_stream) | |
66 | { | |
67 | int peek_idx; | |
68 | bool is_pcap = true; | |
69 | for (peek_idx=0; peek_idx<4; ++peek_idx) | |
70 | { | |
71 | int val = input_stream.get(); | |
72 | //GlobalLogger.debug() << "Peeked value " << std::hex << val; | |
73 | if (val != pcap_magic_bytes[3-peek_idx]) | |
74 | { | |
75 | is_pcap = false; | |
76 | break; | |
77 | } | |
78 | } | |
79 | for (int back_idx=peek_idx; back_idx > 0; --back_idx) | |
80 | input_stream.unget(); | |
81 | return is_pcap; | |
82 | } | |
83 | ||
84 | uint32_t consume_pcap_file_header(std::istream &input_stream) | |
85 | { | |
86 | char *buf = new char[pcap_file_header_size]; | |
87 | input_stream.read(buf, pcap_file_header_size); | |
88 | ||
89 | // interpret as pcap header | |
90 | pcapfile_hdr_t *header = (pcapfile_hdr_t*) reinterpret_cast<uint8_t*>(buf); | |
91 | // could do some checking whether this data actually looks like a valid | |
92 | // pcap header | |
93 | ||
94 | uint32_t result = header->network; | |
95 | delete[] buf; | |
96 | return result; | |
97 | } | |
98 | ||
99 | void consume_pcap_packet_header(std::istream &input_stream) | |
100 | { | |
101 | char *buf = new char[pcap_packet_header_size]; | |
102 | input_stream.read(buf, pcap_packet_header_size); | |
103 | // could do some checking whether this data actually looks like a | |
104 | // pcap header --> see ../icmp/icmppacketfactory.cpp | |
105 | delete[] buf; | |
106 | } | |
107 | ||
108 | ||
109 | void consume_pcap_ethernet_header(std::istream &input_stream) | |
110 | { | |
111 | char *buf = new char[pcap_ethernet_header_size]; | |
112 | input_stream.read(buf, pcap_ethernet_header_size); | |
113 | // could do some checking whether this data actually looks like a | |
114 | // pcap header --> see ../icmp/icmppacketfactory.cpp | |
115 | delete[] buf; | |
116 | } | |
117 | ||
118 | bool consume_single_packet_pcap(std::istream &input_stream) | |
119 | { | |
120 | bool is_pcap = check_for_pcap_header(input_stream); | |
121 | if (!is_pcap) | |
122 | return false; | |
123 | ||
124 | uint32_t packet_type = consume_pcap_file_header(input_stream); | |
125 | consume_pcap_packet_header(input_stream); | |
126 | if (packet_type == 1) | |
127 | consume_pcap_ethernet_header(input_stream); | |
128 | ||
129 | return true; | |
130 | } | |
131 | ||
132 | ||
133 | #pragma pack(pop) // restore old value | |
134 |