Add ability to print name/description of rules.

When run with -l <rule>, falco will print the name/description of the
single rule <rule> and exit. With -L, falco will print the
name/description of all rules.

All the work is done in lua in the rule loader. A new lua function
describe_rule calls the local function describe_single_rule once or
multiple times depending on -l/-L. describe_single_rule prints the rule
name and a wrapped version of the rule description.
This commit is contained in:
Mark Stemm
2016-05-13 16:27:36 -07:00
parent e662d1eeeb
commit 7be0454f6f
4 changed files with 98 additions and 2 deletions

View File

@@ -45,6 +45,8 @@ static void usage()
" -p, --pidfile <pid_file> When run as a daemon, write pid to specified file\n"
" -e <events_file> Read the events from <events_file> (in .scap format) instead of tapping into live.\n"
" -r <rules_file> Rules file (defaults to value set in configuration file, or /etc/falco_rules.yaml).\n"
" -L Show the name and description of all rules and exit.\n"
" -l <rule> Show the name and description of the rule with name <rule> and exit.\n"
"\n"
);
}
@@ -217,6 +219,8 @@ int falco_init(int argc, char **argv)
lua_State* ls = NULL;
bool daemon = false;
string pidfilename = "/var/run/falco.pid";
bool describe_all_rules = false;
string describe_rule = "";
static struct option long_options[] =
{
@@ -236,7 +240,7 @@ int falco_init(int argc, char **argv)
// Parse the args
//
while((op = getopt_long(argc, argv,
"c:ho:e:r:dp:",
"c:ho:e:r:dp:Ll:",
long_options, &long_index)) != -1)
{
switch(op)
@@ -262,6 +266,12 @@ int falco_init(int argc, char **argv)
case 'p':
pidfilename = optarg;
break;
case 'L':
describe_all_rules = true;
break;
case 'l':
describe_rule = optarg;
break;
case '?':
result = EXIT_FAILURE;
goto exit;
@@ -359,6 +369,18 @@ int falco_init(int argc, char **argv)
inspector->set_filter(rules->get_filter());
falco_logger::log(LOG_INFO, "Parsed rules from file " + config.m_rules_filename + "\n");
if (describe_all_rules)
{
rules->describe_rule(NULL);
goto exit;
}
if (describe_rule != "")
{
rules->describe_rule(&describe_rule);
goto exit;
}
inspector->set_hostname_and_port_resolution_mode(false);
if (config.m_json_output)

View File

@@ -182,6 +182,54 @@ function load_rules(filename)
io.flush()
end
local rule_fmt = "%-50s %s"
-- http://lua-users.org/wiki/StringRecipes, with simplifications and bugfixes
local function wrap(str, limit, indent)
indent = indent or ""
limit = limit or 72
local here = 1
return str:gsub("(%s+)()(%S+)()",
function(sp, st, word, fi)
if fi-here > limit then
here = st
return "\n"..indent..word
end
end)
end
local function describe_single_rule(name)
if (state.rules_by_name[name] == nil) then
error ("No such rule: "..name)
end
-- Wrap the description into an multiple lines each of length ~ 60
-- chars, with indenting to line up with the first line.
local wrapped = wrap(state.rules_by_name[name]['desc'], 60, string.format(rule_fmt, "", ""))
local line = string.format(rule_fmt, name, wrapped)
print(line)
print()
end
-- If name is nil, describe all rules
function describe_rule(name)
print()
local line = string.format(rule_fmt, "Rule", "Description")
print(line)
line = string.format(rule_fmt, "----", "-----------")
print(line)
if name == nil then
for rulename, rule in pairs(state.rules_by_name) do
describe_single_rule(rulename)
end
else
describe_single_rule(name)
end
end
function on_event(evt_, rule_id)
if state.rules_by_idx[rule_id] == nil then

View File

@@ -89,10 +89,34 @@ void falco_rules::load_rules(string rules_filename)
throw sinsp_exception(err);
}
} else {
throw sinsp_exception("No function " + m_lua_load_rules + " found in lua compiler module");
throw sinsp_exception("No function " + m_lua_load_rules + " found in lua rule module");
}
}
void falco_rules::describe_rule(std::string *rule)
{
lua_getglobal(m_ls, m_lua_describe_rule.c_str());
if(lua_isfunction(m_ls, -1))
{
if (rule == NULL)
{
lua_pushnil(m_ls);
} else {
lua_pushstring(m_ls, rule->c_str());
}
if(lua_pcall(m_ls, 1, 0, 0) != 0)
{
const char* lerr = lua_tostring(m_ls, -1);
string err = "Could not describe " + (rule == NULL ? "all rules" : "rule " + *rule) + ": " + string(lerr);
throw sinsp_exception(err);
}
} else {
throw sinsp_exception("No function " + m_lua_describe_rule + " found in lua rule module");
}
}
sinsp_filter* falco_rules::get_filter()
{
return m_lua_parser->get_filter();

View File

@@ -9,6 +9,7 @@ class falco_rules
falco_rules(sinsp* inspector, lua_State *ls, string lua_main_filename);
~falco_rules();
void load_rules(string rules_filename);
void describe_rule(string *rule);
sinsp_filter* get_filter();
private:
@@ -22,4 +23,5 @@ class falco_rules
string m_lua_ignored_syscalls = "ignored_syscalls";
string m_lua_ignored_events = "ignored_events";
string m_lua_on_event = "on_event";
string m_lua_describe_rule = "describe_rule";
};