refactor(falco/app): apply early return pattern in actions code

Signed-off-by: Leonardo Di Giovanna <leonardodigiovanna1@gmail.com>
This commit is contained in:
Leonardo Di Giovanna 2025-02-05 11:27:58 +01:00 committed by poiana
parent 31c94df10e
commit 9e2c22804c
19 changed files with 456 additions and 437 deletions

View File

@ -170,14 +170,15 @@ falco::app::run_result falco::app::actions::init_falco_engine(falco::app::state&
if(s.is_capture_mode()) {
auto manager = s.offline_inspector->get_plugin_manager();
for(const auto& p : manager->plugins()) {
if(p->caps() & CAP_SOURCING && p->id() != 0) {
bool added = false;
auto source_idx = manager->source_idx_by_plugin_id(p->id(), added);
auto engine_idx = s.source_infos.at(p->event_source())->engine_idx;
if(!added || source_idx != engine_idx) {
return run_result::fatal("Could not add event source in the engine: " +
p->event_source());
}
if((p->caps() & CAP_SOURCING) == 0 || p->id() == 0) {
continue;
}
bool added = false;
auto source_idx = manager->source_idx_by_plugin_id(p->id(), added);
auto engine_idx = s.source_infos.at(p->event_source())->engine_idx;
if(!added || source_idx != engine_idx) {
return run_result::fatal("Could not add event source in the engine: " +
p->event_source());
}
}
}

View File

@ -147,13 +147,14 @@ falco::app::run_result falco::app::actions::init_inspectors(falco::app::state& s
std::string err;
std::unordered_set<std::string> used_plugins;
const auto& all_plugins = s.offline_inspector->get_plugin_manager()->plugins();
const bool is_capture_mode = s.is_capture_mode();
for(const auto& src : s.loaded_sources) {
auto src_info = s.source_infos.at(src);
// in capture mode, every event source uses the offline inspector.
// in live mode, we create a new inspector for each event source
if(s.is_capture_mode()) {
if(is_capture_mode) {
src_info->inspector = s.offline_inspector;
} else {
src_info->inspector =
@ -174,15 +175,16 @@ falco::app::run_result falco::app::actions::init_inspectors(falco::app::state& s
((p->id() != 0 && src == p->event_source()) ||
(p->id() == 0 && src == falco_common::syscall_source));
if(s.is_capture_mode()) {
if(is_capture_mode) {
// in capture mode, every plugin is already registered
// in the offline inspector by the load_plugins action
plugin = p;
} else {
// in live mode, for the inspector assigned to the given
// event source, we must register the plugin supporting
// that event source and also plugins with field extraction
// capability that are compatible with that event source
// in live mode, for the inspector assigned to the given event source, we must
// register a plugin if one of the following condition applies to it:
// - it has event sourcing capability for the given event source
// - it has one among field extraction, event parsing and async events capabilities
// and is compatible (with respect to that capability) with the given event source
if(is_input ||
(p->caps() & CAP_EXTRACTION &&
sinsp_plugin::is_source_compatible(p->extract_event_sources(), src)) ||
@ -194,22 +196,23 @@ falco::app::run_result falco::app::actions::init_inspectors(falco::app::state& s
}
}
// init the plugin, if we registered it into an inspector
// (in capture mode, this is true for every plugin)
if(plugin) {
// avoid initializing the same plugin twice in the same
// inspector if we're in capture mode
if(!s.is_capture_mode() || used_plugins.find(p->name()) == used_plugins.end()) {
if(!plugin->init(config->m_init_config, err)) {
return run_result::fatal(err);
}
}
if(is_input) {
auto gen_check = src_info->inspector->new_generic_filtercheck();
src_info->filterchecks->add_filter_check(std::move(gen_check));
}
used_plugins.insert(plugin->name());
if(!plugin) {
continue;
}
// init the plugin only if we registered it into an inspector (in capture mode, this is
// true for every plugin). Avoid initializing the same plugin twice in the same
// inspector if we're in capture mode
if(!is_capture_mode || used_plugins.find(p->name()) == used_plugins.end()) {
if(!plugin->init(config->m_init_config, err)) {
return run_result::fatal(err);
}
}
if(is_input) {
auto gen_check = src_info->inspector->new_generic_filtercheck();
src_info->filterchecks->add_filter_check(std::move(gen_check));
}
used_plugins.insert(plugin->name());
}
// populate filtercheck list for this inspector
@ -221,20 +224,22 @@ falco::app::run_result falco::app::actions::init_inspectors(falco::app::state& s
return run_result::fatal(err);
}
// in live mode, each inspector should have registered at most two event sources:
// the "syscall" on, loaded at default at index 0, and optionally another
// one defined by a plugin, at index 1
if(!s.is_capture_mode()) {
const auto& sources = src_info->inspector->event_sources();
if(sources.size() == 0 || sources.size() > 2 ||
sources[0] != falco_common::syscall_source) {
err.clear();
for(const auto& source : sources) {
err += (err.empty() ? "" : ", ") + source;
}
return run_result::fatal("Illegal sources setup in live inspector for source '" +
src + "': " + err);
if(is_capture_mode) {
continue;
}
// in live mode, each inspector should have registered at most two event sources: the
// "syscall" on, loaded at default at index 0, and optionally another one defined by a
// plugin, at index 1
const auto& sources = src_info->inspector->event_sources();
if(sources.size() == 0 || sources.size() > 2 ||
sources[0] != falco_common::syscall_source) {
err.clear();
for(const auto& source : sources) {
err += (err.empty() ? "" : ", ") + source;
}
return run_result::fatal("Illegal sources setup in live inspector for source '" + src +
"': " + err);
}
}

View File

@ -21,17 +21,18 @@ using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::list_fields(falco::app::state& s) {
if(s.options.list_fields) {
if(s.options.list_source_fields != "" &&
!s.engine->is_source_valid(s.options.list_source_fields)) {
return run_result::fatal("Value for --list must be a valid source type");
}
s.engine->list_fields(s.options.list_source_fields,
s.options.verbose,
s.options.names_only,
s.options.markdown);
return run_result::exit();
if(!s.options.list_fields) {
return run_result::ok();
}
return run_result::ok();
if(s.options.list_source_fields != "" &&
!s.engine->is_source_valid(s.options.list_source_fields)) {
return run_result::fatal("Value for --list must be a valid source type");
}
s.engine->list_fields(s.options.list_source_fields,
s.options.verbose,
s.options.names_only,
s.options.markdown);
return run_result::exit();
}

View File

@ -24,20 +24,20 @@ using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::list_plugins(const falco::app::state& s) {
if(s.options.list_plugins) {
std::ostringstream os;
sinsp inspector;
const auto& configs = s.config->m_plugins;
for(auto& c : configs) {
// load the plugin (no need to initialize it)
auto plugin = inspector.register_plugin(c.m_library_path);
format_plugin_info(plugin, os);
os << std::endl;
}
printf("%lu Plugins Loaded:\n\n%s\n", configs.size(), os.str().c_str());
return run_result::exit();
if(!s.options.list_plugins) {
return run_result::ok();
}
return run_result::ok();
std::ostringstream os;
sinsp inspector;
const auto& configs = s.config->m_plugins;
for(auto& c : configs) {
// load the plugin (no need to initialize it)
auto plugin = inspector.register_plugin(c.m_library_path);
format_plugin_info(plugin, os);
os << std::endl;
}
printf("%lu Plugins Loaded:\n\n%s\n", configs.size(), os.str().c_str());
return run_result::exit();
}

View File

@ -51,16 +51,18 @@ falco::app::run_result falco::app::actions::load_plugins(falco::app::state& s) {
"Loading plugin '" + p.m_name + "' from file " + p.m_library_path + "\n");
auto plugin = s.offline_inspector->register_plugin(p.m_library_path);
s.plugin_configs.insert(p, plugin->name());
if(plugin->caps() & CAP_SOURCING && plugin->id() != 0) {
state::source_info src_info;
src_info.filterchecks = std::make_shared<filter_check_list>();
auto sname = plugin->event_source();
s.source_infos.insert(src_info, sname);
// note: this avoids duplicate values
if(std::find(s.loaded_sources.begin(), s.loaded_sources.end(), sname) ==
s.loaded_sources.end()) {
s.loaded_sources.push_back(sname);
}
if((plugin->caps() & CAP_SOURCING) == 0 || plugin->id() == 0) {
continue;
}
// Account the plugin event source
state::source_info src_info;
src_info.filterchecks = std::make_shared<filter_check_list>();
auto src_name = plugin->event_source();
s.source_infos.insert(src_info, src_name);
// note: this avoids duplicate values
if(std::find(s.loaded_sources.begin(), s.loaded_sources.end(), src_name) ==
s.loaded_sources.end()) {
s.loaded_sources.push_back(src_name);
}
}

View File

@ -30,21 +30,23 @@ falco::app::run_result falco::app::actions::pidfile(const falco::app::state& sta
return run_result::ok();
}
if(!state.options.pidfilename.empty()) {
int64_t self_pid = getpid();
std::ofstream stream;
stream.open(state.options.pidfilename);
if(!stream.good()) {
falco_logger::log(
falco_logger::level::ERR,
"Could not write pid to pidfile " + state.options.pidfilename + ". Exiting.\n");
exit(-1);
}
stream << self_pid;
stream.close();
if(state.options.pidfilename.empty()) {
return run_result::ok();
}
int64_t self_pid = getpid();
std::ofstream stream;
stream.open(state.options.pidfilename);
if(!stream.good()) {
falco_logger::log(
falco_logger::level::ERR,
"Could not write pid to pidfile " + state.options.pidfilename + ". Exiting.\n");
exit(-1);
}
stream << self_pid;
stream.close();
return run_result::ok();
}

View File

@ -21,9 +21,10 @@ using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::print_config_schema(falco::app::state &s) {
if(s.options.print_config_schema) {
printf("%s", s.config->m_config_schema.dump(2).c_str());
return run_result::exit();
if(!s.options.print_config_schema) {
return run_result::ok();
}
return run_result::ok();
printf("%s", s.config->m_config_schema.dump(2).c_str());
return run_result::exit();
}

View File

@ -22,12 +22,13 @@ using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::print_generated_gvisor_config(falco::app::state& s) {
if(!s.options.gvisor_generate_config_with_socket.empty()) {
sinsp i;
std::string gvisor_config =
i.generate_gvisor_config(s.options.gvisor_generate_config_with_socket);
printf("%s\n", gvisor_config.c_str());
return run_result::exit();
if(s.options.gvisor_generate_config_with_socket.empty()) {
return run_result::ok();
}
return run_result::ok();
sinsp i;
std::string gvisor_config =
i.generate_gvisor_config(s.options.gvisor_generate_config_with_socket);
printf("%s\n", gvisor_config.c_str());
return run_result::exit();
}

View File

@ -21,9 +21,10 @@ using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::print_help(falco::app::state& s) {
if(s.options.help) {
printf("%s", s.options.usage().c_str());
return run_result::exit();
if(!s.options.help) {
return run_result::ok();
}
return run_result::ok();
printf("%s", s.options.usage().c_str());
return run_result::exit();
}

View File

@ -28,22 +28,25 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::print_kernel_version(const falco::app::state& s) {
#ifdef __linux__
// We print this info only when a kernel driver is injected
if(s.is_modern_ebpf() || s.is_ebpf() || s.is_kmod()) {
std::ifstream input_file("/proc/version");
if(!input_file.is_open()) {
// We don't want to fail, we just need to log something
falco_logger::log(falco_logger::level::INFO,
"Cannot read under '/proc/version' (err_message: '" +
std::string(strerror(errno)) + "', err_code: " +
std::to_string(errno) + "). No info provided, go on.");
return run_result::ok();
}
std::stringstream buffer;
buffer << input_file.rdbuf();
std::string contents(buffer.str());
falco_logger::log(falco_logger::level::INFO, "System info: " + contents);
bool const is_kernel_driver_injected = s.is_modern_ebpf() || s.is_ebpf() || s.is_kmod();
if(!is_kernel_driver_injected) {
return run_result::ok();
}
std::ifstream input_file("/proc/version");
if(!input_file.is_open()) {
// We don't want to fail, we just need to log something
falco_logger::log(
falco_logger::level::INFO,
"Cannot read under '/proc/version' (err_message: '" + std::string(strerror(errno)) +
"', err_code: " + std::to_string(errno) + "). No info provided, go on.");
return run_result::ok();
}
std::stringstream buffer;
buffer << input_file.rdbuf();
std::string contents(buffer.str());
falco_logger::log(falco_logger::level::INFO, "System info: " + contents);
#endif
return run_result::ok();
}

View File

@ -24,25 +24,24 @@ using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::print_page_size(const falco::app::state& s) {
if(s.options.print_page_size) {
#ifndef _WIN32
long page_size = getpagesize();
#else
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
long page_size = sysInfo.dwPageSize;
#endif
if(page_size <= 0) {
return run_result::fatal(
"\nUnable to get the system page size through 'getpagesize()'\n");
} else {
falco_logger::log(
falco_logger::level::INFO,
"Your system page size is: " + std::to_string(page_size) + " bytes\n");
}
return run_result::exit();
if(!s.options.print_page_size) {
return run_result::ok();
}
return run_result::ok();
#ifndef _WIN32
long page_size = getpagesize();
#else
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
long page_size = sysInfo.dwPageSize;
#endif
if(page_size <= 0) {
return run_result::fatal("\nUnable to get the system page size through 'getpagesize()'\n");
}
falco_logger::log(falco_logger::level::INFO,
"Your system page size is: " + std::to_string(page_size) + " bytes\n");
return run_result::exit();
}

View File

@ -24,78 +24,81 @@ using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::print_plugin_info(const falco::app::state &s) {
if(!s.options.print_plugin_info.empty()) {
sinsp inspector;
for(auto &pc : s.config->m_plugins) {
if(pc.m_name == s.options.print_plugin_info ||
pc.m_library_path == s.options.print_plugin_info) {
// load the plugin
auto p = inspector.register_plugin(pc.m_library_path);
// print plugin descriptive info
std::ostringstream os;
format_plugin_info(p, os);
os << std::endl;
printf("%s", os.str().c_str());
// print plugin init schema
os.str("");
os.clear();
ss_plugin_schema_type type;
auto schema = p->get_init_schema(type);
os << "Init config schema type: ";
switch(type) {
case SS_PLUGIN_SCHEMA_JSON:
os << "JSON" << std::endl;
break;
case SS_PLUGIN_SCHEMA_NONE:
default:
os << "Not available, plugin does not implement the init config schema "
"functionality"
<< std::endl;
break;
}
os << schema << std::endl;
os << std::endl;
printf("%s", os.str().c_str());
// init the plugin
std::string err;
if(!p->init(pc.m_init_config, err)) {
return run_result::fatal(err);
}
// print plugin suggested open parameters
if(p->caps() & CAP_SOURCING) {
os.str("");
os.clear();
auto params = p->list_open_params();
if(params.empty()) {
os << "No suggested open params available: ";
os << "plugin has not been configured, or it does not implement the open "
"params suggestion functionality"
<< std::endl;
} else {
os << "Suggested open params:" << std::endl;
for(const auto &oparam : p->list_open_params()) {
if(oparam.desc == "") {
os << oparam.value << std::endl;
} else {
os << oparam.value << ": " << oparam.desc << std::endl;
}
}
}
os << std::endl;
printf("%s", os.str().c_str());
}
// exit
return run_result::exit();
}
}
return run_result::fatal("can't find plugin and print its info: " +
s.options.print_plugin_info);
if(s.options.print_plugin_info.empty()) {
return run_result::ok();
}
return run_result::ok();
sinsp inspector;
for(auto &pc : s.config->m_plugins) {
if(pc.m_name != s.options.print_plugin_info &&
pc.m_library_path != s.options.print_plugin_info) {
continue;
}
// found matching plugin; load it
auto p = inspector.register_plugin(pc.m_library_path);
// print plugin descriptive info
std::ostringstream os;
format_plugin_info(p, os);
os << std::endl;
printf("%s", os.str().c_str());
// print plugin init schema
os.str("");
os.clear();
ss_plugin_schema_type type;
auto schema = p->get_init_schema(type);
os << "Init config schema type: ";
switch(type) {
case SS_PLUGIN_SCHEMA_JSON:
os << "JSON" << std::endl;
break;
case SS_PLUGIN_SCHEMA_NONE:
default:
os << "Not available, plugin does not implement the init config schema "
"functionality"
<< std::endl;
break;
}
os << schema << std::endl;
os << std::endl;
printf("%s", os.str().c_str());
// init the plugin
std::string err;
if(!p->init(pc.m_init_config, err)) {
return run_result::fatal(err);
}
// print plugin suggested open parameters
if(p->caps() & CAP_SOURCING) {
os.str("");
os.clear();
auto params = p->list_open_params();
if(params.empty()) {
os << "No suggested open params available: ";
os << "plugin has not been configured, or it does not implement the open "
"params suggestion functionality"
<< std::endl;
} else {
os << "Suggested open params:" << std::endl;
for(const auto &oparam : p->list_open_params()) {
if(oparam.desc == "") {
os << oparam.value << std::endl;
} else {
os << oparam.value << ": " << oparam.desc << std::endl;
}
}
}
os << std::endl;
printf("%s", os.str().c_str());
}
// exit
return run_result::exit();
}
return run_result::fatal("can't find plugin and print its info: " +
s.options.print_plugin_info);
}

View File

@ -21,9 +21,10 @@ using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::print_rule_schema(falco::app::state &s) {
if(s.options.print_rule_schema) {
printf("%s", s.engine->m_rule_schema.dump(2).c_str());
return run_result::exit();
if(!s.options.print_rule_schema) {
return run_result::ok();
}
return run_result::ok();
printf("%s", s.engine->m_rule_schema.dump(2).c_str());
return run_result::exit();
}

View File

@ -88,31 +88,30 @@ static int get_sysinfo(nlohmann::json& support) {
#endif
falco::app::run_result falco::app::actions::print_support(falco::app::state& s) {
if(s.options.print_support) {
nlohmann::json support;
if(get_sysinfo(support) != 0) {
return run_result::fatal(std::string("Could not get system info: ") + strerror(errno));
}
const falco::versions_info infos(s.offline_inspector);
support["version"] = infos.falco_version;
support["engine_info"] = infos.as_json();
support["cmdline"] = s.cmdline;
support["config"] = s.config->dump();
support["rules_files"] = nlohmann::json::array();
for(const auto& filename : s.config->m_loaded_rules_filenames) {
nlohmann::json finfo;
finfo["name"] = filename;
nlohmann::json variant;
variant["content"] = read_file(filename);
finfo["variants"].push_back(variant);
support["rules_files"].push_back(finfo);
}
printf("%s\n", support.dump().c_str());
return run_result::exit();
if(!s.options.print_support) {
return run_result::ok();
}
return run_result::ok();
nlohmann::json support;
if(get_sysinfo(support) != 0) {
return run_result::fatal(std::string("Could not get system info: ") + strerror(errno));
}
const falco::versions_info infos(s.offline_inspector);
support["version"] = infos.falco_version;
support["engine_info"] = infos.as_json();
support["cmdline"] = s.cmdline;
support["config"] = s.config->dump();
support["rules_files"] = nlohmann::json::array();
for(const auto& filename : s.config->m_loaded_rules_filenames) {
nlohmann::json finfo;
finfo["name"] = filename;
nlohmann::json variant;
variant["content"] = read_file(filename);
finfo["variants"].push_back(variant);
support["rules_files"].push_back(finfo);
}
printf("%s\n", support.dump().c_str());
return run_result::exit();
}

View File

@ -157,30 +157,29 @@ static void print_events(const std::vector<event_entry>& events, bool markdown)
}
falco::app::run_result falco::app::actions::print_syscall_events(falco::app::state& s) {
if(s.options.list_syscall_events) {
const falco::versions_info info(s.offline_inspector);
printf("The events below are valid for Falco *Schema Version*: %s\n",
info.driver_schema_version.c_str());
const libsinsp::events::set<ppm_event_code> available =
libsinsp::events::all_event_set().diff(
sc_set_to_event_set(falco::app::ignored_sc_set()));
const struct events_by_category events_bc = get_event_entries_by_category(true, available);
printf("## Syscall events\n\n");
print_events(events_bc.syscalls, s.options.markdown);
printf("\n\n## Tracepoint events\n\n");
print_events(events_bc.tracepoints, s.options.markdown);
printf("\n\n## Plugin events\n\n");
print_events(events_bc.pluginevents, s.options.markdown);
printf("\n\n## Metaevents\n\n");
print_events(events_bc.metaevents, s.options.markdown);
return run_result::exit();
if(!s.options.list_syscall_events) {
return run_result::ok();
}
return run_result::ok();
const falco::versions_info info(s.offline_inspector);
printf("The events below are valid for Falco *Schema Version*: %s\n",
info.driver_schema_version.c_str());
const libsinsp::events::set<ppm_event_code> available = libsinsp::events::all_event_set().diff(
sc_set_to_event_set(falco::app::ignored_sc_set()));
const struct events_by_category events_bc = get_event_entries_by_category(true, available);
printf("## Syscall events\n\n");
print_events(events_bc.syscalls, s.options.markdown);
printf("\n\n## Tracepoint events\n\n");
print_events(events_bc.tracepoints, s.options.markdown);
printf("\n\n## Plugin events\n\n");
print_events(events_bc.pluginevents, s.options.markdown);
printf("\n\n## Metaevents\n\n");
print_events(events_bc.metaevents, s.options.markdown);
return run_result::exit();
}

View File

@ -22,22 +22,22 @@ using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::print_version(falco::app::state& s) {
if(s.options.print_version_info) {
const falco::versions_info info(s.offline_inspector);
if(s.config->m_json_output) {
printf("%s\n", info.as_json().dump().c_str());
} else {
printf("Falco version: %s\n", info.falco_version.c_str());
printf("Libs version: %s\n", info.libs_version.c_str());
printf("Plugin API: %s\n", info.plugin_api_version.c_str());
printf("Engine: %s\n", info.engine_version.c_str());
printf("Driver:\n");
printf(" API version: %s\n", info.driver_api_version.c_str());
printf(" Schema version: %s\n", info.driver_schema_version.c_str());
printf(" Default driver: %s\n", info.default_driver_version.c_str());
}
return run_result::exit();
if(!s.options.print_version_info) {
return run_result::ok();
}
return run_result::ok();
const falco::versions_info info(s.offline_inspector);
if(s.config->m_json_output) {
printf("%s\n", info.as_json().dump().c_str());
} else {
printf("Falco version: %s\n", info.falco_version.c_str());
printf("Libs version: %s\n", info.libs_version.c_str());
printf("Plugin API: %s\n", info.plugin_api_version.c_str());
printf("Engine: %s\n", info.engine_version.c_str());
printf("Driver:\n");
printf(" API version: %s\n", info.driver_api_version.c_str());
printf(" Schema version: %s\n", info.driver_schema_version.c_str());
printf(" Default driver: %s\n", info.default_driver_version.c_str());
}
return run_result::exit();
}

View File

@ -27,44 +27,46 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::start_grpc_server(falco::app::state& s) {
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
// gRPC server
if(s.config->m_grpc_enabled) {
if(s.options.dry_run) {
falco_logger::log(falco_logger::level::DEBUG,
"Skipping starting gRPC server in dry-run\n");
return run_result::ok();
}
falco_logger::log(falco_logger::level::INFO,
"gRPC server threadiness equals to " +
std::to_string(s.config->m_grpc_threadiness) + "\n");
// TODO(fntlnz,leodido): when we want to spawn multiple threads we need to have a queue per
// thread, or implement different queuing mechanisms, round robin, fanout? What we want to
// achieve?
s.grpc_server.init(s.config->m_grpc_bind_address,
s.config->m_grpc_threadiness,
s.config->m_grpc_private_key,
s.config->m_grpc_cert_chain,
s.config->m_grpc_root_certs,
s.config->m_log_level);
s.grpc_server_thread = std::thread([&s] { s.grpc_server.run(); });
if(!s.config->m_grpc_enabled) {
return run_result::ok();
}
if(s.options.dry_run) {
falco_logger::log(falco_logger::level::DEBUG, "Skipping starting gRPC server in dry-run\n");
return run_result::ok();
}
falco_logger::log(falco_logger::level::INFO,
"gRPC server threadiness equals to " +
std::to_string(s.config->m_grpc_threadiness) + "\n");
// TODO(fntlnz,leodido): when we want to spawn multiple threads we need to have a queue per
// thread, or implement different queuing mechanisms, round robin, fanout? What we want to
// achieve?
s.grpc_server.init(s.config->m_grpc_bind_address,
s.config->m_grpc_threadiness,
s.config->m_grpc_private_key,
s.config->m_grpc_cert_chain,
s.config->m_grpc_root_certs,
s.config->m_log_level);
s.grpc_server_thread = std::thread([&s] { s.grpc_server.run(); });
#endif
return run_result::ok();
}
falco::app::run_result falco::app::actions::stop_grpc_server(falco::app::state& s) {
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(s.config->m_grpc_enabled) {
if(s.options.dry_run) {
falco_logger::log(falco_logger::level::DEBUG,
"Skipping stopping gRPC server in dry-run\n");
return run_result::ok();
}
if(!s.config->m_grpc_enabled) {
return run_result::ok();
}
if(s.grpc_server_thread.joinable()) {
s.grpc_server.shutdown();
s.grpc_server_thread.join();
}
if(s.options.dry_run) {
falco_logger::log(falco_logger::level::DEBUG, "Skipping stopping gRPC server in dry-run\n");
return run_result::ok();
}
if(s.grpc_server_thread.joinable()) {
s.grpc_server.shutdown();
s.grpc_server_thread.join();
}
#endif
return run_result::ok();

View File

@ -26,39 +26,40 @@ using namespace falco::app::actions;
falco::app::run_result falco::app::actions::start_webserver(falco::app::state& state) {
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(!state.is_capture_mode() && state.config->m_webserver_enabled) {
if(state.options.dry_run) {
falco_logger::log(falco_logger::level::DEBUG,
"Skipping starting webserver in dry-run\n");
return run_result::ok();
}
falco_configuration::webserver_config webserver_config = state.config->m_webserver_config;
std::string ssl_option = (webserver_config.m_ssl_enabled ? " (SSL)" : "");
falco_logger::log(falco_logger::level::INFO,
"Starting health webserver with threadiness " +
std::to_string(webserver_config.m_threadiness) +
", listening on " + webserver_config.m_listen_address + ":" +
std::to_string(webserver_config.m_listen_port) + ssl_option +
"\n");
state.webserver.start(state, webserver_config);
if(state.is_capture_mode() || !state.config->m_webserver_enabled) {
return run_result::ok();
}
if(state.options.dry_run) {
falco_logger::log(falco_logger::level::DEBUG, "Skipping starting webserver in dry-run\n");
return run_result::ok();
}
falco_configuration::webserver_config webserver_config = state.config->m_webserver_config;
std::string ssl_option = (webserver_config.m_ssl_enabled ? " (SSL)" : "");
falco_logger::log(falco_logger::level::INFO,
"Starting health webserver with threadiness " +
std::to_string(webserver_config.m_threadiness) + ", listening on " +
webserver_config.m_listen_address + ":" +
std::to_string(webserver_config.m_listen_port) + ssl_option + "\n");
state.webserver.start(state, webserver_config);
#endif
return run_result::ok();
}
falco::app::run_result falco::app::actions::stop_webserver(falco::app::state& state) {
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
if(!state.is_capture_mode() && state.config->m_webserver_enabled) {
if(state.options.dry_run) {
falco_logger::log(falco_logger::level::DEBUG,
"Skipping stopping webserver in dry-run\n");
return run_result::ok();
}
state.webserver.stop();
if(state.is_capture_mode() || !state.config->m_webserver_enabled) {
return run_result::ok();
}
if(state.options.dry_run) {
falco_logger::log(falco_logger::level::DEBUG, "Skipping stopping webserver in dry-run\n");
return run_result::ok();
}
state.webserver.stop();
#endif
return run_result::ok();
}

View File

@ -26,115 +26,113 @@ using namespace falco::app;
using namespace falco::app::actions;
falco::app::run_result falco::app::actions::validate_rules_files(falco::app::state& s) {
if(s.options.validate_rules_filenames.size() > 0) {
std::vector<std::string> rules_contents;
falco::load_result::rules_contents_t rc;
if(s.options.validate_rules_filenames.size() == 0) {
return run_result::ok();
}
try {
read_files(s.options.validate_rules_filenames.begin(),
s.options.validate_rules_filenames.end(),
rules_contents,
rc);
} catch(falco_exception& e) {
return run_result::fatal(e.what());
std::vector<std::string> rules_contents;
falco::load_result::rules_contents_t rc;
try {
read_files(s.options.validate_rules_filenames.begin(),
s.options.validate_rules_filenames.end(),
rules_contents,
rc);
} catch(falco_exception& e) {
return run_result::fatal(e.what());
}
bool successful = true;
// The validation result is *always* printed to
// stdout. When json_output is true, the output is in
// json format and contains all errors/warnings for
// all files.
//
// When json_output is false, it contains a summary of
// each file and whether it was valid or not, along
// with any errors. To match older falco behavior,
// this *only* contains errors.
//
// So for each file stdout will contain:
//
// <filename>: Ok
// or
// <filename>: Invalid
// [All Validation Errors]
//
// Warnings are only printed to stderr, and only
// printed when verbose is true.
std::string summary;
falco_logger::log(falco_logger::level::INFO, "Validating rules file(s):\n");
for(const auto& file : s.options.validate_rules_filenames) {
falco_logger::log(falco_logger::level::INFO, " " + file + "\n");
}
// The json output encompasses all files so the
// validation result is a single json object.
std::string err = "";
nlohmann::json results = nlohmann::json::array();
for(auto& filename : s.options.validate_rules_filenames) {
std::unique_ptr<falco::load_result> res;
res = s.engine->load_rules(rc.at(filename), filename);
if(!check_rules_plugin_requirements(s, err)) {
return run_result::fatal(err);
}
bool successful = true;
// The validation result is *always* printed to
// stdout. When json_output is true, the output is in
// json format and contains all errors/warnings for
// all files.
//
// When json_output is false, it contains a summary of
// each file and whether it was valid or not, along
// with any errors. To match older falco behavior,
// this *only* contains errors.
//
// So for each file stdout will contain:
//
// <filename>: Ok
// or
// <filename>: Invalid
// [All Validation Errors]
//
// Warnings are only printed to stderr, and only
// printed when verbose is true.
std::string summary;
falco_logger::log(falco_logger::level::INFO, "Validating rules file(s):\n");
for(const auto& file : s.options.validate_rules_filenames) {
falco_logger::log(falco_logger::level::INFO, " " + file + "\n");
}
// The json output encompasses all files so the
// validation result is a single json object.
std::string err = "";
nlohmann::json results = nlohmann::json::array();
for(auto& filename : s.options.validate_rules_filenames) {
std::unique_ptr<falco::load_result> res;
res = s.engine->load_rules(rc.at(filename), filename);
if(!check_rules_plugin_requirements(s, err)) {
return run_result::fatal(err);
}
successful &= res->successful();
if(s.config->m_json_output) {
results.push_back(res->as_json(rc));
}
if(summary != "") {
summary += "\n";
}
// Add to the summary if not successful, or successful
// with no warnings.
if(!res->successful() || (res->successful() && !res->has_warnings())) {
summary += res->as_string(true, rc);
} else {
// If here, there must be only warnings.
// Add a line to the summary noting that the
// file was ok with warnings, without actually
// printing the warnings.
summary += filename + ": Ok, with warnings";
falco_logger::log(falco_logger::level::WARNING, res->as_string(true, rc) + "\n");
}
}
// printout of `-L` option
nlohmann::json describe_res;
if(successful && (s.options.describe_all_rules || !s.options.describe_rule.empty())) {
std::string* rptr =
!s.options.describe_rule.empty() ? &(s.options.describe_rule) : nullptr;
const auto& plugins = s.offline_inspector->get_plugin_manager()->plugins();
describe_res = s.engine->describe_rule(rptr, plugins);
}
successful &= res->successful();
if(s.config->m_json_output) {
nlohmann::json res;
res["falco_load_results"] = results;
if(!describe_res.empty() && successful) {
res["falco_describe_results"] = std::move(describe_res);
}
std::cout << res.dump() << std::endl;
} else {
std::cout << summary << std::endl;
if(!describe_res.empty() && successful) {
std::cout << std::endl;
format_described_rules_as_text(describe_res, std::cout);
}
results.push_back(res->as_json(rc));
}
if(successful) {
return run_result::exit();
if(summary != "") {
summary += "\n";
}
// Add to the summary if not successful, or successful
// with no warnings.
if(!res->successful() || (res->successful() && !res->has_warnings())) {
summary += res->as_string(true, rc);
} else {
return run_result::fatal(summary);
// If here, there must be only warnings.
// Add a line to the summary noting that the
// file was ok with warnings, without actually
// printing the warnings.
summary += filename + ": Ok, with warnings";
falco_logger::log(falco_logger::level::WARNING, res->as_string(true, rc) + "\n");
}
}
return run_result::ok();
// printout of `-L` option
nlohmann::json describe_res;
if(successful && (s.options.describe_all_rules || !s.options.describe_rule.empty())) {
std::string* rptr = !s.options.describe_rule.empty() ? &(s.options.describe_rule) : nullptr;
const auto& plugins = s.offline_inspector->get_plugin_manager()->plugins();
describe_res = s.engine->describe_rule(rptr, plugins);
}
if(s.config->m_json_output) {
nlohmann::json res;
res["falco_load_results"] = results;
if(!describe_res.empty() && successful) {
res["falco_describe_results"] = std::move(describe_res);
}
std::cout << res.dump() << std::endl;
} else {
std::cout << summary << std::endl;
if(!describe_res.empty() && successful) {
std::cout << std::endl;
format_described_rules_as_text(describe_res, std::cout);
}
}
if(!successful) {
return run_result::fatal(summary);
}
return run_result::exit();
}