diff --git a/scripts/lua/modules/alert_definitions/other/alert_device_disconnection.lua b/attic/scripts/lua/modules/alert_definitions/alert_device_disconnection.lua similarity index 100% rename from scripts/lua/modules/alert_definitions/other/alert_device_disconnection.lua rename to attic/scripts/lua/modules/alert_definitions/alert_device_disconnection.lua diff --git a/scripts/lua/modules/alert_definitions/other/alert_unexpected_new_device.lua b/attic/scripts/lua/modules/alert_definitions/device_connection.lua similarity index 100% rename from scripts/lua/modules/alert_definitions/other/alert_unexpected_new_device.lua rename to attic/scripts/lua/modules/alert_definitions/device_connection.lua diff --git a/attic/device_connection_disconnection/locales/en.lua b/attic/scripts/plugins/alerts/interface/device_connection_disconnection/locales/en.lua similarity index 100% rename from attic/device_connection_disconnection/locales/en.lua rename to attic/scripts/plugins/alerts/interface/device_connection_disconnection/locales/en.lua diff --git a/attic/device_connection_disconnection/manifest.lua b/attic/scripts/plugins/alerts/interface/device_connection_disconnection/manifest.lua similarity index 100% rename from attic/device_connection_disconnection/manifest.lua rename to attic/scripts/plugins/alerts/interface/device_connection_disconnection/manifest.lua diff --git a/attic/device_connection_disconnection/user_scripts/interface/device_connection_disconnection.lua b/attic/scripts/plugins/alerts/interface/device_connection_disconnection/user_scripts/interface/device_connection_disconnection.lua similarity index 100% rename from attic/device_connection_disconnection/user_scripts/interface/device_connection_disconnection.lua rename to attic/scripts/plugins/alerts/interface/device_connection_disconnection/user_scripts/interface/device_connection_disconnection.lua diff --git a/scripts/locales/en.lua b/scripts/locales/en.lua index d3972919ec..b3031c0a90 100644 --- a/scripts/locales/en.lua +++ b/scripts/locales/en.lua @@ -107,6 +107,7 @@ local lang = { ["delete_alerts"] = "Delete Alerts", ["delete_disabled_alerts"] = "Delete Alerts", ["delete_obs_point"] = "Delete Observation Point", + ["denied"] = "Denied", ["description"] = "Description", ["destination"] = "Destination", ["developer"] = "Developer", @@ -1945,13 +1946,19 @@ local lang = { ["author"] = "Author", ["category"] = "Category", ["delete_alert_exclusions"] = "Deleting alert exclusions will cause new alerts to be triggered again. Do you really want to delete alert exclusions for", + ["delete_device_exclusion"] = "Deleting device exclusions will cause new alerts to be triggered again. Do you really want to delete exclusions for", ["delete_all_alert_exclusions"] = "Delete Check Exclusions", + ["delete_all_device_exclusions"] = "Delete Device Exclusions", ["delete_all_alert_exclusions_message"] = "Do you really want to delete all configured alert exclusions?", + ["delete_all_device_exclusions_message"] = "Do you really want to delete all configured excluded devices?", ["description"] = "Description", - ["device_exclusion"] = "Device Exclusions", + ["device_exclusion"] = "Devices Exclusion", + ["device_exclusion_list"] = "Devices Exclusion List", + ["device_status"] = "Device Status", ["domain_names"] = "Domain Names", ["excluded_domain_name"] = "Excluded Domain Name", ["excluded_host"] = "Excluded Host", + ["excluded_device"] = "Excluded Device", ["excluded_host_name"] = "Excluded Host Name", ["excluded_issuer_dn"] = "Excluded Issuer DN", ["exclusion_list"] = "Behavioural Check Exclusions", diff --git a/scripts/lua/inc/menu.lua b/scripts/lua/inc/menu.lua index caf71a99f7..edd13226ac 100644 --- a/scripts/lua/inc/menu.lua +++ b/scripts/lua/inc/menu.lua @@ -615,6 +615,15 @@ page_utils.add_menubar_section( { entry = page_utils.menu_entries.divider, }, +--[[ { + entry = page_utils.menu_entries.device_exclusions, + section = page_utils.menu_sections.device_exclusions, + hidden = not is_admin or not auth.has_capability(auth.capabilities.checks) or not ntop.isPro(), + url = '/lua/pro/admin/edit_device_exclusions.lua', + }, + { + entry = page_utils.menu_entries.divider, + },]] { entry = page_utils.menu_entries.scripts_config, section = page_utils.menu_sections.checks, diff --git a/scripts/lua/mac_details.lua b/scripts/lua/mac_details.lua index 392b18cf5f..088c7dc542 100644 --- a/scripts/lua/mac_details.lua +++ b/scripts/lua/mac_details.lua @@ -255,9 +255,9 @@ if((page == "overview") or (page == nil)) then print("\n") end - local first_observed = ntop.getHashCache(getFirstSeenDevicesHashKey(ifId), mac_info["mac"]) + local first_observed = ntop.getHashCache(getDevicesHashMapKey(ifId), mac_info["mac"]) - if(not isEmptyString(first_observed)) then + if(not isEmptyString(first_observed)) and (tonumber(first_observed)) then print("" .. i18n("details.first_observed_on") .. "") print(formatEpoch(first_observed)) print("\n") diff --git a/scripts/lua/modules/alert_definitions/other/alert_device_connection.lua b/scripts/lua/modules/alert_definitions/other/alert_device_connection_disconnection.lua similarity index 94% rename from scripts/lua/modules/alert_definitions/other/alert_device_connection.lua rename to scripts/lua/modules/alert_definitions/other/alert_device_connection_disconnection.lua index bcce490279..3c1801142b 100644 --- a/scripts/lua/modules/alert_definitions/other/alert_device_connection.lua +++ b/scripts/lua/modules/alert_definitions/other/alert_device_connection_disconnection.lua @@ -19,7 +19,7 @@ local alert_device_connection = classes.class(alert) -- ############################################## alert_device_connection.meta = { - alert_key = other_alert_keys.alert_device_connection, + alert_key = other_alert_keys.alert_device_connection_disconnection, i18n_title = "alerts_dashboard.device_connection", icon = "fas fa-fw fa-sign-in", entities = { @@ -50,7 +50,7 @@ end -- @return A human-readable string function alert_device_connection.format(ifid, alert, alert_type_params) return(i18n("alert_messages.device_has_connected", { - device = info.device, + device = alert_type_params.device, url = getMacUrl(alert.entity_val), })) end diff --git a/scripts/lua/modules/alert_keys/other_alert_keys.lua b/scripts/lua/modules/alert_keys/other_alert_keys.lua index 8a30156af8..e61f4dc969 100644 --- a/scripts/lua/modules/alert_keys/other_alert_keys.lua +++ b/scripts/lua/modules/alert_keys/other_alert_keys.lua @@ -61,7 +61,7 @@ local other_alert_keys = { alert_lateral_movement = OTHER_BASE_KEY + 48, -- No longer user (moved to the flows) alert_list_download_succeeded = OTHER_BASE_KEY + 49, alert_no_if_activity = OTHER_BASE_KEY + 50, - alert_unexpected_new_device = OTHER_BASE_KEY + 51, + alert_device_connection_disconnection = OTHER_BASE_KEY + 51, alert_shell_script_executed = OTHER_BASE_KEY + 52, alert_periodicity_update = OTHER_BASE_KEY + 53, -- No longer user (moved to the flows) alert_dns_positive_error_ratio = OTHER_BASE_KEY + 54, diff --git a/scripts/lua/modules/check_definitions/interface/device_connection_disconnection.lua b/scripts/lua/modules/check_definitions/interface/device_connection_disconnection.lua new file mode 100644 index 0000000000..65eb132f8a --- /dev/null +++ b/scripts/lua/modules/check_definitions/interface/device_connection_disconnection.lua @@ -0,0 +1,66 @@ +-- +-- (C) 2019-22 - ntop.org +-- + +local alert_consts = require "alert_consts" +local checks = require("checks") +local callback_utils = require "callback_utils" + +-- ################################################################# + +local script + +-- ########################################### + +local function check_allowed_mac(params) + local ifid = interface.getId() + local seen_devices_hash = getDevicesHashMapKey(ifid) + + -- Retrieving the list of the addresses already seen (both allowed and disallowed) and whitelisted + local seen_devices = ntop.getHashAllCache(seen_devices_hash) or {} + + callback_utils.foreachDevice(getInterfaceName(ifid), function(devicename, devicestats, devicebase) + local mac_addr = devicestats["mac"]:upper() + + local alert = alert_consts.alert_types.alert_device_connection_disconnection.new( + mac_addr + ) + + alert:set_score_warning() + alert:set_subtype(getInterfaceName(ifid)) + alert:set_device_type(devicestats["devtype"]) + alert:set_device_name(mac_addr) + alert:set_granularity(params.granularity) + + if (devicestats["location"] == "lan") and not (devicestats["special_mac"]) then + -- This is a LAN MAC address, let's trigger an alert + -- Add this mac to the seen devices on the network + ntop.setHashCache(seen_devices_hash, mac_addr:upper(), 'denied') + alert:trigger(params.alert_entity, nil, params.cur_alerts) + elseif (seen_devices[mac_addr]) and (seen_devices[mac_addr] == 'allowed') then + -- No alert needs to be triggered or a MAC has been moved from denied to allowed + alert:release(params.alert_entity, nil, params.cur_alerts) + end + end) +end + +-- ################################################################# + +script = { + -- Script category + category = checks.check_categories.network, + default_enabled = false, + + hooks = { + min = check_allowed_mac, + }, + + gui = { + i18n_title = "checks.device_connection_disconnection_title", + i18n_description = "checks.device_connection_disconnection_description", + }, +} + +-- ################################################################# + +return script diff --git a/scripts/lua/modules/check_definitions/interface/unexpected_new_device.lua b/scripts/lua/modules/check_definitions/interface/unexpected_new_device.lua deleted file mode 100644 index 47d1f1e5c9..0000000000 --- a/scripts/lua/modules/check_definitions/interface/unexpected_new_device.lua +++ /dev/null @@ -1,108 +0,0 @@ --- --- (C) 2019-22 - ntop.org --- - -local alert_consts = require "alert_consts" -local alerts_api = require "alerts_api" -local alert_utils = require "alert_utils" -local checks = require("checks") -local callback_utils = require "callback_utils" - --- ################################################################# - -local script - --- ################################################################# - -local function check_allowed_mac(params) - local seen_devices_hash = getFirstSeenDevicesHashKey(interface.getId()) - -- Saving the mac address list into a local variable and swapping keys with value due to performance issues - local mac_list = {} - - -- Retrieving the list of the addresses already seen - local seen_devices = ntop.getHashAllCache(seen_devices_hash) or {} - - -- This is the whitelist, that is, MACs configured here won't trigger any alert - for key, mac in ipairs(params.check_config.items) do - mac_list[mac:upper()] = 1 - end - - local macs_stats = interface.getMacsInfo(nil --[[ sortColumn --]], nil --[[ perPage --]], nil --[[ to_skip --]], - nil --[[ sOrder --]], nil --[[ source_macs_only --]], nil --[[ manufacturer --]], - nil, nil --[[ device_type --]], "") - - for _, mac in pairs(macs_stats["macs"] or {}) do - local addr = mac["mac"]:upper() - - if mac_list[addr] then - -- MAC belongs to the whitelist, no alert - goto continue - end - - if seen_devices[addr] then - -- MAC already seen, no alert - goto continue - end - - if mac["location"] == "lan" and not mac["special_mac"] then - -- This is a LAN MAC address, let's trigger an alert - -- Add this mac to the already seen devices - ntop.setHashCache(seen_devices_hash, addr, 1) - - local device = getDeviceName(addr) - - -- Check if the new mac address is expected or not - local alert = alert_consts.alert_types.alert_unexpected_new_device.new( - device, - addr - ) - - alert:set_score_warning() - alert:set_subtype(device) - alert:set_device_type(mac["devtype"]) - alert:set_device_name(device) - - alert:store(alerts_api.macEntity(addr)) - end - - ::continue:: - end -end - --- ################################################################# - -script = { - -- Script category - category = checks.check_categories.network, - - default_enabled = false, - - - -- Specify the default value whe clicking on the "Reset Default" button - default_value = { - items = {}, - }, - - hooks = { - min = check_allowed_mac, - }, - - gui = { - i18n_title = "checks.unexpected_new_device_title", - i18n_description = "checks.unexpected_new_device_description", - - input_builder = "items_list", - item_list_type = "mac_address", - input_title = i18n("checks.unexpected_new_device_exclusion_title"), - input_description = i18n("checks.unexpected_new_device_exclusion_description"), - - input_action_i18n = "Reset Learned Devices", - input_action_url = "lua/rest/v2/delete/host/new_devices.lua", - input_action_confirm = true, - input_action_i18n_confirm = "Are you sure to reset the learned devices?", - }, -} - --- ################################################################# - -return script diff --git a/scripts/lua/modules/http_lint.lua b/scripts/lua/modules/http_lint.lua index e600a30c8a..7ce79d74c1 100644 --- a/scripts/lua/modules/http_lint.lua +++ b/scripts/lua/modules/http_lint.lua @@ -1004,6 +1004,16 @@ local function validateMac(p) end end +-- ############################################## + +-- @brief Returns true if inputstr is a Mac or all string +local function validateDeviceOrAll(inputstr) + return (validateMac(inputstr) or inputstr == 'all') +end +http_lint.validateDeviceOrAll = validateDeviceOrAll + +-- ############################################## + local function validateZoom(zoom) if string.match(zoom, "%d+%a") == zoom then return true @@ -1558,6 +1568,9 @@ local known_parameters = { ["delete_alerts"] = validateBool, ["alert_generation"] = { jsonCleanup, validateJSON }, +-- EXCLUDE DEVICES + ["device"] = validateDeviceOrAll, + -- UI TOASTS ["toast_id"] = validateSingleWord, diff --git a/scripts/lua/modules/lua_utils.lua b/scripts/lua/modules/lua_utils.lua index d1dc0e1405..92edcba42c 100644 --- a/scripts/lua/modules/lua_utils.lua +++ b/scripts/lua/modules/lua_utils.lua @@ -4013,8 +4013,8 @@ end -- ########################################### -- A redis hash mac -> first_seen -function getFirstSeenDevicesHashKey(ifid) - return "ntopng.seen_devices.ifid_" .. ifid +function getDevicesHashMapKey(ifid) + return "ntopng.checks.device_connection_disconnection.ifid_" .. ifid end -- ########################################### diff --git a/scripts/lua/modules/page_utils.lua b/scripts/lua/modules/page_utils.lua index 5d509ac427..01a747298c 100644 --- a/scripts/lua/modules/page_utils.lua +++ b/scripts/lua/modules/page_utils.lua @@ -49,6 +49,7 @@ page_utils.menu_sections = { system_stats = {key = "system_stats", i18n_title = "system", icon = "fas fa-desktop"}, admin = {key = "admin", i18n_title = "settings", icon = "fas fa-cog"}, alert_exclusions = {key = "alert_exclusions", i18n_title = "edit_check.exclusion_list", icon = "fas fa-bell-slash"}, + device_exclusions = {key = "device_exclusions", i18n_title = "edit_check.device_exclusions", icon = "fas fa-bell-slash"}, dev = {key = "dev", i18n_title = "developer", icon = "fas fa-code"}, about = {key = "about", i18n_title = "help", icon = "fas fa-life-ring"}, health = {key = "health", i18n_title = "health", icon = "fas fa-laptop-medical"}, @@ -141,6 +142,7 @@ page_utils.menu_entries = { scripts_config_flows = {key = "scripts_config", subkey="flows", i18n_title = alert_entities.flow.i18n_label, section = "admin", help_link = "https://www.ntop.org/guides/ntopng/web_gui/checks.html"}, scripts_config_system = {key = "scripts_config", subkey="system", i18n_title = alert_entities.system.i18n_label, section = "admin", help_link = "https://www.ntop.org/guides/ntopng/web_gui/checks.html"}, scripts_config_syslog = {key = "scripts_config", subkey="syslog", i18n_title = "syslog.syslog", section = "admin", help_link = "https://www.ntop.org/guides/ntopng/web_gui/checks.html"}, + device_exclusions = {key = "device_exclusions", i18n_title = "edit_check.device_exclusion", section = "device_exclusions"}, alert_exclusions = {key = "alert_exclusions", i18n_title = "edit_check.exclusion_list", section = "alert_exclusions", help_link = "https://www.ntop.org/guides/ntopng/web_gui/checks.html"}, alert_exclusions_hosts = {key = "alert_exclusions", subkey="hosts", i18n_title = alert_entities.host.i18n_label, section = "alert_exclusions", help_link = "https://www.ntop.org/guides/ntopng/web_gui/checks.html"}, alert_exclusions_flows = {key = "alert_exclusions", subkey="flows", i18n_title = alert_entities.flow.i18n_label, section = "alert_exclusions", help_link = "https://www.ntop.org/guides/ntopng/web_gui/checks.html"},