extended ICMP packet dumping to parts after packet creation
[pingcheck] / src / tools / feed_packet_data.cpp
CommitLineData
1d110d20
CH
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on 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
32using I2n::Logger::GlobalLogger;
33namespace po = boost::program_options;
34
9a2428f9
CH
35
36//------------------------------------------------------------------------------
37// constants
1d110d20
CH
38const bool default_is_icmp = true;
39const bool default_is_v4 = true;
40
9a2428f9
CH
41//------------------------------------------------------------------------------
42// function declarations
43void init_logger();
44void increase_verbosity();
6d80c0be 45int read_packets(std::istream &input_stream, const bool, const bool);
9a2428f9
CH
46
47//------------------------------------------------------------------------------
48// helper functions
49
1d110d20
CH
50void 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
58void 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 69int 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
230int 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