--
-- (C) 2014-24 - ntop.org
--
--
-- Container for GUI-related stuff that used to be part of lua_utils.lua
--
if (pragma_once_lua_utils_gui == true) then
-- io.write(debug.traceback().."\n")
-- tprint("Circular dependency in lua_utils_gui.lua")
-- tprint(debug.traceback())
-- avoid multiple inclusions
return
end
pragma_once_lua_utils_gui = true
local clock_start = os.clock()
require "gui_utils"
local host_utils = require "host_utils"
local format_utils = require "format_utils"
local dns_utils = require "dns_utils"
local http_utils = require "http_utils"
local rest_utils = require "rest_utils"
-- For backward compatibility override these functions
sendHTTPContentTypeHeader = rest_utils.sendHTTPContentTypeHeader
sendHTTPHeaderIfName = rest_utils.sendHTTPHeaderIfName
sendHTTPHeaderLogout = rest_utils.sendHTTPHeaderLogout
sendHTTPHeader = rest_utils.sendHTTPHeader
flow2hostinfo = host_utils.flow2hostinfo
hostinfo2url = host_utils.hostinfo2url
hostinfo2detailsurl = host_utils.hostinfo2detailsurl
-- ##############################################
function addGoogleMapsScript()
local g_maps_key = ntop.getCache('ntopng.prefs.google_apis_browser_key')
if g_maps_key ~= nil and g_maps_key ~= "" then
g_maps_key = "&key=" .. g_maps_key
else
g_maps_key = ""
end
print("\n")
end
-- ##############################################
function addLogoLightSvg()
return ([[
]])
end
-- ##############################################
function addLogoDarkSvg()
return ([[
]])
end
-- ##############################################
function addLogoSvg()
return ([[
]])
end
-- ##############################################
function addGauge(name, url, maxValue, width, height)
if (url ~= nil) then
print('')
end
print [[
]]
if (url ~= nil) then
print('\n')
end
end
-- ##############################################
-- @brief Generates an host_details.lua a href link (if available), starting from an `host_info` structure
-- @param host_info A lua table containing at least keys `host` and `vlan` or a full lua table generated with Host::lua
-- @param href_params A lua table containing params host_details.lua params, e.g., {page = "historical"}
-- @param href_value A string containing the visible value shown between a href tags
-- @param href_tooltip A string containing a tooltip shown when hovering the mouse on the link
-- @param href_check Performs existance checks on the link to avoid generating links to inactive hosts or hosts without timeseries
-- @param href_only_with_ts True means that a HREF is geneated only of there are timeseries for this host
-- @return A string containing the a href link or a plain string without a href
function hostinfo2detailshref(host_info, href_params, href_value, href_tooltip, href_check, href_only_with_ts,
show_value_with_no_ref)
local show_href = false
local res = ""
if (href_only_with_ts == true) then
local detailLevel = ntop.getCache("ntopng.prefs.hosts_ts_creation")
if (detailLevel == "full") then
local l7 = ntop.getCache("ntopng.prefs.host_ndpi_timeseries_creation")
if (l7 ~= "none") then
show_href = true
end
end
else
show_href = true
end
if (show_href) then
local hostdetails_url = hostinfo2detailsurl(host_info, href_params, href_check)
if not isEmptyString(hostdetails_url) then
res = string.format("%s", hostdetails_url,
href_tooltip or '', href_value or '')
else
if show_value_with_no_ref == nil or show_value_with_no_ref == true then
res = href_value or ''
end
end
return res
else
return (href_value)
end
end
-- ##############################################
-- @brief Given an interface id create an href to the interface detail page
-- @param href_params A lua table containing params host_details.lua params, e.g., {page = "historical"}
-- @return A string containing the a href link
function interface2detailhref(ifid, href_params)
if ifid then
local params = string.format('ifid=%s', tostring(ifid))
-- Iterate all the href params and create a href
for param_name, param_value in pairs(href_params) do
params = string.format('%s&%s=%s', params, param_name, param_value)
end
return string.format('%s/lua/if_stats.lua?%s', ntop.getHttpPrefix(), params)
end
return ''
end
-- ##############################################
-- @brief Generates an host_details.lua a href link (if available), starting from an ip and a vlan
-- @param ip A string with a valid ip address
-- @param vlan A string or a number with a VLAN or nil when VLAN information is not available
-- @param href_params A lua table containing params host_details.lua params, e.g., {page = "historical"}
-- @param href_value A string containing the visible value shown between a href tags
-- @param href_tooltip A string containing a tooltip shown when hovering the mouse on the link
-- @param href_check Performs existance checks on the link to avoid generating links to inactive hosts or hosts without timeseries
-- @return A string containing the a href link or a plain string without a href
function ip2detailshref(ip, vlan, href_params, href_value, href_tooltip, href_check)
return hostinfo2detailshref({
host = ip,
vlan = tonumber(vlan) or 0
}, href_params, href_value, href_tooltip, href_check)
end
-- ##############################################
function flowinfo2process(process, host_info_to_url)
local fmt, proc_name, proc_user_name = '', '', ''
if process then
-- TODO: add links back once restored
if not isEmptyString(process["name"]) then
local full_clean_name = process["name"]:gsub("'", '')
local t = split(full_clean_name, "/")
clean_name = t[#t]
proc_name = string.format(
" %s",
ntop.getHttpPrefix(), host_info_to_url, full_clean_name, process["pid"], clean_name)
end
-- if not isEmptyString(process["user_name"]) then
-- local clean_user_name = process["user_name"]:gsub("'", '')
-- proc_user_name = string.format(" %s",
-- ntop.getHttpPrefix(),
-- host_info_to_url,
-- clean_user_name,
-- process["uid"],
-- clean_user_name)
-- end
if ((proc_user_name ~= '') or (proc_name ~= '')) then
fmt = string.format("[%s]", table.concat({proc_user_name, proc_name}, ' '))
end
end
return fmt
end
-- ##############################################
function flowinfo2container(container)
local fmt, cont_name, pod_name = '', '', ''
if container then
cont_name = string.format(" %s",
ntop.getHttpPrefix(), container["id"], format_utils.formatContainer(container))
-- local formatted_pod = format_utils.formatPod(container)
-- if not isEmptyString(formatted_pod) then
-- pod_name = string.format(" %s",
-- ntop.getHttpPrefix(),
-- formatted_pod,
-- formatted_pod)
-- end
fmt = string.format("[%s]", table.concat({cont_name, pod_name}, ''))
end
return fmt
end
-- ##############################################
--
-- Analyze the get_info and return a new table containing the url information about an host.
-- Example: url2host(_GET)
--
function url2hostinfo(get_info)
local host = {}
-- Catch when the host key is using as host url parameter
if ((get_info["host"] ~= nil) and (string.find(get_info["host"], "@"))) then
get_info = hostkey2hostinfo(get_info["host"])
end
-- Catch when the host key is using as host url parameter
if (get_info["device"] ~= nil) then
get_info["host"] = get_info["device"]
get_info["device"] = nil
end
if (get_info["host"] ~= nil) then
host["host"] = get_info["host"]
if (debug_host) then
traceError(TRACE_DEBUG, TRACE_CONSOLE, "URL2HOST => Host:" .. get_info["host"] .. "\n")
end
end
if (get_info["vlan"] ~= nil) then
host["vlan"] = tonumber(get_info["vlan"])
if (debug_host) then
traceError(TRACE_DEBUG, TRACE_CONSOLE, "URL2HOST => Vlan:" .. get_info["vlan"] .. "\n")
end
else
host["vlan"] = 0
end
return host
end
-- ##############################################
function unescapeHTML(s)
local unesc = function(h)
local res = string.char(tonumber(h, 16))
return res
end
-- s = string.gsub(s, "+", " ")
s = string.gsub(s, "%%(%x%x)", unesc)
return s
end
-- ##############################################
function unescapeHttpHost(host)
if isEmptyString(host) then
return (host)
end
return string.gsub(string.gsub(host, "http:__", "http://"), "https:__", "https://")
end
-- ##############################################
function isAdministratorOrPrintErr(isJsonResponse)
if (isAdministrator()) then
return (true)
end
local isJson = isJsonResponse or false
if (isJson) then
local json = require("dkjson")
sendHTTPContentTypeHeader('application/json')
print(json.encode({}))
else
local page_utils = require("page_utils")
local dirs = ntop.getDirs()
page_utils.print_header()
dofile(dirs.installdir .. "/scripts/lua/inc/menu.lua")
print(
"
Access forbidden
")
end
return (false)
end
-- ##############################################
function formatBreed(breed, is_encrypted)
local ret = ""
if (breed == "Safe") then
if (is_encrypted == false) then
ret = ""
end
elseif (breed == "Acceptable") then
-- if(is_encrypted == false) then ret = "" end
elseif (breed == "Fun") then
ret = ""
elseif (breed == "Unsafe") then
ret = ""
elseif (breed == "Dangerous") then
ret = ""
end
if (is_encrypted == true) then
ret = ret .. " "
end
return (ret)
end
-- ###############################################
function macInfoWithSymbName(mac, name)
return (' ' .. name .. ' ')
end
-- ###############################################
function macInfo(mac)
return (' ' .. mac .. ' ')
end
-- ###############################################
function intToIPv4(num)
return (math.floor(num / 2 ^ 24) .. "." .. math.floor((num % 2 ^ 24) / 2 ^ 16) .. "." ..
math.floor((num % 2 ^ 16) / 2 ^ 8) .. "." .. num % 2 ^ 8)
end
-- ###############################################
function formatWebSite(site)
return ("" .. site ..
" ")
end
-- #############################################
-- Add here the icons you guess based on the Mac address
-- TODO move to discovery stuff
local guess_icon_keys = {
["dell inc."] = "fas fa-desktop",
["vmware, inc."] = "fas fa-desktop",
["xensource, inc."] = "fas fa-desktop",
["lanner electronics, inc."] = "fas fa-desktop",
["nexcom international co., ltd."] = "fas fa-desktop",
["apple, inc."] = "fab fa-apple",
["cisco systems, inc"] = "fas fa-arrows-alt",
["juniper networks"] = "fas fa-arrows-alt",
["brocade communications systems, inc."] = "fas fa-arrows-alt",
["force10 networks, inc."] = "fas fa-arrows-alt",
["huawei technologies co.,ltd"] = "fas fa-arrows-alt",
["alcatel-lucent ipd"] = "fas fa-arrows-alt",
["arista networks, inc."] = "fas fa-arrows-alt",
["3com corporation"] = "fas fa-arrows-alt",
["routerboard.com"] = "fas fa-arrows-alt",
["extreme networks"] = "fas fa-arrows-alt",
["xerox corporation"] = "fas fa-print"
}
-- #############################################
function guessHostIcon(key)
local m = string.lower(get_manufacturer_mac(key))
local icon = guess_icon_keys[m]
if ((icon ~= nil) and (icon ~= "")) then
return (" ")
else
return ""
end
end
-- ###########################################
-- Note: use data-min and data-max to setup ranges
function makeResolutionButtons(fmt_to_data, ctrl_id, fmt, value, extra, max_val)
local extra = extra or {}
local html_lines = {}
local divisors = {}
-- fill in divisors
if tonumber(value) ~= nil then
-- foreach character in format
string.gsub(fmt, ".", function(k)
local v = fmt_to_data[k]
if v ~= nil then
divisors[#divisors + 1] = {
k = k,
v = v.value
}
end
end)
end
local selected = nil
if tonumber(value) ~= 0 then
selected = highestDivisor(divisors, value, "v")
end
if selected ~= nil then
selected = divisors[selected].k
else
selected = string.sub(fmt, 1, 1)
end
local style = table.merge({
display = "flex"
}, extra.style or {})
html_lines[#html_lines + 1] = [[
]]
-- foreach character in format
string.gsub(fmt, ".", function(k)
local v = fmt_to_data[k]
if v ~= nil then
local line = {}
if ((max_val == nil) or (v.value < max_val)) then
local input_name = ("opt_resbt_%s_%s"):format(k, ctrl_id)
local input = ([[
]]):format(k, truncate(v.value), v.label, input_name, input_name,
ternary((selected == k), 'checked="checked"', ""))
local label = ([[
]]):format(ternary((selected == k), "btn-primary", "btn-secondary"), input_name, v.label)
line[#line + 1] = input
line[#line + 1] = label
html_lines[#html_lines + 1] = table.concat(line, "")
end
end
end)
html_lines[#html_lines + 1] = [[
]]
-- Note: no // comment below, only /* */
local js_init_code = [[
var _resol_inputs = [];
function resol_selector_get_input(a_button) {
return $("input", $(a_button).closest(".form-group")).last();
}
function resol_selector_get_buttons(an_input) {
return $(".btn-group", $(an_input).closest(".form-group")).first().find("input");
}
/* This function scales values wrt selected resolution */
function resol_selector_reset_input_range($selected) {
let duration = $($selected);
let input = resol_selector_get_input(duration);
let raw = parseInt(input.attr("data-min"));
if (! isNaN(raw))
input.attr("min", Math.sign(raw) * Math.ceil(Math.abs(raw) / duration.val()));
raw = parseInt(input.attr("data-max"));
if (! isNaN(raw))
input.attr("max", Math.sign(raw) * Math.ceil(Math.abs(raw) / duration.val()));
var step = parseInt(input.attr("data-step-" + duration.attr("data-resol")));
if (! isNaN(step)) {
input.attr("step", step);
/* Align value */
input.val(input.val() - input.val() % step);
} else
input.attr("step", "");
resol_recheck_input_range(input);
}
/*
* Remove the checked value inside the radio buttons
* and add it only to the one selected
*/
function resol_selector_change_callback(event) {
$(this).parent().find('label').removeClass('btn-primary').addClass('btn-secondary');
$(this).parent().find('input[type="radio"]').prop('checked', false);
$(this).prop('checked', true).removeClass('btn-secondary').addClass('btn-primary');
$(this).parent().find('label[for="' + $(this).attr('id') + '"]').removeClass('btn-secondary').addClass('btn-primary');
resol_selector_reset_input_range($(this));
}
/* Function used to check the value input range */
function resol_recheck_input_range(input) {
let value = input.val();
if (input[0].hasAttribute("min") && Number.isNaN(input.attr("min")))
value = Math.max(parseInt(input.val()), !input.attr("min"));
if (input[0].hasAttribute("max") && Number.isNaN(input.attr("max")))
value = Math.min(parseInt(input.val()), !input.attr("max"));
if ((input.val() != "") && (input.val() != value))
input.val(value);
}
function resol_selector_on_form_submit(event) {
var form = $(this);
if (event.isDefaultPrevented() || (form.find(".has-error").length > 0))
return false;
resol_selector_finalize(form);
return true;
}
function resol_selector_get_raw(input) {
var buttons = resol_selector_get_buttons(input);
var selected = buttons.filter(":checked");
return parseInt(selected.val()) * parseInt(input.val());
}
function resol_selector_finalize(form) {
$.each(_resol_inputs, function(i, elem) {
/* Skip elements which are not part of the form */
if (! $(elem).closest("form").is(form))
return;
var selected = $(elem).find("input[checked]");
var input = resol_selector_get_input(selected);
/* transform in raw units */
var new_input = $("");
new_input.attr("name", input.attr("name"));
input.removeAttr("name");
new_input.val(resol_selector_get_raw(input));
new_input.appendTo(form);
});
/* remove added input names */
$("input[name^=opt_resbt_]", form).removeAttr("name");
}]]
local js_specific_code = [[
$("#]] .. ctrl_id .. [[ input").change(resol_selector_change_callback);
$(function() {
var elemid = "#]] .. ctrl_id .. [[";
_resol_inputs.push(elemid);
var selected = $(elemid + " input[checked]");
resol_selector_reset_input_range(selected);
/* setup the form submit callback (only once) */
var form = selected.closest("form");
if (! form.attr("data-options-handler")) {
form.attr("data-options-handler", 1);
form.submit(resol_selector_on_form_submit);
}
});
]]
-- join strings and strip newlines
local html = string.gsub(table.concat(html_lines, " "), "\n", "")
js_init_code = string.gsub(js_init_code, "", "")
js_specific_code = string.gsub(js_specific_code, "\n", "")
if tonumber(value) ~= nil then
-- returns the new value with selected resolution
return {
html = html,
init = js_init_code,
js = js_specific_code,
value = tonumber(value) / fmt_to_data[selected].value
}
else
return {
html = html,
init = js_init_code,
js = js_specific_code,
value = nil
}
end
end
-- ###########################################
-- avoids manual HTTP prefix and /lua concatenation
function page_url(path)
return ntop.getHttpPrefix() .. "/lua/" .. path
end
-- extracts a page url from the path
function path_get_page(path)
local prefix = ntop.getHttpPrefix() .. "/lua/"
if string.find(path, prefix) == 1 then
return string.sub(path, string.len(prefix) + 1)
end
return path
end
-- ###########################################
function splitUrl(url)
local params = {}
local parts = split(url, "?")
if #parts == 2 then
url = parts[1]
parts = split(parts[2], "&")
for _, param in pairs(parts) do
local p = split(param, "=")
if #p == 2 then
params[p[1]] = p[2]
end
end
end
return {
url = url,
params = params
}
end
-- ##############################################
--- Return an HTML `select` element with passed options.
--
function generate_select(id, name, is_required, is_disabled, options, additional_classes)
local required_flag = (is_required and "required" or "")
local disabled_flag = (is_disabled and "disabled" or "")
local name_attr = (name ~= "" and "name='" .. name .. "'" or "")
local parsed_options = ""
for i, option in ipairs(options) do
parsed_options = parsed_options .. ([[
]])
end
return ([[
]])
end
-- ###########################################
function build_query_url(excluded)
local query = "?"
for key, value in pairs(_GET) do
if not (table.contains(excluded, key)) then
query = query .. string.format("%s=%s&", key, value)
end
end
return query
end
-- ###########################################
function build_query_params(params)
local query = "?"
local t = {}
for key, value in pairs(params) do
t[#t + 1] = string.format("%s=%s", key, value)
end
return query .. table.concat(t, '&')
end
-- ###########################################
function buildHostHREF(ip_address, vlan_id, page)
local stats
if (stats == nil) then
stats = interface.getHostInfo(ip_address, vlan_id)
else
stats = stats.stats
end
if (stats == nil) then
return (ip_address)
else
local hinfo = hostkey2hostinfo(ip_address)
local name = hostinfo2label(hinfo)
local res
if ((name == nil) or (name == "")) then
name = ip_address
end
res = '' .. name .. ''
return (res)
end
end
-- ###########################################
local _cache_map_href = {}
function buildMapHREF(service_peer, map, page, asset_family)
-- cache information in order to speed-up things
if (_cache_map_href[service_peer.ip] ~= nil) then
return (_cache_map_href[service_peer.ip])
end
-- Getting minimal stats to know if the host is still present in memory
local name
local vlan = service_peer.vlan
service_peer.vlan = nil
local map_url = ntop.getHttpPrefix() .. '/lua/pro/enterprise/network_maps.lua?map=' .. map .. '&page=' .. page ..
'&' .. hostinfo2url(service_peer)
local host_url = ''
local host_icon
if vlan then
map_url = map_url .. '&vlan_id=' .. vlan
end
if (asset_family) then
map_url = map_url .. '&asset_family=' .. asset_family
end
-- Getting stats and formatting initial href
if (service_peer.ip or service_peer.host) and not service_peer.is_mac then
-- Host URL only if the host is active
host_url = hostinfo2detailsurl({
host = service_peer.ip or service_peer.host,
vlan = vlan
}, nil, true --[[ check of the host is active --]] )
local hinfo = interface.getHostMinInfo(service_peer.ip or service_peer.host, vlan)
name = hostinfo2label(hinfo or service_peer)
host_icon = "fa-laptop"
else
local minfo = interface.getMacInfo(service_peer.host)
-- The URL only if the MAC is active
if minfo and table.len(minfo) > 0 then
host_url = ntop.getHttpPrefix() .. '/lua/mac_details.lua?' .. hostinfo2url(service_peer)
end
if (service_peer.ip and service_peer.is_mac) or not service_peer.is_mac then
local hinfo = interface.getHostMinInfo(service_peer.ip or service_peer.host, vlan)
name = hostinfo2label(hinfo or service_peer)
else
name = mac2label(service_peer.host)
end
if isMacAddress(name) then
name = mac2label(string.upper(name))
if isMacAddress(name) then
name = get_symbolic_mac(name, true)
end
end
host_icon = "fa-microchip"
end
-- Getting the name if present
name = name or service_peer.host
if vlan and tonumber(vlan) ~= 0 then
name = name .. '@' .. getFullVlanName(vlan)
end
local res
if not isEmptyString(host_url) then
res = string.format('%s', map_url, name, host_url,
host_icon)
else
res = string.format('%s', map_url, name)
end
_cache_map_href[service_peer.ip] = res
return res
end
-- #####################
-- Used by REST v1
function formatAlertAHref(key, value, label)
return "" .. label .. ""
end
function add_historical_flow_explorer_button_ref(extra_params, no_href)
if not ntop.isClickHouseEnabled() then
return ''
end
local base_url = ntop.getHttpPrefix() .. "/lua/pro/db_search.lua?"
for k, v in pairs(extra_params) do
if v["value"] and v["operator"] then
base_url = base_url .. k .. "=" .. v["value"] .. ";" .. v["operator"] .. "&"
end
end
base_url = base_url:sub(1, -2)
if (not no_href) then
return ''
else
return base_url
end
end
function add_delete_obs_point_button()
local button = ''
if isAdministrator() then
button =
''
end
return button
end
-- ##############################################
local _snmp_devices = {}
-- @brief This function format the SNMP interface name.
-- @params device_ip: snmp device ip
-- portidx: number or string, interface index to format
-- short_version: boolean, long formatting version (e.g. flow info) or short version (e.g. dropdown menu)
function format_portidx_name(device_ip, portidx, short_version, shorten_string)
local idx_name = portidx
-- SNMP is available only with Pro version at least
if ntop.isPro() then
local cached_dev = _snmp_devices[device_ip]
if (cached_dev == nil) then
local snmp_cached_dev = require "snmp_cached_dev"
cached_dev = snmp_cached_dev:get_interface_names(device_ip)
_snmp_devices[device_ip] = cached_dev
end
if (cached_dev) and (cached_dev["interfaces"]) then
local port_info = cached_dev["interfaces"][tostring(portidx)]
if port_info then
local dirs = ntop.getDirs()
package.path = dirs.installdir .. "/pro/scripts/lua/modules/?.lua;" .. package.path
snmp_location = require "snmp_location"
if not port_info["id"] then
port_info["id"] = portidx
port_info["snmp_device_ip"] = cached_dev["host_ip"]
end
if short_version then
local name = port_info["name"]
if shorten_string then
if type(shorten_string) == "number" then
name = shortenString(name, shorten_string)
else
name = shortenString(name)
end
end
idx_name = string.format('%s', name);
else
idx_name = string.format('%s', i18n("snmp.interface_device_2", {
interface = snmp_location.snmp_port_link(port_info, true)
-- device=snmp_location.snmp_device_link(cached_dev["host_ip"])
}))
end
else
-- No SNMP configured: last resort use exporters
local snmp_mappings = require "snmp_mappings"
local res = snmp_mappings.get_iface_name(device_ip, portidx)
if (res ~= nil) then
idx_name = res
end
end
end
end
return idx_name
end
-- ##############################################
-- @brief This function converts the SNMP interface name to the corresponding port index.
-- @params device_ip: snmp device ip
-- port_name: string, interface name
function get_portidx_by_name(device_ip, port_name)
-- SNMP is available only with Pro version at least
if ntop.isPro() then
local cached_dev = _snmp_devices[device_ip]
if (cached_dev == nil) then
package.path = dirs.installdir .. "/pro/scripts/lua/modules/?.lua;" .. package.path
local snmp_cached_dev = require "snmp_cached_dev"
cached_dev = snmp_cached_dev:get_interface_names(device_ip)
_snmp_devices[device_ip] = cached_dev
end
if (cached_dev) and (cached_dev["interfaces"]) then
-- SNMP lookup
for idx, info in pairs(cached_dev["interfaces"]) do
if info.name and info.name == port_name then
return idx
end
end
-- No SNMP configured: last resort use exporters
local snmp_mappings = require "snmp_mappings"
local idx = snmp_mappings.get_iface_idx(device_ip, port_name)
if idx then
return idx
end
end
end
return nil
end
-- ##############################################
-- function to format dns query to an HTML copy button and query value
function format_dns_query_copy_btn(dns_query)
return "" .. dns_query .. ""
end
-- @brief Given a table of values, if available, it's going to format the values with the standard
-- info and then return the same table formatted
function format_dns_query_info(dns_info, no_html)
if dns_info.last_query_type then
if no_html then
dns_info.last_query_type = dns_utils.getQueryType(dns_info.last_query_type)
else
dns_info.last_query_type = string.format('%s',
dns_utils.getQueryType(dns_info.last_query_type))
end
end
if dns_info.last_return_code then
if no_html then
dns_info.last_return_code = dns_utils.getResponseStatusCode(dns_info.last_return_code)
else
local badge = get_badge(dns_info.last_return_code)
dns_info.last_return_code = string.format('%s', badge,
dns_utils.getResponseStatusCode(dns_info.last_return_code))
end
end
if dns_info.last_query then
if no_html then
dns_info["last_query"] = dns_info["last_query"]
else
local url = dns_info["last_query"]
url = string.gsub(url, " ", "") -- Clean the URL from spaces and %20, spaces in html
if not string.find(url, '*') then
dns_info.last_query = format_dns_query_copy_btn(dns_info["last_query"])
end
end
end
return dns_info
end
-- ##############################################
function format_tls_info(tls_info, no_html)
if tls_info.notBefore then
tls_info.notBefore = formatEpoch(tls_info.notBefore)
end
if tls_info.notAfter then
tls_info.notAfter = formatEpoch(tls_info.notAfter)
end
if tls_info.notBefore and tls_info.notAfter then
tls_info["tls_certificate_validity"] = string.format("%s - %s", tls_info.notBefore, tls_info.notAfter)
tls_info.notBefore = nil
tls_info.notAfter = nil
end
if (tls_info.tls_version) and (tls_info.tls_version > 0) then
tls_info["tls_version"] = ntop.getTLSVersionName(tls_info.tls_version)
end
if tls_info.client_requested_server_name then
local url = tls_info["client_requested_server_name"]
url = string.gsub(url, " ", "") -- Clean the URL from spaces and %20, spaces in html
if not string.find(url, '*') then
if no_html then
tls_info["client_requested_server_name"] = tls_info["client_requested_server_name"]
else
if not isEmptyString(url) then
tls_info["client_requested_server_name"] = i18n("external_link_url", {
proto = 'https',
url = url,
url_name = url
})
end
end
end
end
if tls_info["ja4_client_hash"] then
if no_html then
tls_info["ja4_client_hash"] = tls_info["ja4_client_hash"]
else
tls_info["ja4_client_hash"] = i18n("copy_button", {
full_name = tls_info["ja4_client_hash"],
name = tls_info["ja4_client_hash"]
})
end
end
if tls_info["server_names"] then
if no_html then
tls_info["server_names"] = tls_info["server_names"]
else
tls_info["server_names"] = i18n("copy_button", {
full_name = tls_info["server_names"],
name = tls_info["server_names"]
})
end
end
return tls_info
end
-- ##############################################
function format_icmp_info(icmp_info)
local icmp_utils = require "icmp_utils"
if icmp_info.code then
icmp_info.code = icmp_utils.get_icmp_code(icmp_info.type, icmp_info.code)
end
if icmp_info.type then
icmp_info.type = icmp_utils.get_icmp_type(icmp_info.type)
end
return icmp_info
end
-- ##############################################
function format_http_info(http_info, no_html)
if http_info["last_return_code"] then
if http_info["last_return_code"] ~= 0 then
if no_html then
http_info["last_method"] = http_info["last_method"]
else
local badge = get_badge(http_info.last_return_code < 400)
http_info["last_return_code"] = string.format('%s', badge,
http_utils.getResponseStatusCode(http_info["last_return_code"]))
end
end
end
if http_info["last_method"] then
if no_html then
http_info["last_method"] = http_info["last_method"]
else
http_info["last_method"] = string.format('%s', http_info["last_method"])
end
end
if http_info["last_url"] then
local url = http_info["last_url"]
if string.find(http_info["last_url"], '^/') then
url = (http_info["server_name"] or "") .. http_info["last_url"]
end
url = string.gsub(url, " ", "") -- Clean the URL from spaces and %20, spaces in html
if not string.find(url, '*') then
if no_html then
http_info["last_url"] = url
else
http_info["last_url"] = i18n("external_link_url", {
proto = 'http',
url = url,
url_name = url
})
end
end
end
return http_info
end
-- ##############################################
function format_common_info(flow_info, formatted_info)
local predominant_bytes = i18n("traffic_srv_to_cli")
if (tonumber(flow_info["cli2srv_bytes"] or 0)) > (tonumber(flow_info["srv2cli_bytes"] or 0)) then
predominant_bytes = i18n("traffic_cli_to_srv")
end
formatted_info["predominant_direction"] = predominant_bytes
formatted_info["server_traffic"] = bytesToSize(flow_info["srv2cli_bytes"] or 0)
formatted_info["client_traffic"] = bytesToSize(flow_info["cli2srv_bytes"] or 0)
return formatted_info
end
-- ##############################################
function format_proto_info(flow_details, proto_info)
local proto_details = {}
for key, value in pairs(proto_info) do
if type(value) ~= "table" then
proto_info[key] = nil
end
end
for proto, info in pairs(proto_info or {}) do
if proto == "tls" then
proto_details[proto] = format_tls_info(info)
break
elseif proto == "dns" then
proto_details[proto] = format_dns_query_info(info)
break
elseif proto == "http" then
proto_details[proto] = format_http_info(info)
break
elseif proto == "icmp" then
proto_details[proto] = format_icmp_info(info)
break
end
end
for protocol, protocol_info in pairs(proto_details) do
local rsp = {
name = i18n('alerts_dashboard.flow_related_info_composed', {
proto = i18n(protocol)
}),
values = {""}
}
flow_details[#flow_details + 1] = rsp
for info_name, info_value in pairsByKeys(protocol_info) do
rsp = {
name = "",
values = {"" .. i18n(info_name) .. "", info_value}
}
flow_details[#flow_details + 1] = rsp
end
end
return flow_details
end
-- ##############################################
-- @brief This function, given an IP and a vlan return the concat of host@vlan
-- @params host_ip: A string containing the IP
-- vlan: A string or a number containing the vlan id
-- @return A string IP@vlan
function format_ip_vlan(ip, vlan)
local host = ip
if (vlan) and (tonumber(vlan) ~= 0) then
host = host .. '@' .. (tonumber(vlan) or vlan)
end
return host
end
-- ##############################################
-- @brief This function, given an alert and "cli" or "srv" string is going to return the formatted hostname
-- @params alert: A table with the alert infos
-- cli_srv: A string "cli" or "srv" used to get the required info
-- @return A string hostname@vlan
function format_alert_hostname(alert, cli_srv)
local host = alert[cli_srv .. "_name"]
if (isEmptyString(host)) then
host = alert[cli_srv .. "_ip"]
end
return format_ip_vlan(shortenString(host, 26), alert["vlan"])
end
-- ##############################################
-- @brief This function format the info field used in tables
-- @params info: A string containing the info field
-- no_html: A boolean, true if no_html is requested (e.g. Download in CSV format),
-- false otherwise
-- @return A string containing the info field formatted
function format_external_link(url, name, no_html, proto, i18n_key)
if (string.contains(url, " ")) then
-- the string contains spaces, so it's not an URL
-- Let's return it as it
return (url)
else
local external_field = url
proto = ternary(((proto) and (proto == 'http' or proto == 'HTTP')), 'http', 'https')
if no_html == false then
if not isEmptyString(url) and not string.find(url, '*') then
if (i18n_key == nil) then
i18n_key = "external_link_url"
end
url = string.gsub(url, " ", "") -- Clean the URL from spaces and %20, spaces in html
external_field = i18n(i18n_key, {
proto = proto,
url = url,
url_name = name
})
end
end
return external_field
end
end
-- ##############################################
function format_confidence_badge(confidence, shorten_string)
local badge = ""
if confidence == 0 or confidence == -1 then
badge = "" ..
get_confidence(confidence, shorten_string) .. ""
elseif confidence then
badge = "" ..
get_confidence(confidence, shorten_string) .. ""
end
return badge
end
-- ##############################################
function format_query_direction(op, val)
local historical_flow_utils = require "historical_flow_utils"
local direction_where = ""
if val == "0" then
direction_where = "(" .. historical_flow_utils.get_flow_column_by_tag("cli_location") .. " " .. op ..
" '0' AND " .. historical_flow_utils.get_flow_column_by_tag("srv_location") .. " " .. op ..
" '0')"
elseif val == "1" then
direction_where = "(" .. historical_flow_utils.get_flow_column_by_tag("cli_location") .. " " .. op ..
" '1' AND " .. historical_flow_utils.get_flow_column_by_tag("srv_location") .. " " .. op ..
" '1')"
elseif val == "2" then
direction_where = "(" .. historical_flow_utils.get_flow_column_by_tag("cli_location") .. " " .. op ..
" '0' AND " .. historical_flow_utils.get_flow_column_by_tag("srv_location") .. " " .. op ..
" '1')"
elseif val == "3" then
direction_where = "(" .. historical_flow_utils.get_flow_column_by_tag("cli_location") .. " " .. op ..
" '1' AND " .. historical_flow_utils.get_flow_column_by_tag("srv_location") .. " " .. op ..
" '0')"
end
return direction_where
end
-- ##############################################
function format_confidence_from_json(record)
local json = require "dkjson"
local alert_json = {}
local confidence = nil
if record["ALERT_JSON"] then
alert_json = json.decode(record["ALERT_JSON"])
elseif record["json"] then
alert_json = json.decode(record["json"])
end
if (alert_json) and (alert_json.proto) and (alert_json.proto.confidence) and
(not isEmptyString(alert_json.proto.confidence)) then
confidence = get_confidence(alert_json.proto.confidence)
end
return confidence
end
-- ##############################################
function format_location_badge(location)
local loc = string.lower(location) or ""
if loc == "local" then
loc = i18n("details.label_short_local_host_badge")
elseif loc == "remote" then
loc = i18n("details.label_short_remote_host_badge")
elseif loc == 'multicast' then
loc = i18n('details.label_short_multicast_host_badge')
end
return loc
end
-- ##############################################
function format_utils.formatSNMPInterface(snmpdevice, interface_index)
local interface_name = format_portidx_name(snmpdevice, interface_index)
return string.format('%s (%s)', interface_index, (interface_name))
end
-- ##############################################
-- Note that ifname can be set by Lua.cpp so don't touch it if already defined
if ((ifname == nil) and (_GET ~= nil)) then
ifname = _GET["ifid"]
if (ifname ~= nil) then
if (ifname .. "" == tostring(tonumber(ifname)) .. "") then
require "label_utils"
-- ifname does not contain the interface name but rather the interface id
ifname = getInterfaceName(ifname, true)
if (ifname == "") then
ifname = nil
end
end
end
if (debug_session) then
traceError(TRACE_DEBUG, TRACE_CONSOLE, "Session => Session:" .. _SESSION["session"])
end
if ((ifname == nil) and (_SESSION ~= nil)) then
if (debug_session) then
traceError(TRACE_DEBUG, TRACE_CONSOLE, "Session => set ifname by _SESSION value")
end
ifname = _SESSION["ifname"]
if (debug_session) then
traceError(TRACE_DEBUG, TRACE_CONSOLE, "Session => ifname:" .. ifname)
end
else
if (debug_session) then
traceError(TRACE_DEBUG, TRACE_CONSOLE, "Session => set ifname by _GET value")
end
end
end
--
-- IMPORTANT
-- Leave it at the end so it can use the functions
-- defined in this file
--
http_lint = require "http_lint"
if (trace_script_duration ~= nil) then
io.write(debug.getinfo(1, 'S').source .. " executed in " .. (os.clock() - clock_start) * 1000 .. " ms\n")
end