mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-20 11:42:06 +00:00
Compare commits
20 Commits
update/cli
...
caniszczyk
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75f967d5c0 | ||
|
|
6a352338e3 | ||
|
|
f8b66d051b | ||
|
|
c237ddc738 | ||
|
|
9d31164a71 | ||
|
|
f433b449d9 | ||
|
|
44955004e3 | ||
|
|
a9dac551b8 | ||
|
|
df8e4e0545 | ||
|
|
321da3e5bf | ||
|
|
4b34b83739 | ||
|
|
5b558cd600 | ||
|
|
3b7401c2e5 | ||
|
|
aea12f4f3b | ||
|
|
f2637c8600 | ||
|
|
0a14d34e16 | ||
|
|
a1bdf3ed61 | ||
|
|
d3c41c2d97 | ||
|
|
90d71a8e92 | ||
|
|
8eb7d83ee8 |
67
.github/workflows/codeql-analysis.yml
vendored
Normal file
67
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '28 10 * * 6'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp', 'python' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
17
falco.yaml
17
falco.yaml
@@ -87,6 +87,23 @@ syscall_event_drops:
|
||||
rate: .03333
|
||||
max_burst: 10
|
||||
|
||||
# Falco continuously monitors outputs performance. When an output channel does not allow
|
||||
# to deliver an alert within a given deadline, an error is reported indicating
|
||||
# which output is blocking notifications.
|
||||
# The timeout error will be reported to the log according to the above log_* settings.
|
||||
# Note that the notification will not be discarded from the output queue; thus,
|
||||
# output channels may indefinitely remain blocked.
|
||||
# An output timeout error indeed indicate a misconfiguration issue or I/O problems
|
||||
# that cannot be recovered by Falco and should be fixed by the user.
|
||||
#
|
||||
# The "output_timeout" value specifies the duration in milliseconds to wait before
|
||||
# considering the deadline exceed.
|
||||
#
|
||||
# With a 2000ms default, the notification consumer can block the Falco output
|
||||
# for up to 2 seconds without reaching the timeout.
|
||||
|
||||
output_timeout: 2000
|
||||
|
||||
# A throttling mechanism implemented as a token bucket limits the
|
||||
# rate of falco notifications. This throttling is controlled by the following configuration
|
||||
# options:
|
||||
|
||||
@@ -176,6 +176,8 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
|
||||
falco_logger::set_level(m_log_level);
|
||||
|
||||
m_output_timeout = m_config->get_scalar<uint32_t>("output_timeout", 2000);
|
||||
|
||||
m_notifications_rate = m_config->get_scalar<uint32_t>("outputs", "rate", 1);
|
||||
m_notifications_max_burst = m_config->get_scalar<uint32_t>("outputs", "max_burst", 1000);
|
||||
|
||||
|
||||
@@ -204,6 +204,7 @@ public:
|
||||
|
||||
bool m_buffered_outputs;
|
||||
bool m_time_format_iso_8601;
|
||||
uint32_t m_output_timeout;
|
||||
|
||||
bool m_grpc_enabled;
|
||||
uint32_t m_grpc_threadiness;
|
||||
|
||||
@@ -972,6 +972,7 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
outputs->init(config.m_json_output,
|
||||
config.m_json_include_output_property,
|
||||
config.m_output_timeout,
|
||||
config.m_notifications_rate, config.m_notifications_max_burst,
|
||||
config.m_buffered_outputs,
|
||||
config.m_time_format_iso_8601,
|
||||
|
||||
@@ -24,6 +24,7 @@ limitations under the License.
|
||||
|
||||
#include "formats.h"
|
||||
#include "logger.h"
|
||||
#include "watchdog.h"
|
||||
|
||||
#include "outputs_file.h"
|
||||
#include "outputs_program.h"
|
||||
@@ -51,18 +52,26 @@ falco_outputs::~falco_outputs()
|
||||
{
|
||||
if(m_initialized)
|
||||
{
|
||||
for(auto it = m_outputs.cbegin(); it != m_outputs.cend(); ++it)
|
||||
this->stop_worker();
|
||||
for(auto o : m_outputs)
|
||||
{
|
||||
(*it)->cleanup();
|
||||
delete o;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void falco_outputs::init(bool json_output,
|
||||
bool json_include_output_property,
|
||||
uint32_t rate, uint32_t max_burst, bool buffered,
|
||||
bool time_format_iso_8601, string hostname)
|
||||
bool json_include_output_property,
|
||||
uint32_t timeout,
|
||||
uint32_t rate, uint32_t max_burst, bool buffered,
|
||||
bool time_format_iso_8601, std::string hostname)
|
||||
{
|
||||
// Cannot be initialized more than one time.
|
||||
if(m_initialized)
|
||||
{
|
||||
throw falco_exception("falco_outputs already initialized");
|
||||
}
|
||||
|
||||
m_json_output = json_output;
|
||||
|
||||
// Note that falco_formats is already initialized by the engine,
|
||||
@@ -71,17 +80,29 @@ void falco_outputs::init(bool json_output,
|
||||
falco_formats::s_json_output = json_output;
|
||||
falco_formats::s_json_include_output_property = json_include_output_property;
|
||||
|
||||
m_timeout = std::chrono::milliseconds(timeout);
|
||||
|
||||
m_notifications_tb.init(rate, max_burst);
|
||||
|
||||
m_buffered = buffered;
|
||||
m_time_format_iso_8601 = time_format_iso_8601;
|
||||
m_hostname = hostname;
|
||||
|
||||
m_worker_thread = std::thread(&falco_outputs::worker, this);
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
// This function has to be called after init() since some configuration settings
|
||||
// need to be passed to the output plugins. Then, although the worker has started,
|
||||
// the worker is still on hold, waiting for a message.
|
||||
// Thus it is still safe to call add_output() before any message has been enqueued.
|
||||
void falco_outputs::add_output(falco::outputs::config oc)
|
||||
{
|
||||
if(!m_initialized)
|
||||
{
|
||||
throw falco_exception("cannot add output: falco_outputs not initialized yet");
|
||||
}
|
||||
|
||||
falco::outputs::abstract_output *oo;
|
||||
|
||||
@@ -129,6 +150,12 @@ void falco_outputs::handle_event(gen_event *evt, string &rule, string &source,
|
||||
return;
|
||||
}
|
||||
|
||||
falco_outputs::ctrl_msg cmsg = {};
|
||||
cmsg.ts = evt->get_ts();
|
||||
cmsg.priority = priority;
|
||||
cmsg.source = source;
|
||||
cmsg.rule = rule;
|
||||
|
||||
string sformat;
|
||||
if(source == "syscall")
|
||||
{
|
||||
@@ -163,35 +190,38 @@ void falco_outputs::handle_event(gen_event *evt, string &rule, string &source,
|
||||
sformat += " " + format;
|
||||
}
|
||||
|
||||
string msg;
|
||||
msg = falco_formats::format_event(evt, rule, source, falco_common::priority_names[priority], sformat);
|
||||
cmsg.msg = falco_formats::format_event(evt, rule, source, falco_common::priority_names[priority], sformat);
|
||||
cmsg.fields = falco_formats::resolve_tokens(evt, source, sformat);
|
||||
|
||||
for(auto it = m_outputs.cbegin(); it != m_outputs.cend(); ++it)
|
||||
{
|
||||
(*it)->output_event(evt, rule, source, priority, sformat, msg);
|
||||
}
|
||||
cmsg.type = ctrl_msg_type::CTRL_MSG_OUTPUT;
|
||||
m_queue.push(cmsg);
|
||||
}
|
||||
|
||||
void falco_outputs::handle_msg(uint64_t now,
|
||||
void falco_outputs::handle_msg(uint64_t ts,
|
||||
falco_common::priority_type priority,
|
||||
std::string &msg,
|
||||
std::string &rule,
|
||||
std::map<std::string, std::string> &output_fields)
|
||||
{
|
||||
std::string full_msg;
|
||||
falco_outputs::ctrl_msg cmsg = {};
|
||||
cmsg.ts = ts;
|
||||
cmsg.priority = priority;
|
||||
cmsg.source = "internal";
|
||||
cmsg.rule = rule;
|
||||
cmsg.fields = output_fields;
|
||||
|
||||
if(m_json_output)
|
||||
{
|
||||
nlohmann::json jmsg;
|
||||
|
||||
// Convert the time-as-nanoseconds to a more json-friendly ISO8601.
|
||||
time_t evttime = now / 1000000000;
|
||||
time_t evttime = ts / 1000000000;
|
||||
char time_sec[20]; // sizeof "YYYY-MM-DDTHH:MM:SS"
|
||||
char time_ns[12]; // sizeof ".sssssssssZ"
|
||||
string iso8601evttime;
|
||||
|
||||
strftime(time_sec, sizeof(time_sec), "%FT%T", gmtime(&evttime));
|
||||
snprintf(time_ns, sizeof(time_ns), ".%09luZ", now % 1000000000);
|
||||
snprintf(time_ns, sizeof(time_ns), ".%09luZ", ts % 1000000000);
|
||||
iso8601evttime = time_sec;
|
||||
iso8601evttime += time_ns;
|
||||
|
||||
@@ -201,15 +231,15 @@ void falco_outputs::handle_msg(uint64_t now,
|
||||
jmsg["time"] = iso8601evttime;
|
||||
jmsg["output_fields"] = output_fields;
|
||||
|
||||
full_msg = jmsg.dump();
|
||||
cmsg.msg = jmsg.dump();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string timestr;
|
||||
bool first = true;
|
||||
|
||||
sinsp_utils::ts_to_string(now, ×tr, false, true);
|
||||
full_msg = timestr + ": " + falco_common::priority_names[priority] + " " + msg + " (";
|
||||
sinsp_utils::ts_to_string(ts, ×tr, false, true);
|
||||
cmsg.msg = timestr + ": " + falco_common::priority_names[priority] + " " + msg + " (";
|
||||
for(auto &pair : output_fields)
|
||||
{
|
||||
if(first)
|
||||
@@ -218,23 +248,95 @@ void falco_outputs::handle_msg(uint64_t now,
|
||||
}
|
||||
else
|
||||
{
|
||||
full_msg += " ";
|
||||
cmsg.msg += " ";
|
||||
}
|
||||
full_msg += pair.first + "=" + pair.second;
|
||||
cmsg.msg += pair.first + "=" + pair.second;
|
||||
}
|
||||
full_msg += ")";
|
||||
cmsg.msg += ")";
|
||||
}
|
||||
|
||||
for(auto it = m_outputs.cbegin(); it != m_outputs.cend(); ++it)
|
||||
{
|
||||
(*it)->output_msg(priority, full_msg);
|
||||
}
|
||||
cmsg.type = ctrl_msg_type::CTRL_MSG_OUTPUT;
|
||||
m_queue.push(cmsg);
|
||||
}
|
||||
|
||||
void falco_outputs::cleanup_outputs()
|
||||
{
|
||||
this->push(falco_outputs::ctrl_msg_type::CTRL_MSG_CLEANUP);
|
||||
}
|
||||
|
||||
void falco_outputs::reopen_outputs()
|
||||
{
|
||||
for(auto it = m_outputs.cbegin(); it != m_outputs.cend(); ++it)
|
||||
this->push(falco_outputs::ctrl_msg_type::CTRL_MSG_REOPEN);
|
||||
}
|
||||
|
||||
void falco_outputs::stop_worker()
|
||||
{
|
||||
watchdog<void *> wd;
|
||||
wd.start([&](void *) -> void {
|
||||
falco_logger::log(LOG_NOTICE, "output channels still blocked, discarding all remaining notifications\n");
|
||||
m_queue.clear();
|
||||
this->push(falco_outputs::ctrl_msg_type::CTRL_MSG_STOP);
|
||||
});
|
||||
wd.set_timeout(m_timeout, nullptr);
|
||||
|
||||
this->push(falco_outputs::ctrl_msg_type::CTRL_MSG_STOP);
|
||||
if(m_worker_thread.joinable())
|
||||
{
|
||||
(*it)->reopen();
|
||||
m_worker_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
inline void falco_outputs::push(ctrl_msg_type cmt)
|
||||
{
|
||||
falco_outputs::ctrl_msg cmsg = {};
|
||||
cmsg.type = cmt;
|
||||
m_queue.push(cmsg);
|
||||
}
|
||||
|
||||
// todo(leogr,leodido): this function is not supposed to throw exceptions, and with "noexcept",
|
||||
// the program is terminated if that occurs. Although that's the wanted behavior,
|
||||
// we still need to improve the error reporting since some inner functions can throw exceptions.
|
||||
void falco_outputs::worker() noexcept
|
||||
{
|
||||
watchdog<std::string> wd;
|
||||
wd.start([&](std::string payload) -> void {
|
||||
falco_logger::log(LOG_CRIT, "\"" + payload + "\" output timeout, all output channels are blocked\n");
|
||||
});
|
||||
|
||||
auto timeout = m_timeout;
|
||||
|
||||
falco_outputs::ctrl_msg cmsg;
|
||||
do
|
||||
{
|
||||
// Block until a message becomes available.
|
||||
m_queue.pop(cmsg);
|
||||
|
||||
for(const auto o : m_outputs)
|
||||
{
|
||||
wd.set_timeout(timeout, o->get_name());
|
||||
try
|
||||
{
|
||||
switch(cmsg.type)
|
||||
{
|
||||
case ctrl_msg_type::CTRL_MSG_OUTPUT:
|
||||
o->output(&cmsg);
|
||||
break;
|
||||
case ctrl_msg_type::CTRL_MSG_CLEANUP:
|
||||
case ctrl_msg_type::CTRL_MSG_STOP:
|
||||
o->cleanup();
|
||||
break;
|
||||
case ctrl_msg_type::CTRL_MSG_REOPEN:
|
||||
o->reopen();
|
||||
break;
|
||||
default:
|
||||
falco_logger::log(LOG_DEBUG, "Outputs worker received an unknown message type\n");
|
||||
}
|
||||
}
|
||||
catch(const exception &e)
|
||||
{
|
||||
falco_logger::log(LOG_ERR, o->get_name() + ": " + string(e.what()) + "\n");
|
||||
}
|
||||
}
|
||||
wd.cancel_timeout();
|
||||
} while(cmsg.type != ctrl_msg_type::CTRL_MSG_STOP);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ limitations under the License.
|
||||
#include "token_bucket.h"
|
||||
#include "falco_engine.h"
|
||||
#include "outputs.h"
|
||||
#include "tbb/concurrent_queue.h"
|
||||
|
||||
//
|
||||
// This class acts as the primary interface between a program and the
|
||||
@@ -39,25 +40,25 @@ public:
|
||||
|
||||
void init(bool json_output,
|
||||
bool json_include_output_property,
|
||||
uint32_t timeout,
|
||||
uint32_t rate, uint32_t max_burst, bool buffered,
|
||||
bool time_format_iso_8601, std::string hostname);
|
||||
|
||||
void add_output(falco::outputs::config oc);
|
||||
|
||||
//
|
||||
// evt is an event that has matched some rule. Pass the event
|
||||
// to all configured outputs.
|
||||
//
|
||||
// Format then send the event to all configured outputs (`evt` is an event that has matched some rule).
|
||||
void handle_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format);
|
||||
|
||||
// Send a generic message to all outputs. Not necessarily associated with any event.
|
||||
// Format then send a generic message to all outputs. Not necessarily associated with any event.
|
||||
void handle_msg(uint64_t now,
|
||||
falco_common::priority_type priority,
|
||||
std::string &msg,
|
||||
std::string &rule,
|
||||
std::map<std::string, std::string> &output_fields);
|
||||
|
||||
void cleanup_outputs();
|
||||
|
||||
void reopen_outputs();
|
||||
|
||||
private:
|
||||
@@ -71,5 +72,28 @@ private:
|
||||
bool m_buffered;
|
||||
bool m_json_output;
|
||||
bool m_time_format_iso_8601;
|
||||
std::chrono::milliseconds m_timeout;
|
||||
std::string m_hostname;
|
||||
|
||||
enum ctrl_msg_type
|
||||
{
|
||||
CTRL_MSG_STOP = 0,
|
||||
CTRL_MSG_OUTPUT = 1,
|
||||
CTRL_MSG_CLEANUP = 2,
|
||||
CTRL_MSG_REOPEN = 3,
|
||||
};
|
||||
|
||||
struct ctrl_msg : falco::outputs::message
|
||||
{
|
||||
ctrl_msg_type type;
|
||||
};
|
||||
|
||||
typedef tbb::concurrent_bounded_queue<ctrl_msg> falco_outputs_cbq;
|
||||
|
||||
falco_outputs_cbq m_queue;
|
||||
|
||||
std::thread m_worker_thread;
|
||||
inline void push(ctrl_msg_type cmt);
|
||||
void worker() noexcept;
|
||||
void stop_worker();
|
||||
};
|
||||
|
||||
@@ -37,6 +37,21 @@ struct config
|
||||
std::map<std::string, std::string> options;
|
||||
};
|
||||
|
||||
//
|
||||
// The message to be outputted. It can either refer to:
|
||||
// - an event that has matched some rule,
|
||||
// - or a generic message (e.g., a drop alert).
|
||||
//
|
||||
struct message
|
||||
{
|
||||
uint64_t ts;
|
||||
falco_common::priority_type priority;
|
||||
std::string msg;
|
||||
std::string rule;
|
||||
std::string source;
|
||||
map<std::string, std::string> fields;
|
||||
};
|
||||
|
||||
//
|
||||
// This class acts as the primary interface for implementing
|
||||
// a Falco output class.
|
||||
@@ -45,6 +60,8 @@ struct config
|
||||
class abstract_output
|
||||
{
|
||||
public:
|
||||
virtual ~abstract_output() {}
|
||||
|
||||
void init(config oc, bool buffered, std::string hostname)
|
||||
{
|
||||
m_oc = oc;
|
||||
@@ -52,15 +69,19 @@ public:
|
||||
m_hostname = hostname;
|
||||
}
|
||||
|
||||
// Output an event that has matched some rule.
|
||||
virtual void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg) = 0;
|
||||
// Return the output's name as per its configuration.
|
||||
const std::string get_name() const
|
||||
{
|
||||
return m_oc.name;
|
||||
}
|
||||
|
||||
// Output a generic message. Not necessarily associated with any event.
|
||||
virtual void output_msg(falco_common::priority_type priority, std::string &msg) = 0;
|
||||
// Output a message.
|
||||
virtual void output(const message *msg) = 0;
|
||||
|
||||
// Possibly close the output and open it again.
|
||||
virtual void reopen() {}
|
||||
|
||||
// Possibly flush the output.
|
||||
virtual void cleanup() {}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -31,16 +31,10 @@ void falco::outputs::output_file::open_file()
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_file::output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg)
|
||||
{
|
||||
output_msg(priority, msg);
|
||||
}
|
||||
|
||||
void falco::outputs::output_file::output_msg(falco_common::priority_type priority, std::string &msg)
|
||||
void falco::outputs::output_file::output(const message *msg)
|
||||
{
|
||||
open_file();
|
||||
m_outfile << msg + "\n";
|
||||
m_outfile << msg->msg + "\n";
|
||||
|
||||
if(m_oc.options["keep_alive"] != "true")
|
||||
{
|
||||
|
||||
@@ -27,10 +27,7 @@ namespace outputs
|
||||
|
||||
class output_file : public abstract_output
|
||||
{
|
||||
void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg);
|
||||
|
||||
void output_msg(falco_common::priority_type priority, std::string &msg);
|
||||
void output(const message *msg);
|
||||
|
||||
void cleanup();
|
||||
|
||||
|
||||
@@ -21,44 +21,41 @@ limitations under the License.
|
||||
#include "formats.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_grpc::output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format,
|
||||
std::string &msg)
|
||||
void falco::outputs::output_grpc::output(const message *msg)
|
||||
{
|
||||
falco::outputs::response grpc_res;
|
||||
|
||||
// time
|
||||
auto timestamp = grpc_res.mutable_time();
|
||||
*timestamp = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(evt->get_ts());
|
||||
*timestamp = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(msg->ts);
|
||||
|
||||
// rule
|
||||
auto r = grpc_res.mutable_rule();
|
||||
*r = rule;
|
||||
*r = msg->rule;
|
||||
|
||||
// source
|
||||
falco::schema::source s = falco::schema::source::SYSCALL;
|
||||
if(!falco::schema::source_Parse(source, &s))
|
||||
if(!falco::schema::source_Parse(msg->source, &s))
|
||||
{
|
||||
throw falco_exception("Unknown source passed to output_grpc::output_event()");
|
||||
throw falco_exception("Unknown source passed to output_grpc::output()");
|
||||
}
|
||||
grpc_res.set_source(s);
|
||||
|
||||
// priority
|
||||
falco::schema::priority p = falco::schema::priority::EMERGENCY;
|
||||
if(!falco::schema::priority_Parse(falco_common::priority_names[priority], &p))
|
||||
if(!falco::schema::priority_Parse(falco_common::priority_names[msg->priority], &p))
|
||||
{
|
||||
throw falco_exception("Unknown priority passed to output_grpc::output_event()");
|
||||
throw falco_exception("Unknown priority passed to output_grpc::output()");
|
||||
}
|
||||
grpc_res.set_priority(p);
|
||||
|
||||
// output
|
||||
auto output = grpc_res.mutable_output();
|
||||
*output = msg;
|
||||
*output = msg->msg;
|
||||
|
||||
// output fields
|
||||
auto &fields = *grpc_res.mutable_output_fields();
|
||||
auto resolvedTkns = falco_formats::resolve_tokens(evt, source, format);
|
||||
for(const auto &kv : resolvedTkns)
|
||||
for(const auto &kv : msg->fields)
|
||||
{
|
||||
fields[kv.first] = kv.second;
|
||||
}
|
||||
@@ -68,9 +65,4 @@ void falco::outputs::output_grpc::output_event(gen_event *evt, std::string &rule
|
||||
*host = m_hostname;
|
||||
|
||||
falco::grpc::queue::get().push(grpc_res);
|
||||
}
|
||||
|
||||
void falco::outputs::output_grpc::output_msg(falco_common::priority_type priority, std::string &msg)
|
||||
{
|
||||
// todo(fntlnz, leodido, leogr) > gRPC does not support subscribing to dropped events yet
|
||||
}
|
||||
@@ -25,10 +25,7 @@ namespace outputs
|
||||
|
||||
class output_grpc : public abstract_output
|
||||
{
|
||||
void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg);
|
||||
|
||||
void output_msg(falco_common::priority_type priority, std::string &msg);
|
||||
void output(const message *msg);
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
|
||||
@@ -18,13 +18,7 @@ limitations under the License.
|
||||
#include "logger.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_http::output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg)
|
||||
{
|
||||
output_msg(priority, msg);
|
||||
}
|
||||
|
||||
void falco::outputs::output_http::output_msg(falco_common::priority_type priority, std::string &msg)
|
||||
void falco::outputs::output_http::output(const message *msg)
|
||||
{
|
||||
CURL *curl = NULL;
|
||||
CURLcode res = CURLE_FAILED_INIT;
|
||||
@@ -37,7 +31,7 @@ void falco::outputs::output_http::output_msg(falco_common::priority_type priorit
|
||||
slist1 = curl_slist_append(slist1, "Content-Type: application/json");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist1);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, m_oc.options["url"].c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg->msg.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, -1L);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
@@ -25,10 +25,7 @@ namespace outputs
|
||||
|
||||
class output_http : public abstract_output
|
||||
{
|
||||
void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg);
|
||||
|
||||
void output_msg(falco_common::priority_type priority, std::string &msg);
|
||||
void output(const message *msg);
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
|
||||
@@ -31,17 +31,11 @@ void falco::outputs::output_program::open_pfile()
|
||||
}
|
||||
}
|
||||
|
||||
void falco::outputs::output_program::output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg)
|
||||
{
|
||||
output_msg(priority, msg);
|
||||
}
|
||||
|
||||
void falco::outputs::output_program::output_msg(falco_common::priority_type priority, std::string &msg)
|
||||
void falco::outputs::output_program::output(const message *msg)
|
||||
{
|
||||
open_pfile();
|
||||
|
||||
fprintf(m_pfile, "%s\n", msg.c_str());
|
||||
fprintf(m_pfile, "%s\n", msg->msg.c_str());
|
||||
|
||||
if(m_oc.options["keep_alive"] != "true")
|
||||
{
|
||||
|
||||
@@ -25,10 +25,7 @@ namespace outputs
|
||||
|
||||
class output_program : public abstract_output
|
||||
{
|
||||
void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg);
|
||||
|
||||
void output_msg(falco_common::priority_type priority, std::string &msg);
|
||||
void output(const message *msg);
|
||||
|
||||
void cleanup();
|
||||
|
||||
|
||||
@@ -18,16 +18,10 @@ limitations under the License.
|
||||
#include <iostream>
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_stdout::output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg)
|
||||
{
|
||||
output_msg(priority, msg);
|
||||
}
|
||||
|
||||
void falco::outputs::output_stdout::output_msg(falco_common::priority_type priority, std::string &msg)
|
||||
void falco::outputs::output_stdout::output(const message *msg)
|
||||
{
|
||||
//
|
||||
// By default, the stdout stream is fully buffered or line buffered
|
||||
// By default, the stdout stream is fully buffered or line buffered
|
||||
// (if the stream can be determined to refer to an interactive device, e.g. in a TTY).
|
||||
// Just enable automatic flushing when unbuffered output is desired.
|
||||
// Note that it is set every time since other writings to the stdout can disable it.
|
||||
@@ -36,7 +30,7 @@ void falco::outputs::output_stdout::output_msg(falco_common::priority_type prior
|
||||
{
|
||||
std::cout << std::unitbuf;
|
||||
}
|
||||
std::cout << msg + "\n";
|
||||
std::cout << msg->msg + "\n";
|
||||
}
|
||||
|
||||
void falco::outputs::output_stdout::cleanup()
|
||||
|
||||
@@ -25,10 +25,7 @@ namespace outputs
|
||||
|
||||
class output_stdout : public abstract_output
|
||||
{
|
||||
void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg);
|
||||
|
||||
void output_msg(falco_common::priority_type priority, std::string &msg);
|
||||
void output(const message *msg);
|
||||
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
@@ -18,14 +18,8 @@ limitations under the License.
|
||||
#include <syslog.h>
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
void falco::outputs::output_syslog::output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg)
|
||||
{
|
||||
output_msg(priority, msg);
|
||||
}
|
||||
|
||||
void falco::outputs::output_syslog::output_msg(falco_common::priority_type priority, std::string &msg)
|
||||
void falco::outputs::output_syslog::output(const message *msg)
|
||||
{
|
||||
// Syslog output should not have any trailing newline
|
||||
::syslog(priority, "%s", msg.c_str());
|
||||
::syslog(msg->priority, "%s", msg->msg.c_str());
|
||||
}
|
||||
|
||||
@@ -25,10 +25,7 @@ namespace outputs
|
||||
|
||||
class output_syslog : public abstract_output
|
||||
{
|
||||
void output_event(gen_event *evt, std::string &rule, std::string &source,
|
||||
falco_common::priority_type priority, std::string &format, std::string &msg);
|
||||
|
||||
void output_msg(falco_common::priority_type priority, std::string &msg);
|
||||
void output(const message *msg);
|
||||
};
|
||||
|
||||
} // namespace outputs
|
||||
|
||||
@@ -57,4 +57,7 @@ enum source {
|
||||
k8s_audit = 1;
|
||||
K8s_audit = 1;
|
||||
K8S_audit = 1;
|
||||
INTERNAL = 2;
|
||||
internal = 2;
|
||||
Internal = 2;
|
||||
}
|
||||
|
||||
96
userspace/falco/watchdog.h
Normal file
96
userspace/falco/watchdog.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <atomic>
|
||||
|
||||
template<typename _T>
|
||||
class watchdog
|
||||
{
|
||||
public:
|
||||
watchdog():
|
||||
m_timeout(nullptr),
|
||||
m_is_running(false)
|
||||
{
|
||||
}
|
||||
|
||||
~watchdog()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void start(std::function<void(_T)> cb,
|
||||
std::chrono::milliseconds resolution = std::chrono::milliseconds(100))
|
||||
{
|
||||
stop();
|
||||
m_is_running.store(true, std::memory_order_release);
|
||||
m_thread = std::thread([this, cb, resolution]() {
|
||||
const auto no_deadline = time_point{};
|
||||
timeout_data curr;
|
||||
while(m_is_running.load(std::memory_order_acquire))
|
||||
{
|
||||
auto t = m_timeout.exchange(nullptr, std::memory_order_release);
|
||||
if(t)
|
||||
{
|
||||
curr = *t;
|
||||
delete t;
|
||||
}
|
||||
if(curr.deadline != no_deadline && curr.deadline < std::chrono::steady_clock::now())
|
||||
{
|
||||
cb(curr.payload);
|
||||
curr.deadline = no_deadline;
|
||||
}
|
||||
std::this_thread::sleep_for(resolution);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
if(m_is_running.load(std::memory_order_acquire))
|
||||
{
|
||||
m_is_running.store(false, std::memory_order_release);
|
||||
if(m_thread.joinable())
|
||||
{
|
||||
m_thread.join();
|
||||
}
|
||||
delete m_timeout.exchange(nullptr, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
inline void set_timeout(std::chrono::milliseconds timeout, _T payload) noexcept
|
||||
{
|
||||
delete m_timeout.exchange(new timeout_data{std::chrono::steady_clock::now() + timeout, payload}, std::memory_order_release);
|
||||
}
|
||||
|
||||
inline void cancel_timeout() noexcept
|
||||
{
|
||||
delete m_timeout.exchange(new timeout_data, std::memory_order_release);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::chrono::time_point<std::chrono::steady_clock> time_point;
|
||||
struct timeout_data
|
||||
{
|
||||
time_point deadline;
|
||||
_T payload;
|
||||
};
|
||||
std::atomic<timeout_data *> m_timeout;
|
||||
std::atomic<bool> m_is_running;
|
||||
std::thread m_thread;
|
||||
};
|
||||
Reference in New Issue
Block a user