on this file might be covered by the GNU General Public License.
*/
+#include <fstream>
+#include <ios>
#include <logfunc.hpp>
+#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
+#include <boost/asio/ip/icmp.hpp>
#include "icmp/icmppacketfactory.h"
#include "tcp/tcpsegmentfactory.h"
using I2n::Logger::GlobalLogger;
namespace po = boost::program_options;
-//const uint32_t pcap_magic_number = 0xa1b2c3d4;
-const char pcap_magic_bytes[] = {0xa1, 0xb2, 0xc3, 0xd4};
+
+//------------------------------------------------------------------------------
+// constants
const bool default_is_icmp = true;
const bool default_is_v4 = true;
+//const uint32_t pcap_magic_number = 0xa1b2c3d4;
+typedef unsigned char byte;
+const byte pcap_magic_bytes[] = {0xa1, 0xb2, 0xc3, 0xd4};
+
+// pcap file header is 5 x uint32 + 2 x uint16 --> 24 bytes
+const std::streamsize pcap_file_header_size = 24;
+
+// pcap file header is 4 x uint32 --> 16 bytes
+const std::streamsize pcap_packet_header_size = 16;
+
+
+//------------------------------------------------------------------------------
+// function declarations
+void init_logger();
+void increase_verbosity();
+bool check_for_pcap_header(std::istream &input_stream);
+void consume_pcap_file_header(std::istream &input_stream);
+void consume_pcap_packet_header(std::istream &input_stream);
+int read_packets(std::istream &input_stream, const bool, const bool, const int);
+
+//------------------------------------------------------------------------------
+// helper functions
+
void init_logger()
{
- // set default: log at level NOTICE to syslog and stderr
- // to ensure that in case of faulty config, the error is noticed
- I2n::Logger::enable_syslog( I2n::Logger::Facility::User );
+ // set default: log at level NOTICE to stderr
I2n::Logger::enable_stderr_log( true );
- I2n::Logger::set_log_level( I2n::Logger::LogLevel::Notice );
+ //I2n::Logger::set_log_level( I2n::Logger::LogLevel::Notice );
+ I2n::Logger::set_log_level( I2n::Logger::LogLevel::Debug );
+ GlobalLogger.info() << "Logger initiated";
}
void increase_verbosity()
{
I2n::Logger::set_log_level( I2n::Logger::LogLevel::Info );
+ GlobalLogger.info() << "Increased verbosity";
}
// determine whether is raw data or pcap by peeking at first 4 bytes
bool is_pcap = true;
for (peek_idx=0; peek_idx<4; ++peek_idx)
{
- if (file_reader.get() != pcap_magic_bytes[peek_idx])
+ int val = input_stream.get();
+ GlobalLogger.debug() << "Peeked value " << std::hex << val;
+ if (val != pcap_magic_bytes[3-peek_idx])
{
is_pcap = false;
break;
}
}
for (int back_idx=peek_idx; back_idx > 0; --back_idx)
- file_reader.unget();
+ input_stream.unget();
if (is_pcap)
GlobalLogger.info() << "File is pcap";
else
GlobalLogger.info() << "File is not pcap";
return is_pcap;
-}
+}
+
+void consume_pcap_file_header(std::istream &input_stream)
+{
+ GlobalLogger.debug() << "Consuming pcap file header";
+ char *buf = new char[pcap_file_header_size];
+ input_stream.read(buf, pcap_file_header_size);
+ // could do some checking whether this data actually looks like a
+ // pcap header --> see ../icmp/icmppacketfactory.cpp
+ delete[] buf;
+}
+
+void consume_pcap_packet_header(std::istream &input_stream)
+{
+ GlobalLogger.debug() << "Consuming pcap packet header";
+ char *buf = new char[pcap_packet_header_size];
+ input_stream.read(buf, pcap_packet_header_size);
+ // could do some checking whether this data actually looks like a
+ // pcap header --> see ../icmp/icmppacketfactory.cpp
+ delete[] buf;
+}
+
+
+int read_packets( std::istream &input_stream, const bool is_icmp,
+ const bool is_v4,
+ const int dump_mode )
+{
+ // peek at start of stream to see if there is a pcap header
+ bool is_pcap = check_for_pcap_header(input_stream);
+ int next_val;
+ if (is_pcap)
+ consume_pcap_file_header(input_stream);
+ if ( !input_stream )
+ {
+ GlobalLogger.notice() << "Failure consuming pcap file header!";
+ return 2;
+ }
+
+ // read from stream until it is empty
+ while (true)
+ {
+ if (is_pcap)
+ {
+ // assume that there is a packet header if stream had pcap header
+ consume_pcap_packet_header(input_stream);
+ if ( !input_stream )
+ {
+ GlobalLogger.notice() <<"Failure consuming pcap packet header!";
+ return 3;
+ }
+ }
+ // feed data to right factory
+ if (is_icmp)
+ {
+ IcmpPacketItem packet;
+ if (is_v4)
+ {
+ GlobalLogger.info() << "Trying to read ICMP v4 packet"
+ << std::endl;
+ packet = IcmpPacketFactory::create_icmp_packet(
+ boost::asio::ip::icmp::v4(), input_stream, dump_mode);
+ }
+ else // v6
+ {
+ GlobalLogger.info() << "Trying to read ICMP v6 packet"
+ << std::endl;
+ packet = IcmpPacketFactory::create_icmp_packet(
+ boost::asio::ip::icmp::v6(), input_stream, dump_mode);
+ }
+
+ if (packet)
+ GlobalLogger.notice() << "Succesfully created ICMP packet";
+ else
+ {
+ GlobalLogger.notice() << "ICMP packet creation failed";
+ return 4;
+ }
+ }
+ else // is tcp
+ {
+ TcpSegmentItem segment;
+ if (is_v4)
+ {
+ GlobalLogger.info() << "Trying to read TCP v4 packet"
+ << std::endl;
+ segment = TcpSegmentFactory::create_tcp_segment(
+ boost::asio::ip::tcp_raw_protocol::v4(),
+ input_stream);
+ }
+ else // v6
+ {
+ GlobalLogger.info() << "Trying to read TCP v6 packet"
+ << std::endl;
+ segment = TcpSegmentFactory::create_tcp_segment(
+ boost::asio::ip::tcp_raw_protocol::v6(),
+ input_stream);
+ }
+
+ if (segment)
+ GlobalLogger.notice() << "Succesfully created TCP segment";
+ else
+ {
+ GlobalLogger.notice() << "TCP segment creation failed";
+ return 4;
+ }
+ }
+
+ if ( !input_stream )
+ {
+ GlobalLogger.notice() << "Stream not good after reading!";
+ return 5;
+ }
+
+ // peek 1 byte to check whether we are at the end of stream
+ next_val = input_stream.get();
+ if ( input_stream.eof() )
+ {
+ GlobalLogger.info() << "Reached end of stream";
+ break;
+ }
+ input_stream.unget();
+ } //eo: while (input_stream)
+
+ return 0;
+} // eo: function read_packets
+
+//------------------------------------------------------------------------------
+/** @brief main function
+ *
+ * @returns 0 if all input resulted in good packets or the error number of the
+ * last failed packet
+ */
int main(int argc, char *argv[])
{
// init logging
init_logger();
- GlobalLogger.debug() << "logger initiated with default config";
bool is_icmp = default_is_icmp;
bool is_v4 = default_is_v4;
- std::istream input_stream;
- bool is_pcap;
- bool have_stream = false;
-
- IcmpPacketItem packet;
- TcpSegmentItem segment;
+ int temp_val, return_val = 0;
+ int dump_mode = 0; // never dump
- // convert arguments
- std::vector<std::string> args(argv, argv + argc);
+ if (argc == 1)
+ {
+ GlobalLogger.notice() << "No arguments! Start with mix of file names "
+ << "and flags";
+ GlobalLogger.notice() << "Valid flags: -i[cmp], -t[cp], -[v]4 -[v]6; "
+ << "-- to read from stdin instead of file";
+ return 1;
+ }
- // loop over arguments
+ // convert arguments to vector of strings and loop over them
+ std::vector<std::string> args(argv+1, argv + argc);
BOOST_FOREACH (const std::string &arg, args)
{
+ GlobalLogger.debug() << "Parsing next arg: " << arg;
+
// check if is some specification of data format
if (arg == "-i" || arg == "-icmp" || arg == "i" || arg == "icmp")
is_icmp = true;
else if (arg == "-t" || arg == "-tcp" || arg == "t" || arg == "tcp")
is_icmp = false;
else if (arg == "-4" || arg == "-v4" || arg == "4" || arg == "v4")
- is_v4 = false;
+ is_v4 = true;
else if (arg == "-6" || arg == "-v6" || arg == "6" || arg == "v6")
- is_v6 = false;
+ is_v4 = false;
+ else if (arg == "-v")
+ increase_verbosity();
else if (arg == "--") // read input from stdin
{
- if (have_stream)
- input_stream.close();
GlobalLogger.info() << "Trying to read from stdin" << std::endl;
- input_stream = std::cin;
+ temp_val = read_packets( std::cin, is_icmp, is_v4, dump_mode );
}
else // assume is file name
{
- if (have_stream)
- input_stream.close();
- GlobalLogger.info() << "Trying to read from " << file_name
+ GlobalLogger.info() << "Trying to read from " << arg
<< std::endl;
- input_stream = file_reader(file_name, ios::in | ios::binary);
+ std::ifstream file_stream(arg.c_str(), std::ios::in |
+ std::ios::binary);
+ temp_val = read_packets( file_stream, is_icmp, is_v4, dump_mode);
+ file_stream.close();
}
- // no stream yet --> check next arg
- if (!have_stream)
- continue;
-
- // read from stream until it is empty
- while (input_stream)
- {
- is_pcap = check_for_pcap_header(input_stream);
- // TODO consume that header: file header and/or packet header
- // (maybe assume for now that there is only one data set per file)
+ if (temp_val != 0)
+ {
+ GlobalLogger.debug() << "Remember error value " << temp_val;
+ return_val = temp_val;
+ }
+ } //eo: loop over input-files
- // feed data to right factory
- if (is_icmp)
- {
- if (is_v4)
- {
- GlobalLogger.info() << "Creating ICMP v4 packet"
- << std::endl;
- packet = IcmpPacketFactory.create_icmp_packet(
- boost::asio::ip::icmp::v4, input_stream);
- }
- else // v6
- {
- GlobalLogger.info() << "Creating ICMP v6 packet"
- << std::endl;
- packet = IcmpPacketFactory.create_icmp_packet(
- boost::asio::ip::icmp::v6, input_stream);
- }
- }
- else // is tcp
- {
- if (is_v4)
- {
- GlobalLogger.info() << "Creating TCP v4 packet"
- << std::endl;
- segment = TcpSegmentFactory::create_tcp_segment(
- boost::asio::ip::tcp_raw_protocol::v4,
- input_stream);
- }
- else // v6
- {
- GlobalLogger.info() << "Creating TCP v6 packet"
- << std::endl;
- segment = TcpSegmentFactory::create_tcp_segment(
- boost::asio::ip::tcp_raw_protocol::v6,
- input_stream);
- }
- }
- } //eo: while (input_stream)
+ GlobalLogger.debug() << "End program with return value " << return_val;
+ return return_val;
- input_stream.close();
- have_stream = false;
- } //eo: loop over input-files
} // eo: function main
+