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