//------------------------------------------------------------------------------
// Author: Pavel Karneliuk
// Description: Class provides validation and access to application parameters
// Copyright (c) 2013 EPAM Systems
//------------------------------------------------------------------------------
/*
This file is part of Nfstrace.
Nfstrace is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 2 of the License.
Nfstrace is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Nfstrace. If not, see .
*/
//------------------------------------------------------------------------------
#include
#include
#include "analysis/plugin.h"
#include "controller/cmdline_args.h"
#include "controller/cmdline_parser.h"
#include "controller/parameters.h"
#include "controller/build_info.h"
#include "filtration/pcap/network_interfaces.h"
//------------------------------------------------------------------------------
namespace NST
{
namespace controller
{
namespace // implementation
{
static const class ParametersImpl* impl = nullptr;
using CLI = NST::controller::cmdline::Args;
class ParametersImpl : public cmdline::CmdlineParser
{
friend class NST::controller::Parameters;
ParametersImpl(int argc, char** argv)
: rpc_message_limit{0}
{
parse(argc, argv);
if(get(CLI::HELP).to_bool())
{
std::cout << PROGRAM_BUILD_INFO << std::endl;
print_usage(std::cout, argv[0]);
for(const auto& a : analysis_modules)
{
const std::string& path {a.path};
try
{
std::cout << "Usage of " << path << ":\n";
std::cout << NST::analysis::Plugin::usage_of(path) << std::endl;
}
catch(std::runtime_error& e)
{
std::cout << e.what() << std::endl;
}
}
return;
}
validate();
if(get(CLI::LIST).to_bool())
{
NST::filtration::pcap::NetworkInterfaces interfaces;
if(interfaces.begin() != interfaces.end())
{
for(auto i : interfaces)
{
std::cout << i << '\n';
for(auto a : i) std::cout << '\t' << a << '\n';
}
std::cout << "[default]: " << interfaces.default_device() << '\n';
}
else
{
std::cerr << "Note: Reading list of network interfaces may "
"require that you have special privileges." << std::endl;
}
}
// cashed values
const std::string program_path(argv[0]);
size_t found {program_path.find_last_of("/\\")};
program = program_path.substr(found+1);
const int limit {get(CLI::MSIZE).to_int()};
if(limit < 1 || limit > 4000)
{
throw cmdline::CLIError{std::string{"Invalid limit of RPC messages: "} + get(CLI::MSIZE).to_cstr()};
}
rpc_message_limit = limit;
}
virtual ~ParametersImpl(){}
ParametersImpl(const ParametersImpl&) = delete;
ParametersImpl& operator=(const ParametersImpl&) = delete;
protected:
void set_multiple_value(int index, char *const v) override
{
if(index == CLI::ANALYZERS) // may have multiple values
{
const std::string arg{v};
size_t ind {arg.find('#')};
if(ind == std::string::npos)
{
analysis_modules.emplace_back(path_to_pam(arg));
}
else
{
const std::string path{arg, 0, ind};
const std::string args{arg, ind + 1};
analysis_modules.emplace_back(path_to_pam(path), args);
}
}
}
private:
std::string default_iofile() const
{
// create string: PROGRAMNAME-BPF-FILTER.pcap
std::string str { impl->program };
str.push_back('-');
str.append(get(CLI::FILTER).to_cstr());
str.append(".pcap");
std::replace(str.begin(), str.end(), ' ', '-');
return str;
}
std::string path_to_pam(const std::string& path) const
{
std::string result_path;
if(access(path.c_str(), F_OK) != -1)
{
result_path = path;
}
else
{
result_path = std::string{MODULES_DIRECTORY_PATH} + path;
}
return result_path;
}
// cashed values
unsigned short rpc_message_limit;
std::string program; // name of program in command line
std::vector analysis_modules;
};
} // unnamed namespace
Parameters::Parameters(int argc, char** argv)
{
// init global instance only once
if(impl) throw std::runtime_error{"initialized twice"};
impl = new ParametersImpl(argc, argv);
}
Parameters::~Parameters()
{
delete impl;
impl = nullptr;
}
bool Parameters::show_help() const
{
return impl->get(CLI::HELP).to_bool();
}
bool Parameters::show_list() const
{
return impl->get(CLI::LIST).to_bool();
}
const std::string& Parameters::program_name() const
{
return impl->program;
}
RunningMode Parameters::running_mode() const
{
const auto& mode = impl->get(CLI::MODE);
if(mode.is(CLI::profiling_mode))
{
return RunningMode::Profiling;
}
else if(mode.is(CLI::dumping_mode))
{
return RunningMode::Dumping;
}
else if(mode.is(CLI::analysis_mode))
{
return RunningMode::Analysis;
}
else if(mode.is(CLI::draining_mode))
{
return RunningMode::Draining;
}
throw cmdline::CLIError{std::string{"Unknown mode: "} + mode.to_cstr()};
}
std::string Parameters::input_file() const
{
// TODO: add file validation
return impl->is_default(CLI::IFILE) ? impl->default_iofile() : impl->get(CLI::IFILE);
}
const std::string Parameters::dropuser() const
{
return impl->get(CLI::DROPROOT);
}
const std::string Parameters::log_path() const
{
return impl->get(CLI::LOGPATH);
}
unsigned short Parameters::queue_capacity() const
{
const int capacity = impl->get(CLI::QSIZE).to_int();
if(capacity < 1 || capacity > 65535)
{
throw cmdline::CLIError(std::string{"Invalid value of queue capacity: "}
+ impl->get(CLI::QSIZE).to_cstr());
}
return capacity;
}
bool Parameters::trace() const
{
// enable tracing if no analysis module was passed
return impl->get(CLI::TRACE).to_bool() || impl->analysis_modules.empty();
}
int Parameters::verbose_level() const
{
return impl->get(CLI::VERBOSE).to_int();
}
const Parameters::CaptureParams Parameters::capture_params() const
{
Parameters::CaptureParams params;
params.interface = impl->get(CLI::INTERFACE);
params.filter = impl->get(CLI::FILTER);
params.snaplen = impl->get(CLI::SNAPLEN).to_int();
params.timeout_ms = impl->get(CLI::TIMEOUT).to_int();
params.buffer_size = impl->get(CLI::BSIZE).to_int() * 1024 * 1024; // MBytes
params.promisc = impl->get(CLI::PROMISC).to_bool();
// check interface
if(impl->is_default(CLI::INTERFACE))
{
params.interface = NST::filtration::pcap::NetworkInterfaces::default_device();
}
// check capture buffer size
if(params.buffer_size < 1024 * 1024) // less than 1 MBytes
{
throw cmdline::CLIError{std::string{"Invalid value of kernel buffer size: "}
+ impl->get(CLI::BSIZE).to_cstr()};
}
// check max length of raw captured UDP packet
if(params.snaplen < 1 || params.snaplen > 65535)
{
throw cmdline::CLIError{std::string{"Invalid value of max length of raw captured UDP packet: "}
+ impl->get(CLI::SNAPLEN).to_cstr()};
}
// check the read timeout that will be used on a capture
if(params.timeout_ms < 1)
{
throw cmdline::CLIError{std::string{"Invalid value of read timeout that will be used on a capture: "}
+ impl->get(CLI::TIMEOUT).to_cstr()};
}
// check and set capture direction
const auto& direction = impl->get(CLI::DIRECTION);
if(direction.is("in"))
{
params.direction = decltype(params.direction)::IN;
}
else if(direction.is("out"))
{
params.direction = decltype(params.direction)::OUT;
}
else if(direction.is("inout"))
{
params.direction = decltype(params.direction)::INOUT;
}
else
{
throw cmdline::CLIError{std::string{"Unknown capturing direction: "}
+ direction.to_cstr()};
}
return params;
}
const Parameters::DumpingParams Parameters::dumping_params() const
{
std::string ofile = impl->is_default(CLI::OFILE) ? impl->default_iofile() : impl->get(CLI::OFILE);
// TODO: add file validation
const int dsize = impl->get(CLI::DSIZE).to_int();
if(dsize != 0 && ofile == "-") // '-' is alias for stdout in libpcap dumps
{
throw cmdline::CLIError{std::string{"Output file \"-\" means stdout, the dump-size must be 0"}};
}
Parameters::DumpingParams params;
params.output_file = ofile;
params.command = impl->get(CLI::COMMAND);
params.size_limit = dsize * 1024 * 1024; // MBytes
return params;
}
const std::vector& Parameters::analysis_modules() const
{
return impl->analysis_modules;
}
unsigned short Parameters::rpcmsg_limit()
{
return impl->rpc_message_limit;
}
} // namespace controller
} // namespace NST
//------------------------------------------------------------------------------