chore: format json_evt in preparation to add fields

Signed-off-by: Lorenzo Fontana <lo@linux.com>

Co-authored-by: Leonardo Di Donato <leodidonato@gmail.com>
This commit is contained in:
Lorenzo Fontana 2019-07-08 12:52:36 +00:00 committed by Leo Di Donato
parent 7501c3cb5d
commit bf19d8c881

View File

@ -19,8 +19,8 @@ limitations under the License.
#include <ctype.h> #include <ctype.h>
#include "utils.h"
#include "uri.h" #include "uri.h"
#include "utils.h"
#include "falco_common.h" #include "falco_common.h"
#include "json_evt.h" #include "json_evt.h"
@ -30,7 +30,6 @@ using namespace std;
json_event::json_event() json_event::json_event()
{ {
} }
json_event::~json_event() json_event::~json_event()
@ -60,7 +59,7 @@ std::string json_event_filter_check::def_format(const json &j, std::string &fiel
std::string json_event_filter_check::json_as_string(const json &j) std::string json_event_filter_check::json_as_string(const json &j)
{ {
if (j.type() == json::value_t::string) if(j.type() == json::value_t::string)
{ {
return j; return j;
} }
@ -70,22 +69,24 @@ std::string json_event_filter_check::json_as_string(const json &j)
} }
} }
json_event_filter_check::field_info::field_info() json_event_filter_check::field_info::field_info():
: m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC) m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
{ {
} }
json_event_filter_check::field_info::field_info(std::string name, json_event_filter_check::field_info::field_info(std::string name,
std::string desc) std::string desc):
: m_name(name), m_desc(desc), m_name(name),
m_desc(desc),
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC) m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
{ {
} }
json_event_filter_check::field_info::field_info(std::string name, json_event_filter_check::field_info::field_info(std::string name,
std::string desc, std::string desc,
index_mode mode) index_mode mode):
: m_name(name), m_desc(desc), m_name(name),
m_desc(desc),
m_idx_mode(mode), m_idx_type(IDX_NUMERIC) m_idx_mode(mode), m_idx_type(IDX_NUMERIC)
{ {
} }
@ -93,8 +94,9 @@ json_event_filter_check::field_info::field_info(std::string name,
json_event_filter_check::field_info::field_info(std::string name, json_event_filter_check::field_info::field_info(std::string name,
std::string desc, std::string desc,
index_mode mode, index_mode mode,
index_type itype) index_type itype):
: m_name(name), m_desc(desc), m_name(name),
m_desc(desc),
m_idx_mode(mode), m_idx_type(itype) m_idx_mode(mode), m_idx_type(itype)
{ {
} }
@ -107,14 +109,15 @@ json_event_filter_check::alias::alias()
{ {
} }
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr) json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr):
: m_jptr(ptr), m_format(def_format) m_jptr(ptr), m_format(def_format)
{ {
} }
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr, json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr,
format_t format) format_t format):
: m_jptr(ptr), m_format(format) m_jptr(ptr),
m_format(format)
{ {
} }
@ -122,8 +125,8 @@ json_event_filter_check::alias::~alias()
{ {
} }
json_event_filter_check::json_event_filter_check() json_event_filter_check::json_event_filter_check():
: m_format(def_format) m_format(def_format)
{ {
} }
@ -150,7 +153,7 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
// What follows the match must not be alphanumeric or a dot // What follows the match must not be alphanumeric or a dot
if(strncmp(info.m_name.c_str(), str, info.m_name.size()) == 0 && if(strncmp(info.m_name.c_str(), str, info.m_name.size()) == 0 &&
!isalnum((int) str[info.m_name.size()]) && !isalnum((int)str[info.m_name.size()]) &&
str[info.m_name.size()] != '.' && str[info.m_name.size()] != '.' &&
info.m_name.size() > match_len) info.m_name.size() > match_len)
{ {
@ -169,7 +172,7 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
if(end != NULL) if(end != NULL)
{ {
m_idx = string(start, end-start); m_idx = string(start, end - start);
} }
idx_len = (end - start + 2); idx_len = (end - start + 2);
@ -197,14 +200,14 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
return match_len + idx_len; return match_len + idx_len;
} }
void json_event_filter_check::add_filter_value(const char* str, uint32_t len, uint32_t i) void json_event_filter_check::add_filter_value(const char *str, uint32_t len, uint32_t i)
{ {
m_values.push_back(string(str)); m_values.push_back(string(str));
} }
bool json_event_filter_check::compare(gen_event *evt) bool json_event_filter_check::compare(gen_event *evt)
{ {
json_event *jevt = (json_event *) evt; json_event *jevt = (json_event *)evt;
std::string value = extract(jevt); std::string value = extract(jevt);
@ -225,7 +228,7 @@ bool json_event_filter_check::compare(gen_event *evt)
case CO_IN: case CO_IN:
for(auto &val : m_values) for(auto &val : m_values)
{ {
if (value == val) if(value == val)
{ {
return true; return true;
} }
@ -268,11 +271,12 @@ json_event_filter_check::check_info &json_event_filter_check::get_fields()
return m_info; return m_info;
} }
uint8_t* json_event_filter_check::extract(gen_event *evt, uint32_t* len, bool sanitize_strings) uint8_t *json_event_filter_check::extract(gen_event *evt, uint32_t *len, bool sanitize_strings)
{ {
json_event *jevt = (json_event *) evt; json_event *jevt = (json_event *)evt;
try { try
{
const json &j = jevt->jevt().at(m_jptr); const json &j = jevt->jevt().at(m_jptr);
// Only format when the value was actually found in // Only format when the value was actually found in
@ -286,7 +290,7 @@ uint8_t* json_event_filter_check::extract(gen_event *evt, uint32_t* len, bool sa
*len = m_tstr.size(); *len = m_tstr.size();
return (uint8_t *) m_tstr.c_str(); return (uint8_t *)m_tstr.c_str();
} }
std::string json_event_filter_check::extract(json_event *evt) std::string json_event_filter_check::extract(json_event *evt)
@ -299,7 +303,7 @@ std::string json_event_filter_check::extract(json_event *evt)
if(res != NULL) if(res != NULL)
{ {
ret.assign((const char *) res, len); ret.assign((const char *)res, len);
} }
return ret; return ret;
@ -315,18 +319,15 @@ jevt_filter_check::jevt_filter_check()
{ {
m_info = {"jevt", m_info = {"jevt",
"generic ways to access json events", "generic ways to access json events",
{ {{s_jevt_time_field, "json event timestamp as a string that includes the nanosecond part"},
{s_jevt_time_field, "json event timestamp as a string that includes the nanosecond part"},
{s_jevt_time_iso_8601_field, "json event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)"}, {s_jevt_time_iso_8601_field, "json event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)"},
{s_jevt_rawtime_field, "absolute event timestamp, i.e. nanoseconds from epoch."}, {s_jevt_rawtime_field, "absolute event timestamp, i.e. nanoseconds from epoch."},
{s_jevt_value_field, "General way to access single property from json object. The syntax is [<json pointer expression>]. The property is returned as a string", IDX_REQUIRED, IDX_KEY}, {s_jevt_value_field, "General way to access single property from json object. The syntax is [<json pointer expression>]. The property is returned as a string", IDX_REQUIRED, IDX_KEY},
{s_jevt_obj_field, "The entire json object, stringified"} {s_jevt_obj_field, "The entire json object, stringified"}}};
}};
} }
jevt_filter_check::~jevt_filter_check() jevt_filter_check::~jevt_filter_check()
{ {
} }
int32_t jevt_filter_check::parse_field_name(const char *str, bool alloc_state, bool needed_for_filtering) int32_t jevt_filter_check::parse_field_name(const char *str, bool alloc_state, bool needed_for_filtering)
@ -360,55 +361,56 @@ int32_t jevt_filter_check::parse_field_name(const char *str, bool alloc_state, b
const char *end; const char *end;
// What follows must be [<json pointer expression>] // What follows must be [<json pointer expression>]
if (*(str + s_jevt_value_field.size()) != '[' || if(*(str + s_jevt_value_field.size()) != '[' ||
((end = strchr(str + 1, ']')) == NULL)) ((end = strchr(str + 1, ']')) == NULL))
{ {
throw falco_exception(string("Could not parse filtercheck field \"") + str + "\". Did not have expected format with 'jevt.value[<json pointer>]'"); throw falco_exception(string("Could not parse filtercheck field \"") + str + "\". Did not have expected format with 'jevt.value[<json pointer>]'");
} }
try { try
m_jptr = json::json_pointer(string(str + (s_jevt_value_field.size()+1), (end-str-(s_jevt_value_field.size()+1)))); {
m_jptr = json::json_pointer(string(str + (s_jevt_value_field.size() + 1), (end - str - (s_jevt_value_field.size() + 1))));
} }
catch (json::parse_error& e) catch(json::parse_error &e)
{ {
throw falco_exception(string("Could not parse filtercheck field \"") + str + "\". Invalid json selector (" + e.what() + ")"); throw falco_exception(string("Could not parse filtercheck field \"") + str + "\". Invalid json selector (" + e.what() + ")");
} }
// The +1 accounts for the closing ']' // The +1 accounts for the closing ']'
m_field = string(str, end-str + 1); m_field = string(str, end - str + 1);
return (end - str + 1); return (end - str + 1);
} }
return 0; return 0;
} }
uint8_t* jevt_filter_check::extract(gen_event *evt, uint32_t* len, bool sanitize_stings) uint8_t *jevt_filter_check::extract(gen_event *evt, uint32_t *len, bool sanitize_stings)
{ {
if(m_field == s_jevt_rawtime_field) if(m_field == s_jevt_rawtime_field)
{ {
m_tstr = to_string(evt->get_ts()); m_tstr = to_string(evt->get_ts());
*len = m_tstr.size(); *len = m_tstr.size();
return (uint8_t *) m_tstr.c_str(); return (uint8_t *)m_tstr.c_str();
} }
else if(m_field == s_jevt_time_field) else if(m_field == s_jevt_time_field)
{ {
sinsp_utils::ts_to_string(evt->get_ts(), &m_tstr, false, true); sinsp_utils::ts_to_string(evt->get_ts(), &m_tstr, false, true);
*len = m_tstr.size(); *len = m_tstr.size();
return (uint8_t *) m_tstr.c_str(); return (uint8_t *)m_tstr.c_str();
} }
else if(m_field == s_jevt_time_iso_8601_field) else if(m_field == s_jevt_time_iso_8601_field)
{ {
sinsp_utils::ts_to_iso_8601(evt->get_ts(), &m_tstr); sinsp_utils::ts_to_iso_8601(evt->get_ts(), &m_tstr);
*len = m_tstr.size(); *len = m_tstr.size();
return (uint8_t *) m_tstr.c_str(); return (uint8_t *)m_tstr.c_str();
} }
else if(m_field == s_jevt_obj_field) else if(m_field == s_jevt_obj_field)
{ {
json_event *jevt = (json_event *) evt; json_event *jevt = (json_event *)evt;
m_tstr = jevt->jevt().dump(); m_tstr = jevt->jevt().dump();
*len = m_tstr.size(); *len = m_tstr.size();
return (uint8_t *) m_tstr.c_str(); return (uint8_t *)m_tstr.c_str();
} }
return json_event_filter_check::extract(evt, len, sanitize_stings); return json_event_filter_check::extract(evt, len, sanitize_stings);
@ -418,7 +420,7 @@ json_event_filter_check *jevt_filter_check::allocate_new()
{ {
jevt_filter_check *chk = new jevt_filter_check(); jevt_filter_check *chk = new jevt_filter_check();
return (json_event_filter_check *) chk; return (json_event_filter_check *)chk;
} }
std::string k8s_audit_filter_check::index_image(const json &j, std::string &field, std::string &idx) std::string k8s_audit_filter_check::index_image(const json &j, std::string &field, std::string &idx)
@ -427,7 +429,8 @@ std::string k8s_audit_filter_check::index_image(const json &j, std::string &fiel
string image; string image;
try { try
{
image = j[idx_num].at("image"); image = j[idx_num].at("image");
} }
catch(json::out_of_range &e) catch(json::out_of_range &e)
@ -470,7 +473,6 @@ std::string k8s_audit_filter_check::index_has_name(const json &j, std::string &f
return string("false"); return string("false");
} }
std::string k8s_audit_filter_check::index_query_param(const json &j, std::string &field, std::string &idx) std::string k8s_audit_filter_check::index_query_param(const json &j, std::string &field, std::string &idx)
{ {
string uri = j; string uri = j;
@ -489,7 +491,7 @@ std::string k8s_audit_filter_check::index_query_param(const json &j, std::string
{ {
std::vector<std::string> param_parts = sinsp_split(part, '='); std::vector<std::string> param_parts = sinsp_split(part, '=');
if(param_parts.size() == 2 && uri::decode(param_parts[0], true)==idx) if(param_parts.size() == 2 && uri::decode(param_parts[0], true) == idx)
{ {
return uri::decode(param_parts[1]); return uri::decode(param_parts[1]);
} }
@ -498,7 +500,6 @@ std::string k8s_audit_filter_check::index_query_param(const json &j, std::string
return string("<NA>"); return string("<NA>");
} }
std::string k8s_audit_filter_check::index_generic(const json &j, std::string &field, std::string &idx) std::string k8s_audit_filter_check::index_generic(const json &j, std::string &field, std::string &idx)
{ {
json item; json item;
@ -511,7 +512,8 @@ std::string k8s_audit_filter_check::index_generic(const json &j, std::string &fi
{ {
uint64_t idx_num = (idx.empty() ? 0 : stoi(idx)); uint64_t idx_num = (idx.empty() ? 0 : stoi(idx));
try { try
{
item = j[idx_num]; item = j[idx_num];
} }
catch(json::out_of_range &e) catch(json::out_of_range &e)
@ -529,7 +531,7 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
// Use the suffix of the field to determine which property to // Use the suffix of the field to determine which property to
// select from each object. // select from each object.
std::string prop = field.substr(field.find_last_of(".")+1); std::string prop = field.substr(field.find_last_of(".") + 1);
std::string ret; std::string ret;
@ -542,7 +544,8 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
ret += " "; ret += " ";
} }
try { try
{
ret += json_event_filter_check::json_as_string(obj.at(prop)); ret += json_event_filter_check::json_as_string(obj.at(prop));
} }
catch(json::out_of_range &e) catch(json::out_of_range &e)
@ -553,7 +556,8 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
} }
else else
{ {
try { try
{
ret = j[stoi(idx)].at(prop); ret = j[stoi(idx)].at(prop);
} }
catch(json::out_of_range &e) catch(json::out_of_range &e)
@ -573,7 +577,8 @@ std::string k8s_audit_filter_check::index_privileged(const json &j, std::string
if(!idx.empty()) if(!idx.empty())
{ {
try { try
{
privileged = j[stoi(idx)].at(jpriv); privileged = j[stoi(idx)].at(jpriv);
} }
catch(json::out_of_range &e) catch(json::out_of_range &e)
@ -584,7 +589,8 @@ std::string k8s_audit_filter_check::index_privileged(const json &j, std::string
{ {
for(auto &container : j) for(auto &container : j)
{ {
try { try
{
if(container.at(jpriv)) if(container.at(jpriv))
{ {
privileged = true; privileged = true;
@ -621,8 +627,7 @@ k8s_audit_filter_check::k8s_audit_filter_check()
{ {
m_info = {"ka", m_info = {"ka",
"Access K8s Audit Log Events", "Access K8s Audit Log Events",
{ {{"ka.auditid", "The unique id of the audit event"},
{"ka.auditid", "The unique id of the audit event"},
{"ka.stage", "Stage of the request (e.g. RequestReceived, ResponseComplete, etc.)"}, {"ka.stage", "Stage of the request (e.g. RequestReceived, ResponseComplete, etc.)"},
{"ka.auth.decision", "The authorization decision"}, {"ka.auth.decision", "The authorization decision"},
{"ka.auth.reason", "The authorization reason"}, {"ka.auth.reason", "The authorization reason"},
@ -655,8 +660,7 @@ k8s_audit_filter_check::k8s_audit_filter_check()
{"ka.req.volume.hostpath", "If the request object contains volume definitions, whether or not a hostPath volume exists that mounts the specified path from the host (...hostpath[/etc]=true if a volume mounts /etc from the host). The index can be a glob, in which case all volumes are considered to find any path matching the specified glob (...hostpath[/usr/*] would match either /usr/local or /usr/bin)", IDX_REQUIRED, IDX_KEY}, {"ka.req.volume.hostpath", "If the request object contains volume definitions, whether or not a hostPath volume exists that mounts the specified path from the host (...hostpath[/etc]=true if a volume mounts /etc from the host). The index can be a glob, in which case all volumes are considered to find any path matching the specified glob (...hostpath[/usr/*] would match either /usr/local or /usr/bin)", IDX_REQUIRED, IDX_KEY},
{"ka.resp.name", "The response object name"}, {"ka.resp.name", "The response object name"},
{"ka.response.code", "The response code"}, {"ka.response.code", "The response code"},
{"ka.response.reason", "The response reason (usually present only for failures)"} {"ka.response.reason", "The response reason (usually present only for failures)"}}};
}};
{ {
m_aliases = { m_aliases = {
@ -693,21 +697,19 @@ k8s_audit_filter_check::k8s_audit_filter_check()
{"ka.req.volume.hostpath", {"/requestObject/spec/volumes"_json_pointer, check_hostpath_vols}}, {"ka.req.volume.hostpath", {"/requestObject/spec/volumes"_json_pointer, check_hostpath_vols}},
{"ka.resp.name", {"/responseObject/metadata/name"_json_pointer}}, {"ka.resp.name", {"/responseObject/metadata/name"_json_pointer}},
{"ka.response.code", {"/responseStatus/code"_json_pointer}}, {"ka.response.code", {"/responseStatus/code"_json_pointer}},
{"ka.response.reason", {"/responseStatus/reason"_json_pointer}} {"ka.response.reason", {"/responseStatus/reason"_json_pointer}}};
};
} }
} }
k8s_audit_filter_check::~k8s_audit_filter_check() k8s_audit_filter_check::~k8s_audit_filter_check()
{ {
} }
json_event_filter_check *k8s_audit_filter_check::allocate_new() json_event_filter_check *k8s_audit_filter_check::allocate_new()
{ {
k8s_audit_filter_check *chk = new k8s_audit_filter_check(); k8s_audit_filter_check *chk = new k8s_audit_filter_check();
return (json_event_filter_check *) chk; return (json_event_filter_check *)chk;
} }
json_event_filter::json_event_filter() json_event_filter::json_event_filter()
@ -762,8 +764,8 @@ std::list<json_event_filter_check::check_info> &json_event_filter_factory::get_f
return m_info; return m_info;
} }
json_event_formatter::json_event_formatter(json_event_filter_factory &json_factory, std::string &format) json_event_formatter::json_event_formatter(json_event_filter_factory &json_factory, std::string &format):
: m_format(format), m_format(format),
m_json_factory(json_factory) m_json_factory(json_factory)
{ {
parse_format(); parse_format();
@ -777,7 +779,7 @@ std::string json_event_formatter::tostring(json_event *ev)
{ {
std::string ret; std::string ret;
std::list<std::pair<std::string,std::string>> resolved; std::list<std::pair<std::string, std::string>> resolved;
resolve_tokens(ev, resolved); resolve_tokens(ev, resolved);
@ -793,7 +795,7 @@ std::string json_event_formatter::tojson(json_event *ev)
{ {
nlohmann::json ret; nlohmann::json ret;
std::list<std::pair<std::string,std::string>> resolved; std::list<std::pair<std::string, std::string>> resolved;
resolve_tokens(ev, resolved); resolve_tokens(ev, resolved);
@ -828,11 +830,11 @@ void json_event_formatter::parse_format()
{ {
// Skip the % // Skip the %
tformat.erase(0, 1); tformat.erase(0, 1);
json_event_filter_check *chk = (json_event_filter_check *) m_json_factory.new_filtercheck(tformat.c_str()); json_event_filter_check *chk = (json_event_filter_check *)m_json_factory.new_filtercheck(tformat.c_str());
if(!chk) if(!chk)
{ {
throw falco_exception(string ("Could not parse format string \"") + m_format + "\": unknown filtercheck field " + tformat); throw falco_exception(string("Could not parse format string \"") + m_format + "\": unknown filtercheck field " + tformat);
} }
size = chk->parsed_size(); size = chk->parsed_size();
@ -852,7 +854,7 @@ void json_event_formatter::parse_format()
// Empty fields are only allowed at the beginning of the string // Empty fields are only allowed at the beginning of the string
if(m_tokens.size() > 0) if(m_tokens.size() > 0)
{ {
throw falco_exception(string ("Could not parse format string \"" + m_format + "\": empty filtercheck field")); throw falco_exception(string("Could not parse format string \"" + m_format + "\": empty filtercheck field"));
} }
continue; continue;
} }
@ -864,7 +866,7 @@ void json_event_formatter::parse_format()
} }
} }
void json_event_formatter::resolve_tokens(json_event *ev, std::list<std::pair<std::string,std::string>> &resolved) void json_event_formatter::resolve_tokens(json_event *ev, std::list<std::pair<std::string, std::string>> &resolved)
{ {
for(auto tok : m_tokens) for(auto tok : m_tokens)
{ {