Commit | Line | Data |
---|---|---|
1d110d20 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 | ||
9a2428f9 CH |
21 | #include <fstream> |
22 | #include <ios> | |
1d110d20 | 23 | #include <logfunc.hpp> |
9a2428f9 | 24 | #include <boost/foreach.hpp> |
1d110d20 | 25 | #include <boost/program_options.hpp> |
9a2428f9 | 26 | #include <boost/asio/ip/icmp.hpp> |
1d110d20 CH |
27 | |
28 | #include "icmp/icmppacketfactory.h" | |
29 | #include "tcp/tcpsegmentfactory.h" | |
688d4b27 | 30 | #include "tools/pcap.h" |
1d110d20 CH |
31 | |
32 | using I2n::Logger::GlobalLogger; | |
33 | namespace po = boost::program_options; | |
34 | ||
9a2428f9 CH |
35 | |
36 | //------------------------------------------------------------------------------ | |
37 | // constants | |
1d110d20 CH |
38 | const bool default_is_icmp = true; |
39 | const bool default_is_v4 = true; | |
40 | ||
9a2428f9 CH |
41 | //------------------------------------------------------------------------------ |
42 | // function declarations | |
43 | void init_logger(); | |
44 | void increase_verbosity(); | |
6d80c0be | 45 | int read_packets(std::istream &input_stream, const bool, const bool); |
9a2428f9 CH |
46 | |
47 | //------------------------------------------------------------------------------ | |
48 | // helper functions | |
49 | ||
1d110d20 CH |
50 | void init_logger() |
51 | { | |
9a2428f9 | 52 | // set default: log at level NOTICE to stderr |
1d110d20 | 53 | I2n::Logger::enable_stderr_log( true ); |
6d80c0be | 54 | I2n::Logger::set_log_level( I2n::Logger::LogLevel::Debug ); |
9a2428f9 | 55 | GlobalLogger.info() << "Logger initiated"; |
1d110d20 CH |
56 | } |
57 | ||
58 | void increase_verbosity() | |
59 | { | |
0caefeeb | 60 | I2n::Logger::set_log_level( I2n::Logger::LogLevel::Debug ); |
9a2428f9 | 61 | GlobalLogger.info() << "Increased verbosity"; |
1d110d20 CH |
62 | } |
63 | ||
cc59e6ff CH |
64 | /** |
65 | * @brief read packets from given input stream | |
66 | * | |
67 | * @returns positive error code or negated number of packets created | |
68 | */ | |
9a2428f9 | 69 | int read_packets( std::istream &input_stream, const bool is_icmp, |
ed614187 | 70 | const bool is_v4) |
9a2428f9 CH |
71 | { |
72 | // peek at start of stream to see if there is a pcap header | |
73 | bool is_pcap = check_for_pcap_header(input_stream); | |
688d4b27 | 74 | if (is_pcap) |
6d80c0be CH |
75 | GlobalLogger.info() << "File is pcap --> consume first " |
76 | << pcap_file_header_size << " bytes"; | |
688d4b27 CH |
77 | else |
78 | GlobalLogger.info() << "File is not pcap"; | |
79 | ||
9a2428f9 | 80 | int next_val; |
cc59e6ff | 81 | int packet_count = 0; |
688d4b27 | 82 | uint32_t packet_type = 0; |
9a2428f9 | 83 | if (is_pcap) |
688d4b27 CH |
84 | { |
85 | packet_type = consume_pcap_file_header(input_stream); | |
86 | GlobalLogger.debug() << "Packet type from header is " << packet_type; | |
87 | } | |
9a2428f9 CH |
88 | if ( !input_stream ) |
89 | { | |
90 | GlobalLogger.notice() << "Failure consuming pcap file header!"; | |
0caefeeb | 91 | return 3; |
9a2428f9 CH |
92 | } |
93 | ||
94 | // read from stream until it is empty | |
95 | while (true) | |
96 | { | |
97 | if (is_pcap) | |
98 | { | |
99 | // assume that there is a packet header if stream had pcap header | |
6d80c0be CH |
100 | GlobalLogger.debug() << "Consume packet header (" |
101 | << pcap_packet_header_size << " bytes)"; | |
9a2428f9 CH |
102 | consume_pcap_packet_header(input_stream); |
103 | if ( !input_stream ) | |
104 | { | |
105 | GlobalLogger.notice() <<"Failure consuming pcap packet header!"; | |
0caefeeb | 106 | return 4; |
9a2428f9 | 107 | } |
688d4b27 CH |
108 | |
109 | if (packet_type == 1) | |
110 | { | |
6d80c0be CH |
111 | GlobalLogger.debug() << "Consume ethernet header (" |
112 | << pcap_ethernet_header_size << " bytes)"; | |
688d4b27 CH |
113 | consume_pcap_ethernet_header(input_stream); |
114 | if ( !input_stream ) | |
115 | { | |
116 | GlobalLogger.notice() <<"Failure consuming pcap packet header!"; | |
117 | return 5; | |
118 | } | |
119 | } | |
9a2428f9 | 120 | } |
1d110d20 | 121 | |
9a2428f9 CH |
122 | // feed data to right factory |
123 | if (is_icmp) | |
124 | { | |
125 | IcmpPacketItem packet; | |
126 | if (is_v4) | |
127 | { | |
128 | GlobalLogger.info() << "Trying to read ICMP v4 packet" | |
129 | << std::endl; | |
130 | packet = IcmpPacketFactory::create_icmp_packet( | |
ed614187 | 131 | boost::asio::ip::icmp::v4(), input_stream); |
9a2428f9 CH |
132 | } |
133 | else // v6 | |
134 | { | |
135 | GlobalLogger.info() << "Trying to read ICMP v6 packet" | |
136 | << std::endl; | |
137 | packet = IcmpPacketFactory::create_icmp_packet( | |
ed614187 | 138 | boost::asio::ip::icmp::v6(), input_stream); |
9a2428f9 CH |
139 | } |
140 | ||
141 | if (packet) | |
cc59e6ff | 142 | { |
9a2428f9 | 143 | GlobalLogger.notice() << "Succesfully created ICMP packet"; |
cc59e6ff CH |
144 | GlobalLogger.info() << packet->to_string(); |
145 | } | |
9a2428f9 CH |
146 | else |
147 | { | |
148 | GlobalLogger.notice() << "ICMP packet creation failed"; | |
688d4b27 | 149 | return 6; |
9a2428f9 CH |
150 | } |
151 | } | |
152 | else // is tcp | |
153 | { | |
154 | TcpSegmentItem segment; | |
155 | if (is_v4) | |
156 | { | |
157 | GlobalLogger.info() << "Trying to read TCP v4 packet" | |
158 | << std::endl; | |
159 | segment = TcpSegmentFactory::create_tcp_segment( | |
160 | boost::asio::ip::tcp_raw_protocol::v4(), | |
161 | input_stream); | |
162 | } | |
163 | else // v6 | |
164 | { | |
165 | GlobalLogger.info() << "Trying to read TCP v6 packet" | |
166 | << std::endl; | |
167 | segment = TcpSegmentFactory::create_tcp_segment( | |
168 | boost::asio::ip::tcp_raw_protocol::v6(), | |
169 | input_stream); | |
170 | } | |
171 | ||
172 | if (segment) | |
173 | GlobalLogger.notice() << "Succesfully created TCP segment"; | |
174 | else | |
175 | { | |
176 | GlobalLogger.notice() << "TCP segment creation failed"; | |
688d4b27 | 177 | return 6; |
9a2428f9 CH |
178 | } |
179 | } | |
180 | ||
181 | if ( !input_stream ) | |
182 | { | |
183 | GlobalLogger.notice() << "Stream not good after reading!"; | |
688d4b27 | 184 | return 7; |
9a2428f9 CH |
185 | } |
186 | ||
cc59e6ff CH |
187 | // if reached this point, created a packet, otherwise will have |
188 | // returned with error code | |
189 | ++packet_count; | |
190 | ||
9a2428f9 CH |
191 | // peek 1 byte to check whether we are at the end of stream |
192 | next_val = input_stream.get(); | |
193 | if ( input_stream.eof() ) | |
194 | { | |
195 | GlobalLogger.info() << "Reached end of stream"; | |
196 | break; | |
197 | } | |
688d4b27 CH |
198 | GlobalLogger.debug() << "Stream continues with value " << std::showbase |
199 | << std::hex << next_val; | |
200 | ||
201 | if (is_pcap && packet_type == 1 && next_val == 0) | |
202 | { | |
203 | GlobalLogger.debug() << "Consume 0s added for alignment"; | |
204 | while (input_stream.good() && next_val == 0) | |
205 | next_val = input_stream.get(); | |
206 | ||
207 | // if stream is still good, then got a non-0 value from it | |
208 | // --> put it back | |
209 | if (input_stream.good()) | |
210 | input_stream.unget(); | |
211 | else | |
212 | { | |
213 | GlobalLogger.info() << "Reached end of stream"; | |
214 | break; | |
215 | } | |
216 | } | |
217 | else | |
218 | input_stream.unget(); | |
9a2428f9 CH |
219 | } //eo: while (input_stream) |
220 | ||
cc59e6ff | 221 | return (-1) * packet_count; |
9a2428f9 CH |
222 | } // eo: function read_packets |
223 | ||
224 | //------------------------------------------------------------------------------ | |
225 | /** @brief main function | |
226 | * | |
227 | * @returns 0 if all input resulted in good packets or the error number of the | |
228 | * last failed packet | |
229 | */ | |
1d110d20 CH |
230 | int main(int argc, char *argv[]) |
231 | { | |
232 | // init logging | |
233 | init_logger(); | |
1d110d20 CH |
234 | |
235 | bool is_icmp = default_is_icmp; | |
236 | bool is_v4 = default_is_v4; | |
cc59e6ff CH |
237 | int current_return, return_val = 0; |
238 | int packet_count_good = 0; | |
239 | int packet_count_bad = 0; | |
ed614187 | 240 | DumpMode dump_mode = DUMP_NEVER; |
1d110d20 | 241 | |
9a2428f9 CH |
242 | if (argc == 1) |
243 | { | |
244 | GlobalLogger.notice() << "No arguments! Start with mix of file names " | |
245 | << "and flags"; | |
246 | GlobalLogger.notice() << "Valid flags: -i[cmp], -t[cp], -[v]4 -[v]6; " | |
247 | << "-- to read from stdin instead of file"; | |
248 | return 1; | |
249 | } | |
1d110d20 | 250 | |
ed614187 CH |
251 | IcmpPacketFactory::PacketDumpMode = dump_mode; |
252 | ||
9a2428f9 CH |
253 | // convert arguments to vector of strings and loop over them |
254 | std::vector<std::string> args(argv+1, argv + argc); | |
1d110d20 CH |
255 | BOOST_FOREACH (const std::string &arg, args) |
256 | { | |
9a2428f9 | 257 | GlobalLogger.debug() << "Parsing next arg: " << arg; |
cc59e6ff | 258 | current_return = 0; |
9a2428f9 | 259 | |
1d110d20 CH |
260 | // check if is some specification of data format |
261 | if (arg == "-i" || arg == "-icmp" || arg == "i" || arg == "icmp") | |
262 | is_icmp = true; | |
263 | else if (arg == "-t" || arg == "-tcp" || arg == "t" || arg == "tcp") | |
264 | is_icmp = false; | |
265 | else if (arg == "-4" || arg == "-v4" || arg == "4" || arg == "v4") | |
9a2428f9 | 266 | is_v4 = true; |
1d110d20 | 267 | else if (arg == "-6" || arg == "-v6" || arg == "6" || arg == "v6") |
9a2428f9 CH |
268 | is_v4 = false; |
269 | else if (arg == "-v") | |
270 | increase_verbosity(); | |
1d110d20 CH |
271 | else if (arg == "--") // read input from stdin |
272 | { | |
1d110d20 | 273 | GlobalLogger.info() << "Trying to read from stdin" << std::endl; |
ed614187 | 274 | current_return = read_packets(std::cin, is_icmp, is_v4); |
1d110d20 CH |
275 | } |
276 | else // assume is file name | |
277 | { | |
9a2428f9 | 278 | GlobalLogger.info() << "Trying to read from " << arg |
1d110d20 | 279 | << std::endl; |
9a2428f9 CH |
280 | std::ifstream file_stream(arg.c_str(), std::ios::in | |
281 | std::ios::binary); | |
0caefeeb CH |
282 | if ( !file_stream ) |
283 | { | |
284 | GlobalLogger.notice() << "Failed to open file " << arg | |
285 | << " for reading!"; | |
cc59e6ff | 286 | current_return = 2; |
0caefeeb CH |
287 | } |
288 | else | |
289 | { | |
ed614187 | 290 | current_return = read_packets( file_stream, is_icmp, is_v4); |
0caefeeb CH |
291 | file_stream.close(); |
292 | } | |
1d110d20 CH |
293 | } |
294 | ||
cc59e6ff | 295 | if (current_return > 0) |
9a2428f9 | 296 | { |
cc59e6ff CH |
297 | GlobalLogger.debug() << "Remember error value " << current_return; |
298 | return_val = current_return; | |
299 | ++packet_count_bad; | |
9a2428f9 | 300 | } |
cc59e6ff CH |
301 | else // returned the number of packets created * (-1) |
302 | packet_count_good -= current_return; | |
9a2428f9 | 303 | } //eo: loop over input-files |
1d110d20 | 304 | |
cc59e6ff CH |
305 | GlobalLogger.notice() << "Created (at least) " << packet_count_good |
306 | << " packets successfully and failed for " << packet_count_bad; | |
307 | // ("at least" because if we get an error code from read_packets, then | |
308 | // there might have been successfull reads earlier in same stream) | |
309 | ||
9a2428f9 CH |
310 | GlobalLogger.debug() << "End program with return value " << return_val; |
311 | return return_val; | |
1d110d20 | 312 | |
1d110d20 | 313 | } // eo: function main |
9a2428f9 | 314 |