diff --git a/userspace/falco/falco.cpp b/userspace/falco/falco.cpp index 53d009fc..6b92058f 100644 --- a/userspace/falco/falco.cpp +++ b/userspace/falco/falco.cpp @@ -45,6 +45,8 @@ static void usage() " -p, --pidfile When run as a daemon, write pid to specified file\n" " -e Read the events from (in .scap format) instead of tapping into live.\n" " -r 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 Show the name and description of the rule with name 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) diff --git a/userspace/falco/lua/rule_loader.lua b/userspace/falco/lua/rule_loader.lua index e7e9c7c5..f5cc8882 100644 --- a/userspace/falco/lua/rule_loader.lua +++ b/userspace/falco/lua/rule_loader.lua @@ -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 diff --git a/userspace/falco/rules.cpp b/userspace/falco/rules.cpp index 5e3fa45a..dc2b7072 100644 --- a/userspace/falco/rules.cpp +++ b/userspace/falco/rules.cpp @@ -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(); diff --git a/userspace/falco/rules.h b/userspace/falco/rules.h index 0d5655e8..91bf6fa5 100644 --- a/userspace/falco/rules.h +++ b/userspace/falco/rules.h @@ -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"; };