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,
72 // peek at start of stream to see if there is a pcap header
73 bool is_pcap = check_for_pcap_header(input_stream);
75 GlobalLogger.info() << "File is pcap";
77 GlobalLogger.info() << "File is not pcap";
81 uint32_t packet_type = 0;
84 packet_type = consume_pcap_file_header(input_stream);
85 GlobalLogger.debug() << "Packet type from header is " << packet_type;
89 GlobalLogger.notice() << "Failure consuming pcap file header!";
93 // read from stream until it is empty
98 // assume that there is a packet header if stream had pcap header
99 GlobalLogger.debug() << "Consume packet header";
100 consume_pcap_packet_header(input_stream);
103 GlobalLogger.notice() <<"Failure consuming pcap packet header!";
107 if (packet_type == 1)
109 GlobalLogger.debug() << "Consume ethernet header";
110 consume_pcap_ethernet_header(input_stream);
113 GlobalLogger.notice() <<"Failure consuming pcap packet header!";
119 // feed data to right factory
122 IcmpPacketItem packet;
125 GlobalLogger.info() << "Trying to read ICMP v4 packet"
127 packet = IcmpPacketFactory::create_icmp_packet(
128 boost::asio::ip::icmp::v4(), input_stream);
132 GlobalLogger.info() << "Trying to read ICMP v6 packet"
134 packet = IcmpPacketFactory::create_icmp_packet(
135 boost::asio::ip::icmp::v6(), input_stream);
140 GlobalLogger.notice() << "Succesfully created ICMP packet";
141 GlobalLogger.info() << packet->to_string();
145 GlobalLogger.notice() << "ICMP packet creation failed";
151 TcpSegmentItem segment;
154 GlobalLogger.info() << "Trying to read TCP v4 packet"
156 segment = TcpSegmentFactory::create_tcp_segment(
157 boost::asio::ip::tcp_raw_protocol::v4(),
162 GlobalLogger.info() << "Trying to read TCP v6 packet"
164 segment = TcpSegmentFactory::create_tcp_segment(
165 boost::asio::ip::tcp_raw_protocol::v6(),
170 GlobalLogger.notice() << "Succesfully created TCP segment";
173 GlobalLogger.notice() << "TCP segment creation failed";
180 GlobalLogger.notice() << "Stream not good after reading!";
184 // if reached this point, created a packet, otherwise will have
185 // returned with error code
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() )
192 GlobalLogger.info() << "Reached end of stream";
195 GlobalLogger.debug() << "Stream continues with value " << std::showbase
196 << std::hex << next_val;
198 if (is_pcap && packet_type == 1 && next_val == 0)
200 GlobalLogger.debug() << "Consume 0s added for alignment";
201 while (input_stream.good() && next_val == 0)
202 next_val = input_stream.get();
204 // if stream is still good, then got a non-0 value from it
206 if (input_stream.good())
207 input_stream.unget();
210 GlobalLogger.info() << "Reached end of stream";
215 input_stream.unget();
216 } //eo: while (input_stream)
218 return (-1) * packet_count;
219 } // eo: function read_packets
221 //------------------------------------------------------------------------------
222 /** @brief main function
224 * @returns 0 if all input resulted in good packets or the error number of the
227 int main(int argc, char *argv[])
232 bool is_icmp = default_is_icmp;
233 bool is_v4 = default_is_v4;
234 int current_return, return_val = 0;
235 int packet_count_good = 0;
236 int packet_count_bad = 0;
237 DumpMode dump_mode = DUMP_NEVER;
241 GlobalLogger.notice() << "No arguments! Start with mix of file names "
243 GlobalLogger.notice() << "Valid flags: -i[cmp], -t[cp], -[v]4 -[v]6; "
244 << "-- to read from stdin instead of file";
248 IcmpPacketFactory::PacketDumpMode = dump_mode;
250 // convert arguments to vector of strings and loop over them
251 std::vector<std::string> args(argv+1, argv + argc);
252 BOOST_FOREACH (const std::string &arg, args)
254 GlobalLogger.debug() << "Parsing next arg: " << arg;
257 // check if is some specification of data format
258 if (arg == "-i" || arg == "-icmp" || arg == "i" || arg == "icmp")
260 else if (arg == "-t" || arg == "-tcp" || arg == "t" || arg == "tcp")
262 else if (arg == "-4" || arg == "-v4" || arg == "4" || arg == "v4")
264 else if (arg == "-6" || arg == "-v6" || arg == "6" || arg == "v6")
266 else if (arg == "-v")
267 increase_verbosity();
268 else if (arg == "--") // read input from stdin
270 GlobalLogger.info() << "Trying to read from stdin" << std::endl;
271 current_return = read_packets(std::cin, is_icmp, is_v4);
273 else // assume is file name
275 GlobalLogger.info() << "Trying to read from " << arg
277 std::ifstream file_stream(arg.c_str(), std::ios::in |
281 GlobalLogger.notice() << "Failed to open file " << arg
287 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