2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
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.
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.
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.
23 #include <logfunc.hpp>
24 #include <boost/foreach.hpp>
25 #include <boost/program_options.hpp>
26 #include <boost/asio/ip/icmp.hpp>
28 #include "icmp/icmppacketfactory.h"
29 #include "tcp/tcpsegmentfactory.h"
30 #include "tools/pcap.h"
32 using I2n::Logger::GlobalLogger;
33 namespace po = boost::program_options;
36 //------------------------------------------------------------------------------
38 const bool default_is_icmp = true;
39 const bool default_is_v4 = true;
41 //------------------------------------------------------------------------------
42 // function declarations
44 void increase_verbosity();
45 int read_packets(std::istream &input_stream, const bool, const bool, const int);
47 //------------------------------------------------------------------------------
52 // set default: log at level NOTICE to stderr
53 I2n::Logger::enable_stderr_log( true );
54 I2n::Logger::set_log_level( I2n::Logger::LogLevel::Info );
55 GlobalLogger.info() << "Logger initiated";
58 void increase_verbosity()
60 I2n::Logger::set_log_level( I2n::Logger::LogLevel::Debug );
61 GlobalLogger.info() << "Increased verbosity";
65 * @brief read packets from given input stream
67 * @returns positive error code or negated number of packets created
69 int read_packets( std::istream &input_stream, const bool is_icmp,
73 // peek at start of stream to see if there is a pcap header
74 bool is_pcap = check_for_pcap_header(input_stream);
76 GlobalLogger.info() << "File is pcap";
78 GlobalLogger.info() << "File is not pcap";
82 uint32_t packet_type = 0;
85 packet_type = consume_pcap_file_header(input_stream);
86 GlobalLogger.debug() << "Packet type from header is " << packet_type;
90 GlobalLogger.notice() << "Failure consuming pcap file header!";
94 // read from stream until it is empty
99 // assume that there is a packet header if stream had pcap header
100 GlobalLogger.debug() << "Consume packet header";
101 consume_pcap_packet_header(input_stream);
104 GlobalLogger.notice() <<"Failure consuming pcap packet header!";
108 if (packet_type == 1)
110 GlobalLogger.debug() << "Consume ethernet header";
111 consume_pcap_ethernet_header(input_stream);
114 GlobalLogger.notice() <<"Failure consuming pcap packet header!";
120 // feed data to right factory
123 IcmpPacketItem packet;
126 GlobalLogger.info() << "Trying to read ICMP v4 packet"
128 packet = IcmpPacketFactory::create_icmp_packet(
129 boost::asio::ip::icmp::v4(), input_stream, dump_mode);
133 GlobalLogger.info() << "Trying to read ICMP v6 packet"
135 packet = IcmpPacketFactory::create_icmp_packet(
136 boost::asio::ip::icmp::v6(), input_stream, dump_mode);
141 GlobalLogger.notice() << "Succesfully created ICMP packet";
142 GlobalLogger.info() << packet->to_string();
146 GlobalLogger.notice() << "ICMP packet creation failed";
152 TcpSegmentItem segment;
155 GlobalLogger.info() << "Trying to read TCP v4 packet"
157 segment = TcpSegmentFactory::create_tcp_segment(
158 boost::asio::ip::tcp_raw_protocol::v4(),
163 GlobalLogger.info() << "Trying to read TCP v6 packet"
165 segment = TcpSegmentFactory::create_tcp_segment(
166 boost::asio::ip::tcp_raw_protocol::v6(),
171 GlobalLogger.notice() << "Succesfully created TCP segment";
174 GlobalLogger.notice() << "TCP segment creation failed";
181 GlobalLogger.notice() << "Stream not good after reading!";
185 // if reached this point, created a packet, otherwise will have
186 // returned with error code
189 // peek 1 byte to check whether we are at the end of stream
190 next_val = input_stream.get();
191 if ( input_stream.eof() )
193 GlobalLogger.info() << "Reached end of stream";
196 GlobalLogger.debug() << "Stream continues with value " << std::showbase
197 << std::hex << next_val;
199 if (is_pcap && packet_type == 1 && next_val == 0)
201 GlobalLogger.debug() << "Consume 0s added for alignment";
202 while (input_stream.good() && next_val == 0)
203 next_val = input_stream.get();
205 // if stream is still good, then got a non-0 value from it
207 if (input_stream.good())
208 input_stream.unget();
211 GlobalLogger.info() << "Reached end of stream";
216 input_stream.unget();
217 } //eo: while (input_stream)
219 return (-1) * packet_count;
220 } // eo: function read_packets
222 //------------------------------------------------------------------------------
223 /** @brief main function
225 * @returns 0 if all input resulted in good packets or the error number of the
228 int main(int argc, char *argv[])
233 bool is_icmp = default_is_icmp;
234 bool is_v4 = default_is_v4;
235 int current_return, return_val = 0;
236 int packet_count_good = 0;
237 int packet_count_bad = 0;
238 int dump_mode = 0; // never dump
242 GlobalLogger.notice() << "No arguments! Start with mix of file names "
244 GlobalLogger.notice() << "Valid flags: -i[cmp], -t[cp], -[v]4 -[v]6; "
245 << "-- to read from stdin instead of file";
249 // convert arguments to vector of strings and loop over them
250 std::vector<std::string> args(argv+1, argv + argc);
251 BOOST_FOREACH (const std::string &arg, args)
253 GlobalLogger.debug() << "Parsing next arg: " << arg;
256 // check if is some specification of data format
257 if (arg == "-i" || arg == "-icmp" || arg == "i" || arg == "icmp")
259 else if (arg == "-t" || arg == "-tcp" || arg == "t" || arg == "tcp")
261 else if (arg == "-4" || arg == "-v4" || arg == "4" || arg == "v4")
263 else if (arg == "-6" || arg == "-v6" || arg == "6" || arg == "v6")
265 else if (arg == "-v")
266 increase_verbosity();
267 else if (arg == "--") // read input from stdin
269 GlobalLogger.info() << "Trying to read from stdin" << std::endl;
270 current_return = read_packets(std::cin, is_icmp, is_v4, dump_mode);
272 else // assume is file name
274 GlobalLogger.info() << "Trying to read from " << arg
276 std::ifstream file_stream(arg.c_str(), std::ios::in |
280 GlobalLogger.notice() << "Failed to open file " << arg
286 current_return = read_packets( file_stream, is_icmp, is_v4,
292 if (current_return > 0)
294 GlobalLogger.debug() << "Remember error value " << current_return;
295 return_val = current_return;
298 else // returned the number of packets created * (-1)
299 packet_count_good -= current_return;
300 } //eo: loop over input-files
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)
307 GlobalLogger.debug() << "End program with return value " << return_val;
310 } // eo: function main