new(userspace/falco): added an option to listen to changes on the config file and rules files, and trigger a Falco reload.

Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
This commit is contained in:
Federico Di Pierro 2022-05-06 09:40:34 +02:00 committed by poiana
parent 8c6cfae18f
commit e32f5a66c5
7 changed files with 87 additions and 3 deletions

View File

@ -18,6 +18,8 @@ limitations under the License.
#include <string.h>
#include <signal.h>
#include <sys/inotify.h>
#include <fcntl.h>
#include "application.h"
@ -30,6 +32,7 @@ using namespace falco::app;
static application dummy;
static std::reference_wrapper<application> s_app = dummy;
static int inot_fd;
static void signal_callback(int signal)
{
@ -85,10 +88,87 @@ application::run_result application::create_signal_handlers()
return ret;
}
application::run_result application::attach_inotify_signals()
{
run_result ret;
if (m_options.monitor_files)
{
inot_fd = inotify_init();
if (inot_fd == -1)
{
ret.success = false;
ret.errstr = std::string("Could not create inotify handler.");
ret.proceed = false;
return ret;
}
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = restart_falco;
if (sigaction(SIGIO, &sa, NULL) == -1)
{
ret.success = false;
ret.errstr = std::string("Failed to link SIGIO to inotify handler.");
ret.proceed = false;
return ret;
}
/* Set owner process that is to receive "I/O possible" signal */
if (fcntl(inot_fd, F_SETOWN, getpid()) == -1)
{
ret.success = false;
ret.errstr = std::string("Failed to setting owner on inotify handler.");
ret.proceed = false;
return ret;
}
/*
* Enable "I/O possible" signaling and make I/O nonblocking
* for file descriptor
*/
int flags = fcntl(inot_fd, F_GETFL);
if (fcntl(inot_fd, F_SETFL, flags | O_ASYNC | O_NONBLOCK) == -1)
{
ret.success = false;
ret.errstr = std::string("Failed to setting flags on inotify handler.");
ret.proceed = false;
return ret;
}
/* Add watchers */
int wd = inotify_add_watch(inot_fd, m_options.conf_filename.c_str(), IN_CLOSE_WRITE);
if (wd == -1)
{
ret.success = false;
ret.errstr = std::string("Failed to watch conf file.");
ret.proceed = false;
return ret;
}
falco_logger::log(LOG_DEBUG, "Watching " + m_options.conf_filename +"\n");
for (const auto &rule : m_state->config->m_rules_filenames) {
wd = inotify_add_watch(inot_fd, rule.c_str(), IN_CLOSE_WRITE);
if (wd == -1)
{
ret.success = false;
ret.errstr = std::string("Failed to watch rule file: ") + rule;
ret.proceed = false;
return ret;
}
falco_logger::log(LOG_DEBUG, "Watching " + rule +"\n");
}
}
return ret;
}
bool application::unregister_signal_handlers(std::string &errstr)
{
run_result ret;
close(inot_fd);
if(! create_handler(SIGINT, SIG_DFL, ret) ||
! create_handler(SIGTERM, SIG_DFL, ret) ||
! create_handler(SIGUSR1, SIG_DFL, ret) ||

View File

@ -22,7 +22,7 @@ application::run_result application::load_config()
{
run_result ret;
if (m_options.conf_filename.size())
if (!m_options.conf_filename.empty())
{
m_state->config->init(m_options.conf_filename, m_options.cmdline_config_options);
falco_logger::set_time_format_iso_8601(m_state->config->m_time_format_iso_8601);

View File

@ -72,12 +72,12 @@ application::run_result application::load_rules_files()
string all_rules;
if (m_options.rules_filenames.size())
if (!m_options.rules_filenames.empty())
{
m_state->config->m_rules_filenames = m_options.rules_filenames;
}
if(m_state->config->m_rules_filenames.size() == 0)
if(m_state->config->m_rules_filenames.empty())
{
ret.success = false;
ret.errstr = "You must specify at least one rules file/directory via -r or a rules_file entry in falco.yaml";

View File

@ -181,6 +181,7 @@ void cmdline_options::define()
#endif
("M", "Stop collecting after <num_seconds> reached.", cxxopts::value(duration_to_tot)->default_value("0"), "<num_seconds>")
("markdown", "When used with --list/--list-syscall-events, print the content in Markdown format", cxxopts::value<bool>(markdown))
("monitor_files", "Monitor rules and config files to reload Falco on change.", cxxopts::value<bool>(monitor_files))
("N", "When used with --list, only print field names.", cxxopts::value(names_only)->default_value("false"))
("o,option", "Set the value of option <opt> to <val>. Overrides values in configuration file. <opt> can be identified using its location in configuration file using dot notation. Elements which are entries of lists can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "<opt>=<val>")
("p,print", "Add additional information to each falco notification's output.\nWith -pc or -pcontainer will use a container-friendly format.\nWith -pk or -pkubernetes will use a kubernetes-friendly format.\nWith -pm or -pmesos will use a mesos-friendly format.\nAdditionally, specifying -pc/-pk/-pm will change the interpretation of %container.info in rule output fields.", cxxopts::value(print_additional), "<output_format>")

View File

@ -35,6 +35,7 @@ public:
// Each of these maps directly to a command line option.
bool help;
std::string conf_filename;
bool monitor_files;
bool all_events;
sinsp_evt::param_fmt event_buffer_format;
std::vector<std::string> cri_socket_paths;

View File

@ -138,6 +138,7 @@ bool application::run(std::string &errstr, bool &restart)
std::bind(&application::print_ignored_events, this),
std::bind(&application::print_support, this),
std::bind(&application::validate_rules_files, this),
std::bind(&application::attach_inotify_signals, this),
std::bind(&application::daemonize, this),
std::bind(&application::init_outputs, this),
std::bind(&application::open_inspector, this),

View File

@ -125,6 +125,7 @@ private:
// These methods comprise the code the application "runs". The
// order in which the methods run is in application.cpp.
run_result create_signal_handlers();
run_result attach_inotify_signals();
run_result daemonize();
run_result init_falco_engine();
run_result init_inspector();