diff --git a/userspace/libsinsp/CMakeLists.txt b/userspace/libsinsp/CMakeLists.txt index 6104603e8a..5d9ebacd9b 100644 --- a/userspace/libsinsp/CMakeLists.txt +++ b/userspace/libsinsp/CMakeLists.txt @@ -87,9 +87,9 @@ add_library(sinsp sinsp_filtercheck_tracer.cpp sinsp_filtercheck_user.cpp sinsp_filtercheck_utils.cpp + filter_compare.cpp filter_check_list.cpp ifinfo.cpp - memmem.cpp metrics_collector.cpp logger.cpp parsers.cpp diff --git a/userspace/libsinsp/filter.cpp b/userspace/libsinsp/filter.cpp index 5c4ee8767f..fa67020281 100644 --- a/userspace/libsinsp/filter.cpp +++ b/userspace/libsinsp/filter.cpp @@ -36,6 +36,7 @@ limitations under the License. #include #include #include +#include /////////////////////////////////////////////////////////////////////////////// // sinsp_filter_expression implementation @@ -304,6 +305,16 @@ void sinsp_filter_compiler::visit(const libsinsp::filter::ast::not_expr* e) m_filter->pop_expression(); } +static inline void check_op_type_compatibility(sinsp_filter_check& c) +{ + std::string err; + auto fi = c.get_transformed_field_info(); + if (fi && !flt_is_comparable(c.m_cmpop, fi->m_type, fi->is_list(), err)) + { + throw sinsp_exception("filter error: " + err); + } +} + void sinsp_filter_compiler::visit(const libsinsp::filter::ast::unary_check_expr* e) { m_pos = e->get_pos(); @@ -317,6 +328,7 @@ void sinsp_filter_compiler::visit(const libsinsp::filter::ast::unary_check_expr* auto check = std::move(m_last_node_field); check->m_cmpop = str_to_cmpop(e->op); check->m_boolop = m_last_boolop; + check_op_type_compatibility(*check); m_filter->add_check(std::move(check)); } @@ -354,6 +366,7 @@ void sinsp_filter_compiler::visit(const libsinsp::filter::ast::binary_check_expr auto check = std::move(m_last_node_field); check->m_cmpop = str_to_cmpop(e->op); check->m_boolop = m_last_boolop; + check_op_type_compatibility(*check); // Read the right-hand values of the filtercheck. m_last_node_field_is_plugin = false; @@ -515,86 +528,6 @@ std::unique_ptr sinsp_filter_compiler::create_filtercheck(st return chk; } -cmpop sinsp_filter_compiler::str_to_cmpop(std::string_view str) -{ - if(str == "=" || str == "==") - { - return CO_EQ; - } - else if(str == "!=") - { - return CO_NE; - } - else if(str == "<=") - { - return CO_LE; - } - else if(str == "<") - { - return CO_LT; - } - else if(str == ">=") - { - return CO_GE; - } - else if(str == ">") - { - return CO_GT; - } - else if(str == "contains") - { - return CO_CONTAINS; - } - else if(str == "icontains") - { - return CO_ICONTAINS; - } - else if(str == "bcontains") - { - return CO_BCONTAINS; - } - else if(str == "startswith") - { - return CO_STARTSWITH; - } - else if(str == "bstartswith") - { - return CO_BSTARTSWITH; - } - else if(str == "endswith") - { - return CO_ENDSWITH; - } - else if(str == "in") - { - return CO_IN; - } - else if(str == "intersects") - { - return CO_INTERSECTS; - } - else if(str == "pmatch") - { - return CO_PMATCH; - } - else if(str == "exists") - { - return CO_EXISTS; - } - else if(str == "glob") - { - return CO_GLOB; - } - else if(str == "iglob") - { - return CO_IGLOB; - } - // we are not supposed to get here, as the parser pre-checks this - ASSERT(false); - throw sinsp_exception("filter error: unrecognized comparison operator '" + std::string(str) + "'"); -} - - sinsp_filter_factory::sinsp_filter_factory(sinsp *inspector, filter_check_list &available_checks) : m_inspector(inspector), m_available_checks(available_checks) diff --git a/userspace/libsinsp/filter.h b/userspace/libsinsp/filter.h index ca2c5b0cb9..e65bc2be01 100644 --- a/userspace/libsinsp/filter.h +++ b/userspace/libsinsp/filter.h @@ -258,7 +258,6 @@ class SINSP_PUBLIC sinsp_filter_compiler: void visit(const libsinsp::filter::ast::binary_check_expr*) override; void visit(const libsinsp::filter::ast::field_expr*) override; void visit(const libsinsp::filter::ast::field_transformer_expr*) override; - cmpop str_to_cmpop(std::string_view); std::string create_filtercheck_name(const std::string& name, const std::string& arg); std::unique_ptr create_filtercheck(std::string_view field); void check_value_and_add_warnings(const libsinsp::filter::ast::pos_info& pos, const std::string& v); diff --git a/userspace/libsinsp/filter_compare.cpp b/userspace/libsinsp/filter_compare.cpp new file mode 100644 index 0000000000..29cc670d02 --- /dev/null +++ b/userspace/libsinsp/filter_compare.cpp @@ -0,0 +1,840 @@ +// SPDX-License-Identifier: Apache-2.0 +/* +Copyright (C) 2024 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 +#include +#include + +#ifdef _WIN32 +#define NOMINMAX +#pragma comment(lib, "Ws2_32.lib") +#include +#include +#else +#include "arpa/inet.h" +#include +#endif + +// +// Fallback implementation of memmem +// +#if !defined(_GNU_SOURCE) && !defined(__APPLE__) +#include + +static inline void *memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen) +{ + const unsigned char *ptr; + const unsigned char *end; + + if(needlelen == 0) + { + return (void *)haystack; + } + + if(haystacklen < needlelen) + { + return NULL; + } + + end = (const unsigned char *)haystack + haystacklen - needlelen; + for(ptr = (const unsigned char *)haystack; ptr <= end; ptr++) + { + if(!memcmp(ptr, needle, needlelen)) + { + return (void *)ptr; + } + } + + return NULL; +} +#endif + +cmpop str_to_cmpop(std::string_view str) +{ + if(str == "=" || str == "==") + { + return CO_EQ; + } + else if(str == "!=") + { + return CO_NE; + } + else if(str == "<=") + { + return CO_LE; + } + else if(str == "<") + { + return CO_LT; + } + else if(str == ">=") + { + return CO_GE; + } + else if(str == ">") + { + return CO_GT; + } + else if(str == "contains") + { + return CO_CONTAINS; + } + else if(str == "icontains") + { + return CO_ICONTAINS; + } + else if(str == "bcontains") + { + return CO_BCONTAINS; + } + else if(str == "startswith") + { + return CO_STARTSWITH; + } + else if(str == "bstartswith") + { + return CO_BSTARTSWITH; + } + else if(str == "endswith") + { + return CO_ENDSWITH; + } + else if(str == "in") + { + return CO_IN; + } + else if(str == "intersects") + { + return CO_INTERSECTS; + } + else if(str == "pmatch") + { + return CO_PMATCH; + } + else if(str == "exists") + { + return CO_EXISTS; + } + else if(str == "glob") + { + return CO_GLOB; + } + else if(str == "iglob") + { + return CO_IGLOB; + } + + throw sinsp_exception("unrecognized filter comparison operator '" + std::string(str) + "'"); +} + +bool cmpop_to_str(cmpop op, std::string& out) +{ + switch (op) + { + case CO_NONE: { out = "none"; return true; } + case CO_EQ: { out = "="; return true; } + case CO_NE: { out = "!="; return true; } + case CO_LT: { out = "<"; return true; } + case CO_LE: { out = "<="; return true; } + case CO_GT: { out = ">"; return true; } + case CO_GE: { out = ">="; return true; } + case CO_CONTAINS: { out = "contains"; return true; } + case CO_IN: { out = "in"; return true; } + case CO_EXISTS: { out = "exists"; return true; } + case CO_ICONTAINS: { out = "icontains"; return true; } + case CO_STARTSWITH: { out = "startswith"; return true; } + case CO_GLOB: { out = "glob"; return true; } + case CO_IGLOB: { out = "iglob"; return true; } + case CO_PMATCH: { out = "pmatch"; return true; } + case CO_ENDSWITH: { out = "endswith"; return true; } + case CO_INTERSECTS: { out = "intersects"; return true; } + case CO_BCONTAINS: { out = "bcontains"; return true; } + case CO_BSTARTSWITH: { out = "bstartswith"; return true; } + default: + ASSERT(false); + out = "unknown"; + return false; + } +}; + +std::string std::to_string(cmpop c) +{ + switch (c) + { + case CO_NONE: return "NONE"; + case CO_EQ: return "EQ"; + case CO_NE: return "NE"; + case CO_LT: return "LT"; + case CO_LE: return "LE"; + case CO_GT: return "GT"; + case CO_GE: return "GE"; + case CO_CONTAINS: return "CONTAINS"; + case CO_IN: return "IN"; + case CO_EXISTS: return "EXISTS"; + case CO_ICONTAINS: return "ICONTAINS"; + case CO_STARTSWITH: return "STARTSWITH"; + case CO_GLOB: return "GLOB"; + case CO_IGLOB: return "IGLOB"; + case CO_PMATCH: return "PMATCH"; + case CO_ENDSWITH: return "ENDSWITH"; + case CO_INTERSECTS: return "INTERSECTS"; + case CO_BCONTAINS: return "BCONTAINS"; + case CO_BSTARTSWITH: return "BSTARTSWITH"; + default: + ASSERT(false); + return ""; + } +}; + +static inline bool flt_is_comparable_numeric(cmpop op, std::string& err) +{ + switch(op) + { + case CO_EQ: + case CO_NE: + case CO_LT: + case CO_LE: + case CO_GT: + case CO_GE: + case CO_IN: + case CO_INTERSECTS: + case CO_EXISTS: + return true; + default: + std::string opname; + cmpop_to_str(op, opname); + err = "'" + opname + "' operator not supported for numeric filters"; + return false; + } +} + +static inline bool flt_is_comparable_bool(cmpop op, std::string& err) +{ + switch(op) + { + case CO_EQ: + case CO_NE: + case CO_IN: + case CO_INTERSECTS: + case CO_EXISTS: + return true; + default: + std::string opname; + cmpop_to_str(op, opname); + err = "'" + opname + "' operator not supported for numeric filters"; + return false; + } +} + +static inline bool flt_is_comparable_string(cmpop op, std::string& err) +{ + switch(op) + { + case CO_EQ: + case CO_NE: + case CO_LT: + case CO_LE: + case CO_GT: + case CO_GE: + case CO_CONTAINS: + case CO_IN: + case CO_EXISTS: + case CO_ICONTAINS: + case CO_STARTSWITH: + case CO_GLOB: + case CO_PMATCH: + case CO_ENDSWITH: + case CO_INTERSECTS: + case CO_IGLOB: + return true; + default: + std::string opname; + cmpop_to_str(op, opname); + err = "'" + opname + "' operator not supported for string filters"; + return false; + } +} + +static inline bool flt_is_comparable_buffer(cmpop op, std::string& err) +{ + switch(op) + { + case CO_EQ: + case CO_NE: + case CO_CONTAINS: + case CO_IN: + case CO_EXISTS: + case CO_STARTSWITH: + case CO_ENDSWITH: + case CO_INTERSECTS: + case CO_BCONTAINS: + case CO_BSTARTSWITH: + return true; + default: + std::string opname; + cmpop_to_str(op, opname); + err = "'" + opname + "' operator not supported for buffer filters"; + return false; + } +} + +static inline bool flt_is_comparable_ip_or_net(cmpop op, std::string& err) +{ + switch(op) + { + case CO_EQ: + case CO_NE: + case CO_IN: + case CO_EXISTS: + case CO_INTERSECTS: + return true; + default: + std::string opname; + cmpop_to_str(op, opname); + err = "'" + opname + "' operator not supported for ip address and network filters"; + return false; + } +} + +static inline bool flt_is_comparable_any_list(cmpop op, std::string& err) +{ + switch(op) + { + case CO_IN: + case CO_EXISTS: + case CO_INTERSECTS: + return true; + default: + std::string opname; + cmpop_to_str(op, opname); + err = "'" + opname + "' operator not supported list filters"; + return false; + } +} + +bool flt_is_comparable(cmpop op, ppm_param_type t, bool is_list, std::string& err) +{ + if(op == CO_EXISTS) + { + return true; + } + + if (is_list) + { + switch (t) + { + case PT_CHARBUF: + case PT_UINT64: + case PT_RELTIME: + case PT_ABSTIME: + case PT_BOOL: + case PT_IPADDR: + case PT_IPNET: + return flt_is_comparable_any_list(op, err); + default: + err = "list filters are not supported for type '" + std::string(param_type_to_string(t)) + "'"; + return false; + } + } + + switch(t) + { + case PT_INT8: + case PT_INT16: + case PT_INT32: + case PT_INT64: + case PT_UINT8: + case PT_UINT16: + case PT_UINT32: + case PT_UINT64: + case PT_ERRNO: + case PT_FD: + case PT_PID: + case PT_SYSCALLID: + case PT_SIGTYPE: + case PT_RELTIME: + case PT_ABSTIME: + case PT_PORT: + case PT_FLAGS8: + case PT_FLAGS16: + case PT_FLAGS32: + case PT_DOUBLE: + case PT_MODE: + case PT_ENUMFLAGS8: + case PT_ENUMFLAGS16: + case PT_ENUMFLAGS32: + return flt_is_comparable_numeric(op, err); + case PT_BOOL: + return flt_is_comparable_bool(op, err); + case PT_IPV4ADDR: + case PT_IPV4NET: + case PT_IPV6ADDR: + case PT_IPV6NET: + case PT_IPADDR: + case PT_IPNET: + return flt_is_comparable_ip_or_net(op, err); + case PT_CHARBUF: + case PT_FSPATH: + case PT_FSRELPATH: + return flt_is_comparable_string(op, err); + case PT_BYTEBUF: + return flt_is_comparable_buffer(op, err); + default: + std::string opname; + cmpop_to_str(op, opname); + err = "'" + opname + "' operator not supported for type '" + std::string(param_type_to_string(t)) + "'"; + return false; + } +} + +// little helper for functions below +template +static inline void _throw_if_not_comparable(cmpop op, Check c) +{ + std::string err; + if (!c(op, err)) + { + throw sinsp_exception(err); + } +} + +template +static inline bool flt_compare_numeric(cmpop op, uint64_t operand1, uint64_t operand2) +{ + switch(op) + { + case CO_EQ: + case CO_IN: + case CO_INTERSECTS: + return (operand1 == operand2); + case CO_NE: + return (operand1 != operand2); + case CO_LT: + return (operand1 < operand2); + case CO_LE: + return (operand1 <= operand2); + case CO_GT: + return (operand1 > operand2); + case CO_GE: + return (operand1 >= operand2); + default: + _throw_if_not_comparable(op, flt_is_comparable_numeric); + return false; + } +} + +static inline bool flt_compare_string(cmpop op, char* operand1, char* operand2) +{ + switch(op) + { + case CO_EQ: + case CO_IN: + case CO_INTERSECTS: + return (strcmp(operand1, operand2) == 0); + case CO_NE: + return (strcmp(operand1, operand2) != 0); + case CO_CONTAINS: + return (strstr(operand1, operand2) != NULL); + case CO_ICONTAINS: +#ifdef _WIN32 + { + std::string s1(operand1); + std::string s2(operand2); + std::transform(s1.begin(), s1.end(), s1.begin(), [](unsigned char c){ return std::tolower(c); }); + std::transform(s2.begin(), s2.end(), s2.begin(), [](unsigned char c){ return std::tolower(c); }); + return (strstr(s1.c_str(), s2.c_str()) != NULL); + } +#else + return (strcasestr(operand1, operand2) != NULL); +#endif + case CO_STARTSWITH: + return (strncmp(operand1, operand2, strlen(operand2)) == 0); + case CO_ENDSWITH: + return (sinsp_utils::endswith(operand1, operand2, strlen(operand1), strlen(operand2))); + case CO_GLOB: + return sinsp_utils::glob_match(operand2, operand1); + case CO_IGLOB: + return sinsp_utils::glob_match(operand2, operand1, true); + case CO_LT: + return (strcmp(operand1, operand2) < 0); + case CO_LE: + return (strcmp(operand1, operand2) <= 0); + case CO_GT: + return (strcmp(operand1, operand2) > 0); + case CO_GE: + return (strcmp(operand1, operand2) >= 0); + case CO_PMATCH: + // note: pmatch is not handled here + return false; + default: + _throw_if_not_comparable(op, flt_is_comparable_string); + return false; + } +} + +static inline bool flt_compare_buffer(cmpop op, char* operand1, char* operand2, uint32_t op1_len, uint32_t op2_len) +{ + switch(op) + { + case CO_EQ: + case CO_IN: + case CO_INTERSECTS: + return op1_len == op2_len && (memcmp(operand1, operand2, op1_len) == 0); + case CO_NE: + return op1_len != op2_len || (memcmp(operand1, operand2, op1_len) != 0); + case CO_CONTAINS: + return (memmem(operand1, op1_len, operand2, op2_len) != NULL); + case CO_BCONTAINS: + return (memmem(operand1, op1_len, operand2, op2_len) != NULL); + case CO_STARTSWITH: + return op2_len <= op1_len && (memcmp(operand1, operand2, op2_len) == 0); + case CO_BSTARTSWITH: + return op2_len <= op1_len && (memcmp(operand1, operand2, op2_len) == 0); + case CO_ENDSWITH: + return (sinsp_utils::endswith(operand1, operand2, op1_len, op2_len)); + default: + _throw_if_not_comparable(op, flt_is_comparable_buffer); + return false; + } +} + +static inline bool flt_compare_bool(cmpop op, uint64_t operand1, uint64_t operand2) +{ + switch(op) + { + case CO_EQ: + case CO_IN: + case CO_INTERSECTS: + return (operand1 == operand2); + case CO_NE: + return (operand1 != operand2); + default: + _throw_if_not_comparable(op, flt_is_comparable_numeric); + return false; + } +} + +static inline bool flt_compare_ipv4addr(cmpop op, uint64_t operand1, uint64_t operand2) +{ + switch(op) + { + case CO_EQ: + case CO_IN: + case CO_INTERSECTS: + return operand1 == operand2; + case CO_NE: + return operand1 != operand2; + default: + _throw_if_not_comparable(op, flt_is_comparable_ip_or_net); + return false; + } +} + +static inline bool flt_compare_ipv6addr(cmpop op, ipv6addr* operand1, ipv6addr* operand2) +{ + switch(op) + { + case CO_EQ: + case CO_IN: + case CO_INTERSECTS: + return *operand1 == *operand2; + case CO_NE: + return *operand1 != *operand2; + default: + _throw_if_not_comparable(op, flt_is_comparable_ip_or_net); + return false; + } +} + +bool flt_compare_ipv4net(cmpop op, uint64_t operand1, const ipv4net* operand2) +{ + switch(op) + { + case CO_EQ: + case CO_IN: + case CO_INTERSECTS: + return ((operand1 & operand2->m_netmask) == (operand2->m_ip & operand2->m_netmask)); + case CO_NE: + return ((operand1 & operand2->m_netmask) != (operand2->m_ip & operand2->m_netmask)); + default: + _throw_if_not_comparable(op, flt_is_comparable_ip_or_net); + return false; + } +} + +bool flt_compare_ipv6net(cmpop op, const ipv6addr *operand1, const ipv6net *operand2) +{ + switch(op) + { + case CO_EQ: + case CO_IN: + case CO_INTERSECTS: + return operand2->in_cidr(*operand1); + case CO_NE: + return !operand2->in_cidr(*operand1); + default: + _throw_if_not_comparable(op, flt_is_comparable_ip_or_net); + return false; + } +} + +// flt_cast takes a pointer to memory, dereferences it as fromT type and casts it +// to a compatible toT type +template +static inline toT flt_cast(const void* ptr) +{ + fromT val; + memcpy(&val, ptr, sizeof(fromT)); + + return static_cast(val); +} + +bool flt_compare(cmpop op, ppm_param_type type, const void* operand1, const void* operand2, uint32_t op1_len, uint32_t op2_len) +{ + // + // sinsp_filter_check_*::compare + // already discard NULL values + // + if(op == CO_EXISTS) + { + return true; + } + + switch(type) + { + case PT_INT8: + return flt_compare_numeric(op, flt_cast(operand1), flt_cast(operand2)); + case PT_INT16: + return flt_compare_numeric(op, flt_cast(operand1), flt_cast(operand2)); + case PT_INT32: + return flt_compare_numeric(op, flt_cast(operand1), flt_cast(operand2)); + case PT_INT64: + case PT_FD: + case PT_PID: + case PT_ERRNO: + return flt_compare_numeric(op, flt_cast(operand1), flt_cast(operand2)); + case PT_FLAGS8: + case PT_ENUMFLAGS8: + case PT_UINT8: + case PT_SIGTYPE: + return flt_compare_numeric(op, flt_cast(operand1), flt_cast(operand2)); + case PT_FLAGS16: + case PT_UINT16: + case PT_ENUMFLAGS16: + case PT_PORT: + case PT_SYSCALLID: + return flt_compare_numeric(op, flt_cast(operand1), flt_cast(operand2)); + case PT_UINT32: + case PT_FLAGS32: + case PT_ENUMFLAGS32: + case PT_MODE: + return flt_compare_numeric(op, flt_cast(operand1), flt_cast(operand2)); + case PT_BOOL: + return flt_compare_bool(op, flt_cast(operand1), flt_cast(operand2)); + case PT_IPV4ADDR: + if (op2_len != sizeof(struct in_addr)) + { + return false; + } + return flt_compare_ipv4addr(op, flt_cast(operand1), flt_cast(operand2)); + case PT_IPV4NET: + if (op2_len != sizeof(ipv4net)) + { + return false; + } + return flt_compare_ipv4net(op, (uint64_t)*(uint32_t*)operand1, (ipv4net*)operand2); + case PT_IPV6ADDR: + if (op2_len != sizeof(ipv6addr)) + { + return false; + } + return flt_compare_ipv6addr(op, (ipv6addr *)operand1, (ipv6addr *)operand2); + case PT_IPV6NET: + if (op2_len != sizeof(ipv6net)) + { + return false; + } + return flt_compare_ipv6net(op, (ipv6addr *)operand1, (ipv6net*)operand2); + case PT_IPADDR: + if(op1_len == sizeof(struct in_addr)) + { + if (op2_len != sizeof(struct in_addr)) + { + return false; + } + return flt_compare(op, PT_IPV4ADDR, operand1, operand2, op1_len, op2_len); + } + else if(op1_len == sizeof(struct in6_addr)) + { + if (op2_len != sizeof(ipv6addr)) + { + return false; + } + return flt_compare(op, PT_IPV6ADDR, operand1, operand2, op1_len, op2_len); + } + else + { + throw sinsp_exception("rawval_to_string called with IP address of incorrect size " + std::to_string(op1_len)); + } + case PT_IPNET: + if(op1_len == sizeof(struct in_addr)) + { + if (op2_len != sizeof(ipv4net)) + { + return false; + } + return flt_compare(op, PT_IPV4NET, operand1, operand2, op1_len, op2_len); + } + else if(op1_len == sizeof(struct in6_addr)) + { + if (op2_len != sizeof(ipv6net)) + { + return false; + } + return flt_compare(op, PT_IPV6NET, operand1, operand2, op1_len, op2_len); + } + else + { + throw sinsp_exception("rawval_to_string called with IP network of incorrect size " + std::to_string(op1_len)); + } + case PT_UINT64: + case PT_RELTIME: + case PT_ABSTIME: + return flt_compare_numeric(op, flt_cast(operand1), flt_cast(operand2)); + case PT_CHARBUF: + case PT_FSPATH: + case PT_FSRELPATH: + return flt_compare_string(op, (char*)operand1, (char*)operand2); + case PT_BYTEBUF: + return flt_compare_buffer(op, (char*)operand1, (char*)operand2, op1_len, op2_len); + case PT_DOUBLE: + return flt_compare_numeric(op, flt_cast(operand1), flt_cast(operand2)); + default: + ASSERT(false); + return false; + } +} + +bool flt_compare_avg(cmpop op, + ppm_param_type type, + const void* operand1, + const void* operand2, + uint32_t op1_len, + uint32_t op2_len, + uint32_t cnt1, + uint32_t cnt2) +{ + int64_t i641, i642; + uint64_t u641, u642; + double d1, d2; + + // + // If count = 0 we assume that the value is zero too (there are assertions to + // check that, and we just divide by 1 + // + if(cnt1 == 0) + { + cnt1 = 1; + } + + if(cnt2 == 0) + { + cnt2 = 1; + } + + switch(type) + { + case PT_INT8: + i641 = ((int64_t)*(int8_t*)operand1) / cnt1; + i642 = ((int64_t)*(int8_t*)operand2) / cnt2; + ASSERT(cnt1 != 0 || i641 == 0); + ASSERT(cnt2 != 0 || i642 == 0); + return flt_compare_numeric(op, i641, i642); + case PT_INT16: + i641 = ((int64_t)*(int16_t*)operand1) / cnt1; + i642 = ((int64_t)*(int16_t*)operand2) / cnt2; + ASSERT(cnt1 != 0 || i641 == 0); + ASSERT(cnt2 != 0 || i642 == 0); + return flt_compare_numeric(op, i641, i642); + case PT_INT32: + i641 = ((int64_t)*(int32_t*)operand1) / cnt1; + i642 = ((int64_t)*(int32_t*)operand2) / cnt2; + ASSERT(cnt1 != 0 || i641 == 0); + ASSERT(cnt2 != 0 || i642 == 0); + return flt_compare_numeric(op, i641, i642); + case PT_INT64: + case PT_FD: + case PT_PID: + case PT_ERRNO: + i641 = ((int64_t)*(int64_t*)operand1) / cnt1; + i642 = ((int64_t)*(int64_t*)operand2) / cnt2; + ASSERT(cnt1 != 0 || i641 == 0); + ASSERT(cnt2 != 0 || i642 == 0); + return flt_compare_numeric(op, i641, i642); + case PT_FLAGS8: + case PT_UINT8: + case PT_ENUMFLAGS8: + case PT_SIGTYPE: + u641 = ((uint64_t)*(uint8_t*)operand1) / cnt1; + u642 = ((uint64_t)*(uint8_t*)operand2) / cnt2; + ASSERT(cnt1 != 0 || u641 == 0); + ASSERT(cnt2 != 0 || u642 == 0); + return flt_compare_numeric(op, u641, u642); + case PT_FLAGS16: + case PT_UINT16: + case PT_ENUMFLAGS16: + case PT_PORT: + case PT_SYSCALLID: + u641 = ((uint64_t)*(uint16_t*)operand1) / cnt1; + u642 = ((uint64_t)*(uint16_t*)operand2) / cnt2; + ASSERT(cnt1 != 0 || u641 == 0); + ASSERT(cnt2 != 0 || u642 == 0); + return flt_compare_numeric(op, u641, u642); + case PT_UINT32: + case PT_FLAGS32: + case PT_ENUMFLAGS32: + case PT_MODE: + case PT_BOOL: + case PT_IPV4ADDR: + case PT_IPV6ADDR: + // What does an average mean for ip addresses anyway? + u641 = ((uint64_t)*(uint32_t*)operand1) / cnt1; + u642 = ((uint64_t)*(uint32_t*)operand2) / cnt2; + ASSERT(cnt1 != 0 || u641 == 0); + ASSERT(cnt2 != 0 || u642 == 0); + return flt_compare_numeric(op, u641, u642); + case PT_UINT64: + case PT_RELTIME: + case PT_ABSTIME: + u641 = (*(uint64_t*)operand1) / cnt1; + u642 = (*(uint64_t*)operand2) / cnt2; + ASSERT(cnt1 != 0 || u641 == 0); + ASSERT(cnt2 != 0 || u642 == 0); + return flt_compare_numeric(op, u641, u642); + case PT_DOUBLE: + d1 = (*(double*)operand1) / cnt1; + d2 = (*(double*)operand2) / cnt2; + ASSERT(cnt1 != 0 || d1 == 0); + ASSERT(cnt2 != 0 || d2 == 0); + return flt_compare_numeric(op, d1, d2); + default: + ASSERT(false); + return false; + } +} diff --git a/userspace/libsinsp/filter_compare.h b/userspace/libsinsp/filter_compare.h new file mode 100644 index 0000000000..8860332a87 --- /dev/null +++ b/userspace/libsinsp/filter_compare.h @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: Apache-2.0 +/* +Copyright (C) 2024 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. + +*/ + +#pragma once + +#include +#include + +#include +#include +#include + +/* + * Operators to compare events + */ +enum cmpop: uint8_t +{ + CO_NONE = 0, + CO_EQ = 1, + CO_NE = 2, + CO_LT = 3, + CO_LE = 4, + CO_GT = 5, + CO_GE = 6, + CO_CONTAINS = 7, + CO_IN = 8, + CO_EXISTS = 9, + CO_ICONTAINS = 10, + CO_STARTSWITH = 11, + CO_GLOB = 12, + CO_PMATCH = 13, + CO_ENDSWITH = 14, + CO_INTERSECTS = 15, + CO_BCONTAINS = 16, + CO_BSTARTSWITH = 17, + CO_IGLOB = 18, +}; + +cmpop str_to_cmpop(std::string_view str); +bool cmpop_to_str(cmpop op, std::string& out); + +namespace std +{ +std::string to_string(cmpop); +} + +bool flt_is_comparable(cmpop op, ppm_param_type t, bool is_list, std::string& err); +bool flt_compare(cmpop op, ppm_param_type type, const void* operand1, const void* operand2, uint32_t op1_len = 0, uint32_t op2_len = 0); +bool flt_compare_avg(cmpop op, ppm_param_type type, const void* operand1, const void* operand2, uint32_t op1_len, uint32_t op2_len, uint32_t cnt1, uint32_t cnt2); +bool flt_compare_ipv4net(cmpop op, uint64_t operand1, const ipv4net* operand2); +bool flt_compare_ipv6net(cmpop op, const ipv6addr *operand1, const ipv6net *operand2); diff --git a/userspace/libsinsp/filter_value.h b/userspace/libsinsp/filter_value.h index 24d3c01678..38e328288b 100644 --- a/userspace/libsinsp/filter_value.h +++ b/userspace/libsinsp/filter_value.h @@ -20,7 +20,9 @@ limitations under the License. #include #include + #include +#include // Used for CO_IN/CO_PMATCH filterchecks using PT_CHARBUFs to allow // for quick multi-value comparisons. Should also work for any @@ -57,4 +59,3 @@ struct g_equal_to_membuf memcmp(a.first, b.first, a.second) == 0); } }; - diff --git a/userspace/libsinsp/memmem.cpp b/userspace/libsinsp/memmem.cpp deleted file mode 100644 index b3b3a19916..0000000000 --- a/userspace/libsinsp/memmem.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -/* -Copyright (C) 2023 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. - -*/ - -#ifndef _GNU_SOURCE -#include - -void *memmem(const void *haystack, size_t haystacklen, - const void *needle, size_t needlelen) -{ - const unsigned char *ptr; - const unsigned char *end; - - if(needlelen == 0) - { - return (void *)haystack; - } - - if(haystacklen < needlelen) - { - return NULL; - } - - end = (const unsigned char *)haystack + haystacklen - needlelen; - for(ptr = (const unsigned char *)haystack; ptr <= end; ptr++) - { - if(!memcmp(ptr, needle, needlelen)) - { - return (void *)ptr; - } - } - - return NULL; -} -#endif diff --git a/userspace/libsinsp/sinsp_filtercheck.cpp b/userspace/libsinsp/sinsp_filtercheck.cpp index e088708f23..b260f295fb 100644 --- a/userspace/libsinsp/sinsp_filtercheck.cpp +++ b/userspace/libsinsp/sinsp_filtercheck.cpp @@ -25,22 +25,6 @@ limitations under the License. #define STRPROPERTY_STORAGE_SIZE 1024 -#ifndef _GNU_SOURCE -// -// Fallback implementation of memmem -// -void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); -#endif - -#ifdef _WIN32 -#define NOMINMAX -#pragma comment(lib, "Ws2_32.lib") -#include -#else -#include "arpa/inet.h" -#include -#endif - std::string std::to_string(boolop b) { switch (b) @@ -61,620 +45,6 @@ std::string std::to_string(boolop b) return ""; } -std::string std::to_string(cmpop c) -{ - switch (c) - { - case CO_NONE: return "NONE"; - case CO_EQ: return "EQ"; - case CO_NE: return "NE"; - case CO_LT: return "LT"; - case CO_LE: return "LE"; - case CO_GT: return "GT"; - case CO_GE: return "GE"; - case CO_CONTAINS: return "CONTAINS"; - case CO_IN: return "IN"; - case CO_EXISTS: return "EXISTS"; - case CO_ICONTAINS: return "ICONTAINS"; - case CO_STARTSWITH: return "STARTSWITH"; - case CO_GLOB: return "GLOB"; - case CO_IGLOB: return "IGLOB"; - case CO_PMATCH: return "PMATCH"; - case CO_ENDSWITH: return "ENDSWITH"; - case CO_INTERSECTS: return "INTERSECTS"; - case CO_BCONTAINS: return "BCONTAINS"; - case CO_BSTARTSWITH: return "BSTARTSWITH"; - } - return ""; -}; - - -/////////////////////////////////////////////////////////////////////////////// -// type-based comparison functions -/////////////////////////////////////////////////////////////////////////////// -bool flt_compare_uint64(cmpop op, uint64_t operand1, uint64_t operand2) -{ - switch(op) - { - case CO_EQ: - return (operand1 == operand2); - case CO_NE: - return (operand1 != operand2); - case CO_LT: - return (operand1 < operand2); - case CO_LE: - return (operand1 <= operand2); - case CO_GT: - return (operand1 > operand2); - case CO_GE: - return (operand1 >= operand2); - case CO_CONTAINS: - throw sinsp_exception("'contains' not supported for numeric filters"); - return false; - case CO_ICONTAINS: - throw sinsp_exception("'icontains' not supported for numeric filters"); - return false; - case CO_BCONTAINS: - throw sinsp_exception("'bcontains' not supported for numeric filters"); - return false; - case CO_STARTSWITH: - throw sinsp_exception("'startswith' not supported for numeric filters"); - return false; - case CO_BSTARTSWITH: - throw sinsp_exception("'bstartswith' not supported for numeric filters"); - return false; - case CO_ENDSWITH: - throw sinsp_exception("'endswith' not supported for numeric filters"); - return false; - case CO_GLOB: - throw sinsp_exception("'glob' not supported for numeric filters"); - return false; - case CO_IGLOB: - throw sinsp_exception("'iglob' not supported for numeric filters"); - return false; - default: - throw sinsp_exception("'unknown' not supported for numeric filters"); - return false; - } -} - -bool flt_compare_int64(cmpop op, int64_t operand1, int64_t operand2) -{ - switch(op) - { - case CO_EQ: - return (operand1 == operand2); - case CO_NE: - return (operand1 != operand2); - case CO_LT: - return (operand1 < operand2); - case CO_LE: - return (operand1 <= operand2); - case CO_GT: - return (operand1 > operand2); - case CO_GE: - return (operand1 >= operand2); - case CO_CONTAINS: - throw sinsp_exception("'contains' not supported for numeric filters"); - return false; - case CO_ICONTAINS: - throw sinsp_exception("'icontains' not supported for numeric filters"); - return false; - case CO_BCONTAINS: - throw sinsp_exception("'bcontains' not supported for numeric filters"); - return false; - case CO_STARTSWITH: - throw sinsp_exception("'startswith' not supported for numeric filters"); - return false; - case CO_BSTARTSWITH: - throw sinsp_exception("'bstartswith' not supported for numeric filters"); - return false; - case CO_ENDSWITH: - throw sinsp_exception("'endswith' not supported for numeric filters"); - return false; - case CO_GLOB: - throw sinsp_exception("'glob' not supported for numeric filters"); - return false; - case CO_IGLOB: - throw sinsp_exception("'iglob' not supported for numeric filters"); - return false; - default: - throw sinsp_exception("'unknown' not supported for numeric filters"); - return false; - } -} - -bool flt_compare_string(cmpop op, char* operand1, char* operand2) -{ - switch(op) - { - case CO_EQ: - return (strcmp(operand1, operand2) == 0); - case CO_NE: - return (strcmp(operand1, operand2) != 0); - case CO_CONTAINS: - return (strstr(operand1, operand2) != NULL); - case CO_ICONTAINS: -#ifdef _WIN32 - { - std::string s1(operand1); - std::string s2(operand2); - std::transform(s1.begin(), s1.end(), s1.begin(), [](unsigned char c){ return std::tolower(c); }); - std::transform(s2.begin(), s2.end(), s2.begin(), [](unsigned char c){ return std::tolower(c); }); - return (strstr(s1.c_str(), s2.c_str()) != NULL); - } -#else - return (strcasestr(operand1, operand2) != NULL); -#endif - case CO_BCONTAINS: - throw sinsp_exception("'bcontains' not supported for string filters"); - case CO_STARTSWITH: - return (strncmp(operand1, operand2, strlen(operand2)) == 0); - case CO_BSTARTSWITH: - throw sinsp_exception("'bstartswith' not supported for string filters"); - case CO_ENDSWITH: - return (sinsp_utils::endswith(operand1, operand2, strlen(operand1), strlen(operand2))); - case CO_GLOB: - return sinsp_utils::glob_match(operand2, operand1); - case CO_IGLOB: - return sinsp_utils::glob_match(operand2, operand1, true); - case CO_LT: - return (strcmp(operand1, operand2) < 0); - case CO_LE: - return (strcmp(operand1, operand2) <= 0); - case CO_GT: - return (strcmp(operand1, operand2) > 0); - case CO_GE: - return (strcmp(operand1, operand2) >= 0); - default: - ASSERT(false); - throw sinsp_exception("invalid filter operator " + std::to_string((long long) op)); - return false; - } -} - -bool flt_compare_buffer(cmpop op, char* operand1, char* operand2, uint32_t op1_len, uint32_t op2_len) -{ - switch(op) - { - case CO_EQ: - return op1_len == op2_len && (memcmp(operand1, operand2, op1_len) == 0); - case CO_NE: - return op1_len != op2_len || (memcmp(operand1, operand2, op1_len) != 0); - case CO_CONTAINS: - return (memmem(operand1, op1_len, operand2, op2_len) != NULL); - case CO_ICONTAINS: - throw sinsp_exception("'icontains' not supported for buffer filters"); - case CO_BCONTAINS: - return (memmem(operand1, op1_len, operand2, op2_len) != NULL); - case CO_STARTSWITH: - return op2_len <= op1_len && (memcmp(operand1, operand2, op2_len) == 0); - case CO_BSTARTSWITH: - return op2_len <= op1_len && (memcmp(operand1, operand2, op2_len) == 0); - case CO_ENDSWITH: - return (sinsp_utils::endswith(operand1, operand2, op1_len, op2_len)); - case CO_GLOB: - throw sinsp_exception("'glob' not supported for buffer filters"); - case CO_IGLOB: - throw sinsp_exception("'iglob' not supported for buffer filters"); - case CO_LT: - throw sinsp_exception("'<' not supported for buffer filters"); - case CO_LE: - throw sinsp_exception("'<=' not supported for buffer filters"); - case CO_GT: - throw sinsp_exception("'>' not supported for buffer filters"); - case CO_GE: - throw sinsp_exception("'>=' not supported for buffer filters"); - default: - ASSERT(false); - throw sinsp_exception("invalid filter operator " + std::to_string((long long) op)); - return false; - } -} - -bool flt_compare_double(cmpop op, double operand1, double operand2) -{ - switch(op) - { - case CO_EQ: - return (operand1 == operand2); - case CO_NE: - return (operand1 != operand2); - case CO_LT: - return (operand1 < operand2); - case CO_LE: - return (operand1 <= operand2); - case CO_GT: - return (operand1 > operand2); - case CO_GE: - return (operand1 >= operand2); - case CO_CONTAINS: - throw sinsp_exception("'contains' not supported for numeric filters"); - return false; - case CO_ICONTAINS: - throw sinsp_exception("'icontains' not supported for numeric filters"); - return false; - case CO_BCONTAINS: - throw sinsp_exception("'bcontains' not supported for numeric filters"); - return false; - case CO_STARTSWITH: - throw sinsp_exception("'startswith' not supported for numeric filters"); - return false; - case CO_BSTARTSWITH: - throw sinsp_exception("'bstartswith' not supported for numeric filters"); - return false; - case CO_ENDSWITH: - throw sinsp_exception("'endswith' not supported for numeric filters"); - return false; - case CO_GLOB: - throw sinsp_exception("'glob' not supported for numeric filters"); - return false; - case CO_IGLOB: - throw sinsp_exception("'iglob' not supported for numeric filters"); - return false; - default: - throw sinsp_exception("'unknown' not supported for numeric filters"); - return false; - } -} - -bool flt_compare_ipv4net(cmpop op, uint64_t operand1, const ipv4net* operand2) -{ - switch(op) - { - case CO_EQ: - case CO_IN: - { - return ((operand1 & operand2->m_netmask) == (operand2->m_ip & operand2->m_netmask)); - } - case CO_NE: - return ((operand1 & operand2->m_netmask) != (operand2->m_ip & operand2->m_netmask)); - case CO_CONTAINS: - throw sinsp_exception("'contains' not supported for numeric filters"); - return false; - case CO_ICONTAINS: - throw sinsp_exception("'icontains' not supported for numeric filters"); - return false; - case CO_BCONTAINS: - throw sinsp_exception("'bcontains' not supported for numeric filters"); - return false; - case CO_STARTSWITH: - throw sinsp_exception("'startswith' not supported for numeric filters"); - return false; - case CO_BSTARTSWITH: - throw sinsp_exception("'bstartswith' not supported for numeric filters"); - return false; - case CO_ENDSWITH: - throw sinsp_exception("'endswith' not supported for numeric filters"); - return false; - case CO_GLOB: - throw sinsp_exception("'glob' not supported for numeric filters"); - return false; - case CO_IGLOB: - throw sinsp_exception("'iglob' not supported for numeric filters"); - return false; - default: - throw sinsp_exception("comparison operator not supported for ipv4 networks"); - } -} - -bool flt_compare_ipv6addr(cmpop op, ipv6addr *operand1, ipv6addr *operand2) -{ - switch(op) - { - case CO_EQ: - case CO_IN: - return *operand1 == *operand2; - case CO_NE: - return *operand1 != *operand2; - case CO_CONTAINS: - throw sinsp_exception("'contains' not supported for ipv6 addresses"); - return false; - case CO_ICONTAINS: - throw sinsp_exception("'icontains' not supported for ipv6 addresses"); - return false; - case CO_BCONTAINS: - throw sinsp_exception("'bcontains' not supported for ipv6 addresses"); - return false; - case CO_STARTSWITH: - throw sinsp_exception("'startswith' not supported for ipv6 addresses"); - return false; - case CO_BSTARTSWITH: - throw sinsp_exception("'bstartswith' not supported for ipv6 addresses"); - return false; - case CO_GLOB: - throw sinsp_exception("'glob' not supported for ipv6 addresses"); - return false; - case CO_IGLOB: - throw sinsp_exception("'iglob' not supported for ipv6 addresses"); - return false; - default: - throw sinsp_exception("comparison operator not supported for ipv6 addresses"); - } -} - -bool flt_compare_ipv6net(cmpop op, const ipv6addr *operand1, const ipv6net *operand2) -{ - switch(op) - { - case CO_EQ: - case CO_IN: - return operand2->in_cidr(*operand1); - case CO_NE: - return !operand2->in_cidr(*operand1); - case CO_CONTAINS: - throw sinsp_exception("'contains' not supported for ipv6 networks"); - return false; - case CO_ICONTAINS: - throw sinsp_exception("'icontains' not supported for ipv6 networks"); - return false; - case CO_BCONTAINS: - throw sinsp_exception("'bcontains' not supported for ipv6 networks"); - return false; - case CO_STARTSWITH: - throw sinsp_exception("'startswith' not supported for ipv6 networks"); - return false; - case CO_BSTARTSWITH: - throw sinsp_exception("'bstartswith' not supported for ipv6 networks"); - return false; - case CO_GLOB: - throw sinsp_exception("'glob' not supported for ipv6 networks"); - return false; - case CO_IGLOB: - throw sinsp_exception("'iglob' not supported for ipv6 networks"); - return false; - default: - throw sinsp_exception("comparison operator not supported for ipv6 networks"); - } -} - -// flt_cast takes a pointer to memory, dereferences it as fromT type and casts it -// to a compatible toT type -template -static inline toT flt_cast(const void* ptr) -{ - fromT val; - memcpy(&val, ptr, sizeof(fromT)); - - return static_cast(val); -} - -bool flt_compare(cmpop op, ppm_param_type type, const void* operand1, const void* operand2, uint32_t op1_len, uint32_t op2_len) -{ - // - // sinsp_filter_check_*::compare - // already discard NULL values - // - if(op == CO_EXISTS) - { - return true; - } - - switch(type) - { - case PT_INT8: - return flt_compare_int64(op, flt_cast(operand1), flt_cast(operand2)); - case PT_INT16: - return flt_compare_int64(op, flt_cast(operand1), flt_cast(operand2)); - case PT_INT32: - return flt_compare_int64(op, flt_cast(operand1), flt_cast(operand2)); - case PT_INT64: - case PT_FD: - case PT_PID: - case PT_ERRNO: - return flt_compare_int64(op, flt_cast(operand1), flt_cast(operand2)); - case PT_FLAGS8: - case PT_ENUMFLAGS8: - case PT_UINT8: - case PT_SIGTYPE: - return flt_compare_uint64(op, flt_cast(operand1), flt_cast(operand2)); - case PT_FLAGS16: - case PT_UINT16: - case PT_ENUMFLAGS16: - case PT_PORT: - case PT_SYSCALLID: - return flt_compare_uint64(op, flt_cast(operand1), flt_cast(operand2)); - case PT_UINT32: - case PT_FLAGS32: - case PT_ENUMFLAGS32: - case PT_MODE: - case PT_BOOL: - case PT_IPV4ADDR: - if (op2_len != sizeof(struct in_addr)) - { - return false; - } - return flt_compare_uint64(op, flt_cast(operand1), flt_cast(operand2)); - case PT_IPV4NET: - if (op2_len != sizeof(ipv4net)) - { - return false; - } - return flt_compare_ipv4net(op, (uint64_t)*(uint32_t*)operand1, (ipv4net*)operand2); - case PT_IPV6ADDR: - if (op2_len != sizeof(ipv6addr)) - { - return false; - } - return flt_compare_ipv6addr(op, (ipv6addr *)operand1, (ipv6addr *)operand2); - case PT_IPV6NET: - if (op2_len != sizeof(ipv6net)) - { - return false; - } - return flt_compare_ipv6net(op, (ipv6addr *)operand1, (ipv6net*)operand2); - case PT_IPADDR: - if(op1_len == sizeof(struct in_addr)) - { - if (op2_len != sizeof(struct in_addr)) - { - return false; - } - return flt_compare(op, PT_IPV4ADDR, operand1, operand2, op1_len, op2_len); - } - else if(op1_len == sizeof(struct in6_addr)) - { - if (op2_len != sizeof(ipv6addr)) - { - return false; - } - return flt_compare(op, PT_IPV6ADDR, operand1, operand2, op1_len, op2_len); - } - else - { - throw sinsp_exception("rawval_to_string called with IP address of incorrect size " + std::to_string(op1_len)); - } - case PT_IPNET: - if(op1_len == sizeof(struct in_addr)) - { - if (op2_len != sizeof(ipv4net)) - { - return false; - } - return flt_compare(op, PT_IPV4NET, operand1, operand2, op1_len, op2_len); - } - else if(op1_len == sizeof(struct in6_addr)) - { - if (op2_len != sizeof(ipv6net)) - { - return false; - } - return flt_compare(op, PT_IPV6NET, operand1, operand2, op1_len, op2_len); - } - else - { - throw sinsp_exception("rawval_to_string called with IP network of incorrect size " + std::to_string(op1_len)); - } - case PT_UINT64: - case PT_RELTIME: - case PT_ABSTIME: - return flt_compare_uint64(op, flt_cast(operand1), flt_cast(operand2)); - case PT_CHARBUF: - case PT_FSPATH: - case PT_FSRELPATH: - return flt_compare_string(op, (char*)operand1, (char*)operand2); - case PT_BYTEBUF: - return flt_compare_buffer(op, (char*)operand1, (char*)operand2, op1_len, op2_len); - case PT_DOUBLE: - return flt_compare_double(op, flt_cast(operand1), flt_cast(operand2)); - case PT_SOCKADDR: - case PT_SOCKTUPLE: - case PT_FDLIST: - case PT_SIGSET: - default: - ASSERT(false); - return false; - } -} - -bool flt_compare_avg(cmpop op, - ppm_param_type type, - const void* operand1, - const void* operand2, - uint32_t op1_len, - uint32_t op2_len, - uint32_t cnt1, - uint32_t cnt2) -{ - int64_t i641, i642; - uint64_t u641, u642; - double d1, d2; - - // - // If count = 0 we assume that the value is zero too (there are assertions to - // check that, and we just divide by 1 - // - if(cnt1 == 0) - { - cnt1 = 1; - } - - if(cnt2 == 0) - { - cnt2 = 1; - } - - switch(type) - { - case PT_INT8: - i641 = ((int64_t)*(int8_t*)operand1) / cnt1; - i642 = ((int64_t)*(int8_t*)operand2) / cnt2; - ASSERT(cnt1 != 0 || i641 == 0); - ASSERT(cnt2 != 0 || i642 == 0); - return flt_compare_int64(op, i641, i642); - case PT_INT16: - i641 = ((int64_t)*(int16_t*)operand1) / cnt1; - i642 = ((int64_t)*(int16_t*)operand2) / cnt2; - ASSERT(cnt1 != 0 || i641 == 0); - ASSERT(cnt2 != 0 || i642 == 0); - return flt_compare_int64(op, i641, i642); - case PT_INT32: - i641 = ((int64_t)*(int32_t*)operand1) / cnt1; - i642 = ((int64_t)*(int32_t*)operand2) / cnt2; - ASSERT(cnt1 != 0 || i641 == 0); - ASSERT(cnt2 != 0 || i642 == 0); - return flt_compare_int64(op, i641, i642); - case PT_INT64: - case PT_FD: - case PT_PID: - case PT_ERRNO: - i641 = ((int64_t)*(int64_t*)operand1) / cnt1; - i642 = ((int64_t)*(int64_t*)operand2) / cnt2; - ASSERT(cnt1 != 0 || i641 == 0); - ASSERT(cnt2 != 0 || i642 == 0); - return flt_compare_int64(op, i641, i642); - case PT_FLAGS8: - case PT_UINT8: - case PT_ENUMFLAGS8: - case PT_SIGTYPE: - u641 = ((uint64_t)*(uint8_t*)operand1) / cnt1; - u642 = ((uint64_t)*(uint8_t*)operand2) / cnt2; - ASSERT(cnt1 != 0 || u641 == 0); - ASSERT(cnt2 != 0 || u642 == 0); - return flt_compare_uint64(op, u641, u642); - case PT_FLAGS16: - case PT_UINT16: - case PT_ENUMFLAGS16: - case PT_PORT: - case PT_SYSCALLID: - u641 = ((uint64_t)*(uint16_t*)operand1) / cnt1; - u642 = ((uint64_t)*(uint16_t*)operand2) / cnt2; - ASSERT(cnt1 != 0 || u641 == 0); - ASSERT(cnt2 != 0 || u642 == 0); - return flt_compare_uint64(op, u641, u642); - case PT_UINT32: - case PT_FLAGS32: - case PT_ENUMFLAGS32: - case PT_MODE: - case PT_BOOL: - case PT_IPV4ADDR: - case PT_IPV6ADDR: - // What does an average mean for ip addresses anyway? - u641 = ((uint64_t)*(uint32_t*)operand1) / cnt1; - u642 = ((uint64_t)*(uint32_t*)operand2) / cnt2; - ASSERT(cnt1 != 0 || u641 == 0); - ASSERT(cnt2 != 0 || u642 == 0); - return flt_compare_uint64(op, u641, u642); - case PT_UINT64: - case PT_RELTIME: - case PT_ABSTIME: - u641 = (*(uint64_t*)operand1) / cnt1; - u642 = (*(uint64_t*)operand2) / cnt2; - ASSERT(cnt1 != 0 || u641 == 0); - ASSERT(cnt2 != 0 || u642 == 0); - return flt_compare_uint64(op, u641, u642); - case PT_DOUBLE: - d1 = (*(double*)operand1) / cnt1; - d2 = (*(double*)operand2) / cnt2; - ASSERT(cnt1 != 0 || d1 == 0); - ASSERT(cnt2 != 0 || d2 == 0); - return flt_compare_double(op, d1, d2); - default: - ASSERT(false); - return false; - } -} - template static inline void ensure_unique_ptr_allocated(Ptr& p, Params... args) { diff --git a/userspace/libsinsp/sinsp_filtercheck.h b/userspace/libsinsp/sinsp_filtercheck.h index c39a7b7db2..18d30b9f09 100644 --- a/userspace/libsinsp/sinsp_filtercheck.h +++ b/userspace/libsinsp/sinsp_filtercheck.h @@ -18,41 +18,17 @@ limitations under the License. #pragma once -#include -#include -#include -#include -#include -#include #include #include #include +#include #include -/* - * Operators to compare events - */ -enum cmpop: uint8_t { - CO_NONE = 0, - CO_EQ = 1, - CO_NE = 2, - CO_LT = 3, - CO_LE = 4, - CO_GT = 5, - CO_GE = 6, - CO_CONTAINS = 7, - CO_IN = 8, - CO_EXISTS = 9, - CO_ICONTAINS = 10, - CO_STARTSWITH = 11, - CO_GLOB = 12, - CO_PMATCH = 13, - CO_ENDSWITH = 14, - CO_INTERSECTS = 15, - CO_BCONTAINS = 16, - CO_BSTARTSWITH = 17, - CO_IGLOB = 18, -}; +#include + +#include +#include +#include enum boolop: uint8_t { @@ -66,14 +42,8 @@ enum boolop: uint8_t BO_ANDNOT = 5, }; -bool flt_compare(cmpop op, ppm_param_type type, const void* operand1, const void* operand2, uint32_t op1_len = 0, uint32_t op2_len = 0); -bool flt_compare_avg(cmpop op, ppm_param_type type, const void* operand1, const void* operand2, uint32_t op1_len, uint32_t op2_len, uint32_t cnt1, uint32_t cnt2); -bool flt_compare_ipv4net(cmpop op, uint64_t operand1, const ipv4net* operand2); -bool flt_compare_ipv6net(cmpop op, const ipv6addr *operand1, const ipv6net *operand2); - namespace std { -std::string to_string(cmpop); std::string to_string(boolop); } diff --git a/userspace/libsinsp/sinsp_filtercheck_fd.cpp b/userspace/libsinsp/sinsp_filtercheck_fd.cpp index f0f54182b6..e3e61cfd79 100644 --- a/userspace/libsinsp/sinsp_filtercheck_fd.cpp +++ b/userspace/libsinsp/sinsp_filtercheck_fd.cpp @@ -1404,8 +1404,12 @@ bool sinsp_filter_check_fd::compare_ip(sinsp_evt *evt) if(m_fdinfo != NULL) { - scap_fd_type evt_type = m_fdinfo->m_type; + if(m_cmpop == CO_EXISTS) + { + return true; + } + scap_fd_type evt_type = m_fdinfo->m_type; if(evt_type == SCAP_FD_IPV4_SOCK) { if(m_cmpop == CO_EQ || m_cmpop == CO_IN) @@ -1486,6 +1490,11 @@ bool sinsp_filter_check_fd::compare_net(sinsp_evt *evt) return false; } + if(m_cmpop == CO_EXISTS) + { + return true; + } + bool sip_cmp = false; bool dip_cmp = false; @@ -1533,6 +1542,11 @@ bool sinsp_filter_check_fd::compare_port(sinsp_evt *evt) if(m_fdinfo != NULL) { + if(m_cmpop == CO_EXISTS) + { + return true; + } + uint16_t* sport; uint16_t* dport; scap_fd_type evt_type = m_fdinfo->m_type; @@ -1637,6 +1651,11 @@ bool sinsp_filter_check_fd::compare_domain(sinsp_evt *evt) if(m_fdinfo != NULL) { + if(m_cmpop == CO_EXISTS) + { + return true; + } + scap_fd_type evt_type = m_fdinfo->m_type; if(evt_type != SCAP_FD_IPV4_SOCK && evt_type != SCAP_FD_IPV6_SOCK) diff --git a/userspace/libsinsp/test/filter_compiler.ut.cpp b/userspace/libsinsp/test/filter_compiler.ut.cpp index 984bdac886..e08dae74a2 100644 --- a/userspace/libsinsp/test/filter_compiler.ut.cpp +++ b/userspace/libsinsp/test/filter_compiler.ut.cpp @@ -14,6 +14,10 @@ class mock_compiler_filter_check : public sinsp_filter_check int32_t parse_field_name(std::string_view str, bool alloc_state, bool needed_for_filtering) override { m_name = str; + if (str == "c.buffer") + { + m_field_info.m_type = PT_BYTEBUF; + } return 0; } @@ -23,7 +27,7 @@ class mock_compiler_filter_check : public sinsp_filter_check { return true; } - if (m_name == "c.false") + if (m_name == "c.false" || m_name == "c.buffer") { return false; } @@ -38,6 +42,11 @@ class mock_compiler_filter_check : public sinsp_filter_check return false; } + const filtercheck_field_info* get_field_info() const override + { + return &m_field_info; + } + inline void add_filter_value(const char* str, uint32_t l, uint32_t i) override { m_value = string(str, l); @@ -53,8 +62,9 @@ class mock_compiler_filter_check : public sinsp_filter_check return false; } - string m_name; - string m_value; + std::string m_name; + std::string m_value; + filtercheck_field_info m_field_info{PT_CHARBUF, 0, PF_NA, "", "", ""}; }; // A factory that creates mock filterchecks @@ -205,9 +215,7 @@ TEST(sinsp_filter_compiler, supported_operators) test_filter_compile(factory, "c.true glob value"); test_filter_compile(factory, "c.true contains value"); test_filter_compile(factory, "c.true icontains value"); - test_filter_compile(factory, "c.true bcontains 12ab001fc5"); test_filter_compile(factory, "c.true startswith value"); - test_filter_compile(factory, "c.true bstartswith 48545450"); test_filter_compile(factory, "c.true endswith value"); test_filter_compile(factory, "c.true > 1"); test_filter_compile(factory, "c.true < 1"); @@ -217,14 +225,305 @@ TEST(sinsp_filter_compiler, supported_operators) test_filter_compile(factory, "c.true intersects ()"); test_filter_compile(factory, "c.true pmatch ()"); test_filter_compile(factory, "c.true in()"); + test_filter_compile(factory, "c.buffer bcontains 12ab001fc5"); + test_filter_compile(factory, "c.buffer bstartswith 48545450"); // operators incompatibilites - test_filter_compile(factory, "c.true bstartswith g", true); - test_filter_compile(factory, "c.true bstartswith 123Z", true); - test_filter_compile(factory, "c.true bstartswith abc_1", true); - test_filter_compile(factory, "c.true bstartswith g", true); - test_filter_compile(factory, "c.true bstartswith 123Z", true); - test_filter_compile(factory, "c.true bstartswith abc_1", true); + test_filter_compile(factory, "c.buffer bstartswith g", true); + test_filter_compile(factory, "c.buffer bstartswith 123Z", true); + test_filter_compile(factory, "c.buffer bstartswith abc_1", true); + test_filter_compile(factory, "c.buffer bstartswith g", true); + test_filter_compile(factory, "c.buffer bstartswith 123Z", true); + test_filter_compile(factory, "c.buffer bstartswith abc_1", true); +} + +TEST(sinsp_filter_compiler, operators_field_types_compatibility) +{ + sinsp inspector; + sinsp_filter_check_list filterlist; + auto factory = std::make_shared(&inspector, filterlist); + + // PT_ABSTIME + test_filter_compile(factory, "evt.rawtime exists"); + test_filter_compile(factory, "evt.rawtime = 1"); + test_filter_compile(factory, "evt.rawtime != 1"); + test_filter_compile(factory, "evt.rawtime < 1"); + test_filter_compile(factory, "evt.rawtime <= 1"); + test_filter_compile(factory, "evt.rawtime > 1"); + test_filter_compile(factory, "evt.rawtime >= 1"); + test_filter_compile(factory, "evt.rawtime contains 1", true); + test_filter_compile(factory, "evt.rawtime in (1)"); + test_filter_compile(factory, "evt.rawtime intersects (1)"); + test_filter_compile(factory, "evt.rawtime icontains 1", true); + test_filter_compile(factory, "evt.rawtime startswith 1", true); + test_filter_compile(factory, "evt.rawtime glob 1", true); + test_filter_compile(factory, "evt.rawtime pmatch (1)", true); + test_filter_compile(factory, "evt.rawtime endswith 1", true); + test_filter_compile(factory, "evt.rawtime bcontains 303000", true); + test_filter_compile(factory, "evt.rawtime bstartswith 303000", true); + test_filter_compile(factory, "evt.rawtime iglob 1", true); + + // PT_BOOL + test_filter_compile(factory, "evt.is_io exists"); + test_filter_compile(factory, "evt.is_io = true"); + test_filter_compile(factory, "evt.is_io != true"); + test_filter_compile(factory, "evt.is_io < true", true); + test_filter_compile(factory, "evt.is_io <= true", true); + test_filter_compile(factory, "evt.is_io > true", true); + test_filter_compile(factory, "evt.is_io >= true", true); + test_filter_compile(factory, "evt.is_io contains true", true); + test_filter_compile(factory, "evt.is_io in (true)"); + test_filter_compile(factory, "evt.is_io intersects (true)"); + test_filter_compile(factory, "evt.is_io icontains true", true); + test_filter_compile(factory, "evt.is_io startswith true", true); + test_filter_compile(factory, "evt.is_io glob true", true); + test_filter_compile(factory, "evt.is_io pmatch (true)", true); + test_filter_compile(factory, "evt.is_io endswith true", true); + test_filter_compile(factory, "evt.is_io bcontains 7472756500", true); + test_filter_compile(factory, "evt.is_io bstartswith 7472756500", true); + test_filter_compile(factory, "evt.is_io iglob true", true); + + // PT_BYTEBUF + test_filter_compile(factory, "evt.buffer exists"); + test_filter_compile(factory, "evt.buffer = test"); + test_filter_compile(factory, "evt.buffer != test"); + test_filter_compile(factory, "evt.buffer < 1", true); + test_filter_compile(factory, "evt.buffer <= 2", true); + test_filter_compile(factory, "evt.buffer > 3", true); + test_filter_compile(factory, "evt.buffer >= 4", true); + test_filter_compile(factory, "evt.buffer contains test"); + test_filter_compile(factory, "evt.buffer in (test)"); + test_filter_compile(factory, "evt.buffer intersects (test)"); + test_filter_compile(factory, "evt.buffer icontains test", true); + test_filter_compile(factory, "evt.buffer startswith test"); + test_filter_compile(factory, "evt.buffer glob test", true); + test_filter_compile(factory, "evt.buffer pmatch (test)", true); + test_filter_compile(factory, "evt.buffer endswith test"); + test_filter_compile(factory, "evt.buffer bcontains 303000"); + test_filter_compile(factory, "evt.buffer bstartswith 303000"); + test_filter_compile(factory, "evt.buffer iglob test", true); + + // PT_CHARBUF + test_filter_compile(factory, "fd.name exists"); + test_filter_compile(factory, "fd.name = true"); + test_filter_compile(factory, "fd.name != true"); + test_filter_compile(factory, "fd.name < 1"); + test_filter_compile(factory, "fd.name <= 1"); + test_filter_compile(factory, "fd.name > 1"); + test_filter_compile(factory, "fd.name >= 1"); + test_filter_compile(factory, "fd.name contains true"); + test_filter_compile(factory, "fd.name in (true)"); + test_filter_compile(factory, "fd.name intersects (true)"); + test_filter_compile(factory, "fd.name icontains true"); + test_filter_compile(factory, "fd.name startswith true"); + test_filter_compile(factory, "fd.name glob true"); + test_filter_compile(factory, "fd.name pmatch (true)"); + test_filter_compile(factory, "fd.name endswith true"); + test_filter_compile(factory, "fd.name bcontains 303000", true); + test_filter_compile(factory, "fd.name bstartswith 303000", true); + test_filter_compile(factory, "fd.name iglob true"); + + // PT_DOUBLE + test_filter_compile(factory, "thread.cpu exists"); + test_filter_compile(factory, "thread.cpu = 1"); + // note: floating point values still not supported + test_filter_compile(factory, "thread.cpu = 1.0", true); + test_filter_compile(factory, "thread.cpu != 1"); + test_filter_compile(factory, "thread.cpu < 1"); + test_filter_compile(factory, "thread.cpu <= 1"); + test_filter_compile(factory, "thread.cpu > 1"); + test_filter_compile(factory, "thread.cpu >= 1"); + test_filter_compile(factory, "thread.cpu contains 1", true); + test_filter_compile(factory, "thread.cpu in (1)"); + test_filter_compile(factory, "thread.cpu intersects (1)"); + test_filter_compile(factory, "thread.cpu icontains 1", true); + test_filter_compile(factory, "thread.cpu startswith 1", true); + test_filter_compile(factory, "thread.cpu glob 1", true); + test_filter_compile(factory, "thread.cpu pmatch (1)", true); + test_filter_compile(factory, "thread.cpu endswith 1", true); + test_filter_compile(factory, "thread.cpu bcontains 303000", true); + test_filter_compile(factory, "thread.cpu bstartswith 303000", true); + test_filter_compile(factory, "thread.cpu iglob 1", true); + + // PT_INT16 + test_filter_compile(factory, "evt.cpu exists"); + test_filter_compile(factory, "evt.cpu = 1"); + test_filter_compile(factory, "evt.cpu != 1"); + test_filter_compile(factory, "evt.cpu < 1"); + test_filter_compile(factory, "evt.cpu <= 1"); + test_filter_compile(factory, "evt.cpu > 1"); + test_filter_compile(factory, "evt.cpu >= 1"); + test_filter_compile(factory, "evt.cpu contains 1", true); + test_filter_compile(factory, "evt.cpu in (1)"); + test_filter_compile(factory, "evt.cpu intersects (1)"); + test_filter_compile(factory, "evt.cpu icontains 1", true); + test_filter_compile(factory, "evt.cpu startswith 1", true); + test_filter_compile(factory, "evt.cpu glob 1", true); + test_filter_compile(factory, "evt.cpu pmatch (1)", true); + test_filter_compile(factory, "evt.cpu endswith 1", true); + test_filter_compile(factory, "evt.cpu bcontains 303000", true); + test_filter_compile(factory, "evt.cpu bstartswith 303000", true); + test_filter_compile(factory, "evt.cpu iglob 1", true); + + // PT_INT32 + test_filter_compile(factory, "fd.dev exists"); + test_filter_compile(factory, "fd.dev = 1"); + test_filter_compile(factory, "fd.dev != 1"); + test_filter_compile(factory, "fd.dev < 1"); + test_filter_compile(factory, "fd.dev <= 1"); + test_filter_compile(factory, "fd.dev > 1"); + test_filter_compile(factory, "fd.dev >= 1"); + test_filter_compile(factory, "fd.dev contains 1", true); + test_filter_compile(factory, "fd.dev in (1)"); + test_filter_compile(factory, "fd.dev intersects (1)"); + test_filter_compile(factory, "fd.dev icontains 1", true); + test_filter_compile(factory, "fd.dev startswith 1", true); + test_filter_compile(factory, "fd.dev glob 1", true); + test_filter_compile(factory, "fd.dev pmatch (1)", true); + test_filter_compile(factory, "fd.dev endswith 1", true); + test_filter_compile(factory, "fd.dev bcontains 303000", true); + test_filter_compile(factory, "fd.dev bstartswith 303000", true); + test_filter_compile(factory, "fd.dev iglob 1", true); + + // PT_INT64 + test_filter_compile(factory, "proc.pid exists"); + test_filter_compile(factory, "proc.pid = 1"); + test_filter_compile(factory, "proc.pid != 1"); + test_filter_compile(factory, "proc.pid < 1"); + test_filter_compile(factory, "proc.pid <= 1"); + test_filter_compile(factory, "proc.pid > 1"); + test_filter_compile(factory, "proc.pid >= 1"); + test_filter_compile(factory, "proc.pid contains 1", true); + test_filter_compile(factory, "proc.pid in (1)"); + test_filter_compile(factory, "proc.pid intersects (1)"); + test_filter_compile(factory, "proc.pid icontains 1", true); + test_filter_compile(factory, "proc.pid startswith 1", true); + test_filter_compile(factory, "proc.pid glob 1", true); + test_filter_compile(factory, "proc.pid pmatch (1)", true); + test_filter_compile(factory, "proc.pid endswith 1", true); + test_filter_compile(factory, "proc.pid bcontains 303000", true); + test_filter_compile(factory, "proc.pid bstartswith 303000", true); + test_filter_compile(factory, "proc.pid iglob 1", true); + + // PT_IPADDR + test_filter_compile(factory, "fd.ip exists"); + test_filter_compile(factory, "fd.ip = 127.0.0.1"); + test_filter_compile(factory, "fd.ip != 127.0.0.1"); + test_filter_compile(factory, "fd.ip < 127", true); + test_filter_compile(factory, "fd.ip <= 127", true); + test_filter_compile(factory, "fd.ip > 127", true); + test_filter_compile(factory, "fd.ip >= 127", true); + test_filter_compile(factory, "fd.ip contains 127.0.0.1", true); + test_filter_compile(factory, "fd.ip in (127.0.0.1)"); + test_filter_compile(factory, "fd.ip intersects (127.0.0.1)"); + test_filter_compile(factory, "fd.ip icontains 127.0.0.1", true); + test_filter_compile(factory, "fd.ip startswith 127.0.0.1", true); + test_filter_compile(factory, "fd.ip glob 127.0.0.1", true); + test_filter_compile(factory, "fd.ip pmatch (127.0.0.1)", true); + test_filter_compile(factory, "fd.ip endswith 127.0.0.1", true); + test_filter_compile(factory, "fd.ip bcontains 3132372e302e302e3100", true); + test_filter_compile(factory, "fd.ip bstartswith 3132372e302e302e3100", true); + test_filter_compile(factory, "fd.ip iglob 127.0.0.1", true); + + // PT_IPNET + test_filter_compile(factory, "fd.net exists"); + test_filter_compile(factory, "fd.net = 127.0.0.1/32"); + test_filter_compile(factory, "fd.net != 127.0.0.1/32"); + test_filter_compile(factory, "fd.net < 127", true); + test_filter_compile(factory, "fd.net <= 127", true); + test_filter_compile(factory, "fd.net > 127", true); + test_filter_compile(factory, "fd.net >= 127", true); + test_filter_compile(factory, "fd.net contains 127.0.0.1/32", true); + test_filter_compile(factory, "fd.net in (127.0.0.1/32)"); + test_filter_compile(factory, "fd.net intersects (127.0.0.1/32)"); + test_filter_compile(factory, "fd.net icontains 127.0.0.1/32", true); + test_filter_compile(factory, "fd.net startswith 127.0.0.1/32", true); + test_filter_compile(factory, "fd.net glob 127.0.0.1/32", true); + test_filter_compile(factory, "fd.net pmatch (127.0.0.1/32)", true); + test_filter_compile(factory, "fd.net endswith 127.0.0.1/32", true); + test_filter_compile(factory, "fd.net bcontains 3132372e302e302e312f333200", true); + test_filter_compile(factory, "fd.net bstartswith 3132372e302e302e312f333200", true); + test_filter_compile(factory, "fd.net iglob 127.0.0.1/32", true); + + // PT_PORT + test_filter_compile(factory, "fd.port exists"); + test_filter_compile(factory, "fd.port = 1"); + test_filter_compile(factory, "fd.port != 1"); + test_filter_compile(factory, "fd.port < 1"); + test_filter_compile(factory, "fd.port <= 1"); + test_filter_compile(factory, "fd.port > 1"); + test_filter_compile(factory, "fd.port >= 1"); + test_filter_compile(factory, "fd.port contains 1", true); + test_filter_compile(factory, "fd.port in (1)"); + test_filter_compile(factory, "fd.port intersects (1)"); + test_filter_compile(factory, "fd.port icontains 1", true); + test_filter_compile(factory, "fd.port startswith 1", true); + test_filter_compile(factory, "fd.port glob 1", true); + test_filter_compile(factory, "fd.port pmatch (1)", true); + test_filter_compile(factory, "fd.port endswith 1", true); + test_filter_compile(factory, "fd.port bcontains 303000", true); + test_filter_compile(factory, "fd.port bstartswith 303000", true); + test_filter_compile(factory, "fd.port iglob 1", true); + + // PT_RELTIME + test_filter_compile(factory, "proc.pid.ts exists"); + test_filter_compile(factory, "proc.pid.ts = 1"); + test_filter_compile(factory, "proc.pid.ts != 1"); + test_filter_compile(factory, "proc.pid.ts < 1"); + test_filter_compile(factory, "proc.pid.ts <= 1"); + test_filter_compile(factory, "proc.pid.ts > 1"); + test_filter_compile(factory, "proc.pid.ts >= 1"); + test_filter_compile(factory, "proc.pid.ts contains 1", true); + test_filter_compile(factory, "proc.pid.ts in (1)"); + test_filter_compile(factory, "proc.pid.ts intersects (1)"); + test_filter_compile(factory, "proc.pid.ts icontains 1", true); + test_filter_compile(factory, "proc.pid.ts startswith 1", true); + test_filter_compile(factory, "proc.pid.ts glob 1", true); + test_filter_compile(factory, "proc.pid.ts pmatch (1)", true); + test_filter_compile(factory, "proc.pid.ts endswith 1", true); + test_filter_compile(factory, "proc.pid.ts bcontains 303000", true); + test_filter_compile(factory, "proc.pid.ts bstartswith 303000", true); + test_filter_compile(factory, "proc.pid.ts iglob 1", true); + + // PT_UINT32 + test_filter_compile(factory, "evt.count exists"); + test_filter_compile(factory, "evt.count = 1"); + test_filter_compile(factory, "evt.count != 1"); + test_filter_compile(factory, "evt.count < 1"); + test_filter_compile(factory, "evt.count <= 1"); + test_filter_compile(factory, "evt.count > 1"); + test_filter_compile(factory, "evt.count >= 1"); + test_filter_compile(factory, "evt.count contains 1", true); + test_filter_compile(factory, "evt.count in (1)"); + test_filter_compile(factory, "evt.count intersects (1)"); + test_filter_compile(factory, "evt.count icontains 1", true); + test_filter_compile(factory, "evt.count startswith 1", true); + test_filter_compile(factory, "evt.count glob 1", true); + test_filter_compile(factory, "evt.count pmatch (1)", true); + test_filter_compile(factory, "evt.count endswith 1", true); + test_filter_compile(factory, "evt.count bcontains 303000", true); + test_filter_compile(factory, "evt.count bstartswith 303000", true); + test_filter_compile(factory, "evt.count iglob 1", true); + + // PT_UINT64 + test_filter_compile(factory, "evt.num exists"); + test_filter_compile(factory, "evt.num = 1"); + test_filter_compile(factory, "evt.num != 1"); + test_filter_compile(factory, "evt.num < 1"); + test_filter_compile(factory, "evt.num <= 1"); + test_filter_compile(factory, "evt.num > 1"); + test_filter_compile(factory, "evt.num >= 1"); + test_filter_compile(factory, "evt.num contains 1", true); + test_filter_compile(factory, "evt.num in (1)"); + test_filter_compile(factory, "evt.num intersects (1)"); + test_filter_compile(factory, "evt.num icontains 1", true); + test_filter_compile(factory, "evt.num startswith 1", true); + test_filter_compile(factory, "evt.num glob 1", true); + test_filter_compile(factory, "evt.num pmatch (1)", true); + test_filter_compile(factory, "evt.num endswith 1", true); + test_filter_compile(factory, "evt.num bcontains 303000", true); + test_filter_compile(factory, "evt.num bstartswith 303000", true); + test_filter_compile(factory, "evt.num iglob 1", true); } TEST(sinsp_filter_compiler, complex_filter) diff --git a/userspace/libsinsp/value_parser.cpp b/userspace/libsinsp/value_parser.cpp index bf2a90b1d7..7285cfbc6a 100644 --- a/userspace/libsinsp/value_parser.cpp +++ b/userspace/libsinsp/value_parser.cpp @@ -167,6 +167,17 @@ size_t sinsp_filter_value_parser::string_to_rawval(const char* str, uint32_t len } break; + case PT_DOUBLE: + { + check_storage_size(str, max_len, sizeof(double)); + // note(jasondellaluce): we historically never supported parsing + // floating point number values, so as a starter we just stick to + // integer numberd + // todo(jasondellaluce): support floating point (double) value parsing + *(double*)storage = (double)sinsp_numparser::parsed32(str); + parsed_len = sizeof(double); + break; + } case PT_IPADDR: if(memchr(str, '.', len) != NULL) {