Add support for more filter operators in alerts explorer

This commit is contained in:
Alfredo Cardigliano 2021-06-29 18:25:45 +02:00
parent 3a2f678cbd
commit a8d08b2d3e
7 changed files with 302 additions and 220 deletions

View file

@ -289,52 +289,63 @@ local modals = {
})
}
local operators_by_filter = {
alert_id = {'eq','neq'},
severity = {'eq','lte','gte','neq'},
ip = {'eq','neq'},
port = {'eq','neq'},
l7_proto = {'eq','neq'},
role = {'eq','neq'},
roles = {'eq','neq'},
text = {'eq','neq'},
}
local defined_tags = {
["host"] = {
alert_id = {'eq'},
severity = {'eq','lte','gte'},
ip = {'eq'},
role = {'eq'},
alert_id = operators_by_filter.alert_id,
severity = operators_by_filter.severity,
ip = operators_by_filter.ip,
role = operators_by_filter.role,
},
["mac"] = {
alert_id = {'eq'},
severity = {'eq','lte','gte'}
alert_id = operators_by_filter.alert_id,
severity = operators_by_filter.severity,
},
["snmp_device"] = {
alert_id = {'eq'},
severity = {'eq','lte','gte'}
alert_id = operators_by_filter.alert_id,
severity = operators_by_filter.severity,
},
["flow"] = {
alert_id = {'eq'},
severity = {'eq','lte','gte'},
l7_proto = {'eq'},
cli_ip = {'eq'},
srv_ip = {'eq'},
cli_port = {'eq'},
srv_port = {'eq'},
roles = {'eq'},
alert_id = operators_by_filter.alert_id,
severity = operators_by_filter.severity,
l7_proto = operators_by_filter.l7_proto,
cli_ip = operators_by_filter.ip,
srv_ip = operators_by_filter.ip,
cli_port = operators_by_filter.port,
srv_port = operators_by_filter.port,
roles = operators_by_filter.roles,
},
["system"] = {
alert_id = {'eq'},
severity = {'eq','lte','gte'}
alert_id = operators_by_filter.alert_id,
severity = operators_by_filter.severity,
},
["am_host"] = {
alert_id = {'eq'},
severity = {'eq','lte','gte'},
alert_id = operators_by_filter.alert_id,
severity = operators_by_filter.severity,
},
["interface"] = {
alert_id = {'eq'},
subtype = {'eq'},
severity = {'eq','lte','gte'}
alert_id = operators_by_filter.alert_id,
severity = operators_by_filter.severity,
subtype = operators_by_filter.text,
},
["user"] = {
alert_id = {'eq'},
severity = {'eq','lte','gte'}
alert_id = operators_by_filter.alert_id,
severity = operators_by_filter.severity,
},
["network"] = {
alert_id = {'eq'},
severity = {'eq','lte','gte'},
network_name = {'eq'}
alert_id = operators_by_filter.alert_id,
severity = operators_by_filter.severity,
network_name = operators_by_filter.text,
}
}
@ -368,10 +379,7 @@ local extra_range_buttons = [[
local available_filter_types = {}
local all_alert_types = {}
local extra_tags_buttons = ""
local severity_operators = {}
if page ~= "all" then
severity_operators = defined_tags[page].severity
extra_tags_buttons = [[
<button class="btn btn-link" aria-controls="]]..page..[[-alerts-table" type="button" id="btn-add-alert-filter" onclick="alertStats.filterModalShow()"><span><i class="fas fa-plus" data-original-title="" title="]]..i18n("alerts_dashboard.add_filter")..[["></i></span>
</button>
@ -396,7 +404,7 @@ local context = {
range_picker = {
default = status == "historical" and "30min" or "1week",
tags = {
enabled = true,
enabled = (page ~= 'all' and status ~= 'engaged'),
tag_operators = tag_utils.tag_operators,
view_only = true,
defined_tags = defined_tags[page],
@ -466,7 +474,7 @@ local context = {
severities = alert_severities,
alert_types = all_alert_types,
l7_protocols = interface.getnDPIProtocols(),
severity_operators = severity_operators,
operators_by_filter = operators_by_filter,
tag_operators = tag_utils.tag_operators,
}
}

View file

@ -132,8 +132,7 @@ function alert_store:add_alert_id_filter(alert_id)
local alert_id, op = self:strip_filter_operator(alert_id)
if not self._alert_id and tonumber(alert_id) then
self._alert_id = tonumber(alert_id)
self._where[#self._where + 1] = string.format("alert_id = %u", alert_id)
self._where[#self._where + 1] = string.format("alert_id %s %u", op, alert_id)
return true
end
end

View file

@ -159,10 +159,19 @@ end
--@param ip The host IP
--@return True if set is successful, false otherwise
function flow_alert_store:add_cli_ip_filter(ip)
if not self._cli_ip then
self._cli_ip = ip
self._where[#self._where + 1] = string.format("cli_ip = '%s'", self._cli_ip)
return true
if not isEmptyString(ip) then
local ip, op = self:strip_filter_operator(ip)
local host = hostkey2hostinfo(ip)
if not isEmptyString(host["host"]) then
if not self._cli_ip then
self._cli_ip = host["host"]
self._where[#self._where + 1] = string.format("cli_ip %s '%s'", op, self._cli_ip)
if not isEmptyString(host["vlan"]) then
self:add_vlan_id_filter(host["vlan"])
end
return true
end
end
end
return false
@ -174,10 +183,20 @@ end
--@param ip The host IP
--@return True if set is successful, false otherwise
function flow_alert_store:add_srv_ip_filter(ip)
if not self._srv_ip then
self._srv_ip = ip
self._where[#self._where + 1] = string.format("srv_ip = '%s'", self._srv_ip)
return true
if not isEmptyString(ip) then
local ip, op = self:strip_filter_operator(ip)
local host = hostkey2hostinfo(ip)
if not isEmptyString(host["host"]) then
self:add_srv_ip_filter(host["host"])
if not self._srv_ip then
self._srv_ip = host["host"]
self._where[#self._where + 1] = string.format("srv_ip %s '%s'", op, self._srv_ip)
if not isEmptyString(host["vlan"]) then
self:add_vlan_id_filter(host["vlan"])
end
return true
end
end
end
return false
@ -189,10 +208,15 @@ end
--@param ip The host IP
--@return True if set is successful, false otherwise
function flow_alert_store:add_ip_filter(ip)
if not self._ip then
self._ip = ip
self._where[#self._where + 1] = string.format("(srv_ip = '%s' OR cli_ip = '%s')", self._ip, self._ip)
return true
if not isEmptyString(ip) then
local ip, op = self:strip_filter_operator(ip)
if not self._ip then
self._ip = ip
local logic = 'OR'
if op == '!=' then logic = 'AND' end
self._where[#self._where + 1] = string.format("(srv_ip %s '%s' %s cli_ip %s '%s')", op, self._ip, logic, op, self._ip)
return true
end
end
return false
@ -204,10 +228,15 @@ end
--@param port The port
--@return True if set is successful, false otherwise
function flow_alert_store:add_cli_port_filter(port)
if not self._cli_port then
self._cli_port = port
self._where[#self._where + 1] = string.format("cli_port = '%s'", self._cli_port)
return true
if not isEmptyString(port) then
local port, op = self:strip_filter_operator(port)
if not isEmptyString(port) then
if not self._cli_port then
self._cli_port = port
self._where[#self._where + 1] = string.format("cli_port %s '%s'", op, self._cli_port)
return true
end
end
end
return false
@ -219,10 +248,15 @@ end
--@param port The port
--@return True if set is successful, false otherwise
function flow_alert_store:add_srv_port_filter(port)
if not self._srv_port then
self._srv_port = port
self._where[#self._where + 1] = string.format("srv_port = '%s'", self._srv_port)
return true
if not isEmptyString(port) then
local port, op = self:strip_filter_operator(port)
if not isEmptyString(port) then
if not self._srv_port then
self._srv_port = port
self._where[#self._where + 1] = string.format("srv_port %s '%s'", op, self._srv_port)
return true
end
end
end
return false
@ -234,10 +268,13 @@ end
--@param vlan_id The VLAN ID
--@return True if set is successful, false otherwise
function flow_alert_store:add_vlan_id_filter(vlan_id)
if not self._vlan_id and tonumber(vlan_id) then
self._vlan_id = tonumber(vlan_id)
self._where[#self._where + 1] = string.format("vlan_id = %u", self._vlan_id)
return true
if not isEmptyString(vlan_id) then
local vlan_id, op = self:strip_filter_operator(vlan_id)
if not self._vlan_id and tonumber(vlan_id) then
self._vlan_id = tonumber(vlan_id)
self._where[#self._where + 1] = string.format("vlan_id %s %u", op, self._vlan_id)
return true
end
end
return false
@ -249,17 +286,22 @@ end
--@param l7_proto The l7 proto
--@return True if set is successful, false otherwise
function flow_alert_store:add_l7_proto_filter(l7_proto)
if not self._l7_proto then
if not tonumber(l7_proto) then
-- Try converting l7 proto name to number
l7_proto = interface.getnDPIProtoId(l7_proto)
end
if tonumber(l7_proto) then
self._l7_proto = tonumber(l7_proto)
self._l7_master_proto = tonumber(l7_proto)
self._where[#self._where + 1] = string.format("(l7_proto = %u OR l7_master_proto = %u)",
self._l7_proto, self._l7_master_proto)
return true
if not isEmptyString(l7_proto) then
local l7_proto, op = self:strip_filter_operator(l7_proto)
if not self._l7_proto then
if not tonumber(l7_proto) then
-- Try converting l7 proto name to number
l7_proto = interface.getnDPIProtoId(l7_proto)
end
if tonumber(l7_proto) then
self._l7_proto = tonumber(l7_proto)
self._l7_master_proto = tonumber(l7_proto)
local logic = 'OR'
if op == '!=' then logic = 'AND' end
self._where[#self._where + 1] = string.format("(l7_proto %s %u %s l7_master_proto %s %u)",
op, self._l7_proto, logic, op, self._l7_master_proto)
return true
end
end
end
@ -272,16 +314,19 @@ end
--@param roles The roles (had_attacker, has_victim, no_attacker_nor_victim)
--@return True if set is successful, false otherwise
function flow_alert_store:add_roles_filter(roles)
if not self._roles then
self._roles = roles
if roles == 'has_attacker' then
self._where[#self._where + 1] = "(is_cli_attacker = 1 OR is_srv_attacker = 1)"
elseif roles == 'has_victim' then
self._where[#self._where + 1] = "(is_cli_victim = 1 OR is_srv_victim = 1)"
elseif roles == 'no_attacker_nor_victim' then
self._where[#self._where + 1] = "(is_cli_attacker = 0 AND is_srv_attacker = 0 AND is_srv_victim = 0 AND is_cli_victim = 0)"
if not isEmptyString(roles) then
local roles, op = self:strip_filter_operator(roles)
if not self._roles then
self._roles = roles
if roles == 'has_attacker' then
self._where[#self._where + 1] = "(is_cli_attacker = 1 OR is_srv_attacker = 1)"
elseif roles == 'has_victim' then
self._where[#self._where + 1] = "(is_cli_victim = 1 OR is_srv_victim = 1)"
elseif roles == 'no_attacker_nor_victim' then
self._where[#self._where + 1] = "(is_cli_attacker = 0 AND is_srv_attacker = 0 AND is_srv_victim = 0 AND is_cli_victim = 0)"
end
return true
end
return true
end
return false
@ -299,56 +344,13 @@ function flow_alert_store:_add_additional_request_filters()
local l7_proto = _GET["l7_proto"]
local roles = _GET["roles"]
if not isEmptyString(vlan_id) then
local vlan_id, op = self:strip_filter_operator(vlan_id)
self:add_vlan_id_filter(vlan_id)
end
if not isEmptyString(cli_ip) then
local ip, op = self:strip_filter_operator(cli_ip)
local host = hostkey2hostinfo(ip)
if not isEmptyString(host["host"]) then
self:add_cli_ip_filter(host["host"])
end
if not isEmptyString(host["vlan"]) then
self:add_vlan_id_filter(host["vlan"])
end
end
if not isEmptyString(srv_ip) then
local ip, op = self:strip_filter_operator(srv_ip)
local host = hostkey2hostinfo(ip)
if not isEmptyString(host["host"]) then
self:add_srv_ip_filter(host["host"])
end
if not isEmptyString(host["vlan"]) then
self:add_vlan_id_filter(host["vlan"])
end
end
if not isEmptyString(cli_port) then
local port, op = self:strip_filter_operator(cli_port)
if not isEmptyString(port) then
self:add_cli_port_filter(port)
end
end
if not isEmptyString(srv_port) then
local port, op = self:strip_filter_operator(srv_port)
if not isEmptyString(port) then
self:add_srv_port_filter(port)
end
end
if not isEmptyString(l7_proto) then
local l7_proto, op = self:strip_filter_operator(l7_proto)
self:add_l7_proto_filter(l7_proto)
end
if not isEmptyString(roles) then
local roles, op = self:strip_filter_operator(roles)
self:add_roles_filter(roles)
end
self:add_vlan_id_filter(vlan_id)
self:add_cli_ip_filter(cli_ip)
self:add_srv_ip_filter(srv_ip)
self:add_cli_port_filter(cli_port)
self:add_srv_port_filter(srv_port)
self:add_l7_proto_filter(l7_proto)
self:add_roles_filter(roles)
end
-- ##############################################

View file

@ -98,10 +98,21 @@ end
--@param ip The host IP
--@return True if set is successful, false otherwise
function host_alert_store:add_ip_filter(ip)
if not self._ip then
self._ip = ip
self._where[#self._where + 1] = string.format("ip = '%s'", self._ip)
return true
if not isEmptyString(ip) then
local ip, op = self:strip_filter_operator(ip)
local host = hostkey2hostinfo(ip)
self._entity_value = hostinfo2hostkey(host)
if not isEmptyString(host["host"]) then
if not self._ip then
self._ip = host["host"]
self._where[#self._where + 1] = string.format("ip %s '%s'", op, self._ip)
if not isEmptyString(host["vlan"]) then
self:add_vlan_id_filter(host["vlan"])
end
return true
end
end
end
return false
@ -113,10 +124,13 @@ end
--@param ip The VLAN ID
--@return True if set is successful, false otherwise
function host_alert_store:add_vlan_id_filter(vlan_id)
if not self._vlan_id and tonumber(vlan_id) then
self._vlan_id = tonumber(vlan_id)
self._where[#self._where + 1] = string.format("vlan_id = %u", self._vlan_id)
return true
if not isEmptyString(vlan_id) then
local vlan_id, op = self:strip_filter_operator(vlan_id)
if not self._vlan_id and tonumber(vlan_id) then
self._vlan_id = tonumber(vlan_id)
self._where[#self._where + 1] = string.format("vlan_id %s %u", op, self._vlan_id)
return true
end
end
return false
@ -128,51 +142,34 @@ end
--@param role The role (attacker or victim)
--@return True if set is successful, false otherwise
function host_alert_store:add_role_filter(role)
if not self._role then
if role == 'attacker' then
self._role = alert_roles.alert_role_is_attacker.role_id
self._where[#self._where + 1] = "is_attacker = 1"
elseif role == 'victim' then
self._role = alert_roles.alert_role_is_victim.role_id
self._where[#self._where + 1] = "is_victim = 1"
if not isEmptyString(role) then
local role, op = self:strip_filter_operator(role)
if not self._role then
if role == 'attacker' then
self._role = alert_roles.alert_role_is_attacker.role_id
self._where[#self._where + 1] = string.format("is_attacker %s 1", op)
elseif role == 'victim' then
self._role = alert_roles.alert_role_is_victim.role_id
self._where[#self._where + 1] = string.format("is_victim %s 1", op)
end
return true
end
return true
end
return false
end
-- ##############################################
--@brief Add filters according to what is specified inside the REST API
function host_alert_store:_add_additional_request_filters()
local ip = _GET["ip"]
local vlan_id = _GET["vlan_id"]
local ip = _GET["ip"]
local role = _GET["role"]
if not isEmptyString(vlan_id) then
local vlan_id, op = self:strip_filter_operator(vlan_id)
self:add_vlan_id_filter(vlan_id)
end
if not isEmptyString(ip) then
local ip, op = self:strip_filter_operator(ip)
local host = hostkey2hostinfo(ip)
self._entity_value = hostinfo2hostkey(host)
if not isEmptyString(host["host"]) then
self:add_ip_filter(host["host"])
end
if not isEmptyString(host["vlan"]) then
self:add_vlan_id_filter(host["vlan"])
end
end
if not isEmptyString(role) then
local role, op = self:strip_filter_operator(role)
self:add_role_filter(role)
end
self:add_vlan_id_filter(vlan_id)
self:add_ip_filter(ip)
self:add_role_filter(role)
end
-- ##############################################

View file

@ -64,10 +64,13 @@ end
--@param ip The subtype, as string
--@return True if set is successful, false otherwise
function interface_alert_store:add_subtype_filter(subtype)
if not self._subtype and not isEmptyString(subtype) then
self._subtype = subtype
self._where[#self._where + 1] = string.format("subtype = '%s'", self:_escape(self._subtype))
return true
if not isEmptyString(subtype) then
local subtype, op = self:strip_filter_operator(subtype)
if not self._subtype and not isEmptyString(subtype) then
self._subtype = subtype
self._where[#self._where + 1] = string.format("subtype %s '%s'", op, self:_escape(self._subtype))
return true
end
end
return false
@ -80,10 +83,7 @@ function interface_alert_store:_add_additional_request_filters()
-- Add filters specific to the system family
local subtype = _GET["subtype"]
if not isEmptyString(subtype) then
local subtype, op = self:strip_filter_operator(subtype)
self:add_subtype_filter(subtype)
end
self:add_subtype_filter(subtype)
end
-- ##############################################

View file

@ -62,14 +62,16 @@ end
--@param network_name The local network name
--@return True if set is successful, false otherwise
function network_alert_store:add_network_name_filter(network_name)
if not self._entity_value and not self._network_name and not isEmptyString(network_name) then
-- This is to filter engaged alerts
self._entity_value = network_name
-- This is to filter historical alerts
self._network_name = network_name
self._where[#self._where + 1] = string.format("name = '%s'", self._escape(network_name))
return true
if not isEmptyString(network_name) then
network_name, op = self:strip_filter_operator(network_name)
if not self._entity_value and not self._network_name and not isEmptyString(network_name) then
-- This is to filter engaged alerts
self._entity_value = network_name
-- This is to filter historical alerts
self._network_name = network_name
self._where[#self._where + 1] = string.format("name %s '%s'", op, self._escape(network_name))
return true
end
end
return false
@ -82,10 +84,7 @@ function network_alert_store:_add_additional_request_filters()
-- Add filters specific to the system family
local network_name = _GET["network_name"]
if not isEmptyString(network_name) then
network_name = self:strip_filter_operator(network_name)
self:add_network_name_filter(network_name)
end
self:add_network_name_filter(network_name)
end
-- ##############################################