ntopng/scripts/lua/rest/v2/charts/host/map.lua
2022-01-24 16:46:26 +01:00

448 lines
11 KiB
Lua

--
-- (C) 2013-22 - ntop.org
--
local dirs = ntop.getDirs()
package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path
require "lua_utils"
local rest_utils = require("rest_utils")
local callback_utils = require("callback_utils")
local hosts_map_utils = require("hosts_map_utils")
local HostsMapMode = hosts_map_utils.HostsMapMode
local MODES = hosts_map_utils.MODES
local MAX_RADIUS_PX = 30
local MIN_RADIUS_PX = 3
local rc = rest_utils.consts.success.ok
local first_host_table = {}
local second_host_table = {}
local max_radius = 0
-- Note To change the label "Remote Hosts" and "Local Hosts" shown
-- into the chart, just change the value of these names
local first_table_name = "Local Hosts"
local second_table_name = "Remote Hosts"
-- Change check_condition if you want a different condition to put hosts into the tables
local check_condition
local formatHost
local bubble_mode = tonumber(_GET["bubble_mode"]) or 0
local show_remote = _GET["show_remote"] or true
local ifid = _GET["ifid"]
if isEmptyString(ifid) then
rc = rest_utils.consts.err.invalid_interface
rest_utils.answer(rc)
return
end
interface.select(ifid)
-- ###################################################
local function shrinkTable(t, max_num)
local n = 1
local t2 = {}
for i,v in pairsByField(t, 'z', rev) do
if(n < max_num) then
t2[n] = v
n = n + 1
end
end
return(t2)
end
-- List of the functions used to get the necessary functions
-- ###################################################
local function allFlows(hostname, host, label)
local line
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = host["active_flows.as_server"],
y = host["active_flows.as_client"],
z = host["bytes.sent"] + host["bytes.rcvd"]
}
return line
end
-- ###################################################
local function unreachableFlows(hostname, host, label)
local line
if (host["unreachable_flows.as_server"] + host["unreachable_flows.as_client"] > 0) then
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = host["unreachable_flows.as_server"],
y = host["unreachable_flows.as_client"],
z = host["bytes.sent"] + host["bytes.rcvd"]
}
end
return line
end
-- ###################################################
local function alertedFlows(hostname, host, label)
local line
if ((host["alerted_flows.as_server"] ~= nil) and
(host["alerted_flows.as_client"] ~= nil) and
(host["alerted_flows.as_server"] + host["alerted_flows.as_client"] > 0)) then
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = host["alerted_flows.as_server"],
y = host["alerted_flows.as_client"],
z = host["alerted_flows.as_server"] + host["alerted_flows.as_client"]
}
end
return line
end
-- ###################################################
local function dnsQueries(hostname, host, label)
local line
if ((host["dns"] ~= nil) and
((host["dns"]["sent"]["num_queries"] + host["dns"]["rcvd"]["num_queries"]) > 0)) then
local x = host["dns"]["rcvd"]["num_replies_ok"]
local y = host["dns"]["sent"]["num_queries"]
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = x,
y = y,
z = x + y
}
end
return line
end
-- ###################################################
local function synDistribution(hostname, host, label)
local line
local stats = interface.getHostInfo(host["ip"], host["vlan"])
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = stats["pktStats.sent"]["tcp_flags"]["syn"],
y = stats["pktStats.recv"]["tcp_flags"]["syn"],
z = host["active_flows.as_client"] + host["active_flows.as_server"]
}
return line
end
-- ###################################################
local function synVsRst(hostname, host, label)
local line
local stats = interface.getHostInfo(host["ip"], host["vlan"])
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = stats["pktStats.sent"]["tcp_flags"]["syn"],
y = stats["pktStats.recv"]["tcp_flags"]["rst"],
z = host["active_flows.as_client"] + host["active_flows.as_server"]
}
return line
end
-- ###################################################
local function synVsSynack(hostname, host, label)
local line
local stats = interface.getHostInfo(host["ip"], host["vlan"])
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = stats["pktStats.sent"]["tcp_flags"]["syn"],
y = stats["pktStats.recv"]["tcp_flags"]["synack"],
z = host["active_flows.as_client"] + host["active_flows.as_server"]
}
return line
end
-- ###################################################
local function tcpPktsSentVsRcvd(hostname, host, label)
local line
local stats = interface.getHostInfo(host["ip"], host["vlan"])
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = stats["tcp.packets.sent"],
y = stats["tcp.packets.rcvd"],
z = stats["tcp.bytes.sent"] + stats["tcp.bytes.rcvd"]
}
return line
end
-- ###################################################
local function tcpBytesSentVsRcvd(hostname, host, label)
local line
local stats = interface.getHostInfo(host["ip"], host["vlan"])
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = stats["tcp.bytes.sent"],
y = stats["tcp.bytes.rcvd"],
z = stats["tcp.bytes.sent"] + stats["tcp.bytes.rcvd"]
}
return line
end
-- ###################################################
local function activeAlertFlows(hostname, host, label)
local line
if (host["active_alerted_flows"] > 0) then
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = host["active_flows.as_server"],
y = host["active_flows.as_client"],
z = host["active_alerted_flows"]
}
end
return line
end
-- ###################################################
local function trafficRatio(hostname, host, label)
local line
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = host["bytes_ratio"],
y = host["pkts_ratio"],
z = host["bytes.sent"] + host["bytes.rcvd"]
}
return line
end
-- ###################################################
local function score(hostname, host, label)
local line
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = host["score.as_client"],
y = host["score.as_server"],
z = host["score.as_client"] + host["score.as_server"]
}
return line
end
-- ###################################################
local function blacklistedFlowsHosts(hostname, host, label)
local line
line = {
meta = {
url_query = "host="..hostname,
label = label,
},
x = host.num_blacklisted_flows.as_client,
y = host.num_blacklisted_flows.as_server,
z = host.num_blacklisted_flows.as_client + host.num_blacklisted_flows.as_server
}
return line
end
-- ###################################################
local function processHost(hostname, host)
local line
local label = host.name
check_condition = (host.localhost ~= nil) and (host.localhost == true)
-- starts is defined inside the lua_utils module
if ((label == nil) or (string.len(label) == 0) or starts(label, "@")) then
label = hostname
end
line = nil
line = formatHost(hostname, host, label)
if (line ~= nil) then
if (line.z > max_radius) then
max_radius = line.z
end
if(check_condition) then
table.insert(first_host_table, line)
else
table.insert(second_host_table, line)
end
end
end
-- ###################################################
-- Switch case used to know which function to format the hosts needs to be used
if (bubble_mode == HostsMapMode.ALL_FLOWS) then
formatHost = allFlows
elseif (bubble_mode == HostsMapMode.UNREACHABLE_FLOWS) then
formatHost = unreachableFlows
elseif (bubble_mode == HostsMapMode.ALERTED_FLOWS) then
formatHost = alertedFlows
elseif (bubble_mode == HostsMapMode.DNS_QUERIES) then
formatHost = dnsQueries
elseif (bubble_mode == HostsMapMode.SYN_DISTRIBUTION) then
formatHost = synDistribution
elseif (bubble_mode == HostsMapMode.SYN_VS_RST) then
formatHost = synVsRst
elseif (bubble_mode == HostsMapMode.SYN_VS_SYNACK) then
formatHost = synVsSynack
elseif (bubble_mode == HostsMapMode.TCP_PKTS_SENT_VS_RCVD) then
formatHost = tcpPktsSentVsRcvd
elseif (bubble_mode == HostsMapMode.TCP_BYTES_SENT_VS_RCVD) then
formatHost = tcpBytesSentVsRcvd
elseif (bubble_mode == HostsMapMode.ACTIVE_ALERT_FLOWS) then
formatHost = activeAlertFlows
elseif (bubble_mode == HostsMapMode.TRAFFIC_RATIO) then
formatHost = trafficRatio
elseif (bubble_mode == HostsMapMode.SCORE) then
formatHost = score
elseif (bubble_mode == HostsMapMode.BLACKLISTED_FLOWS_HOSTS) then
formatHost = blacklistedFlowsHosts
end
-- Callback cycle
if (show_remote) then
callback_utils.foreachHost(ifname, processHost)
else
callback_utils.foreachLocalHost(ifname, processHost)
end
-- Reduce the number of hosts to a reasonable value (< max_num)
local max_num = 999
first_host_table = shrinkTable(first_host_table, max_num)
second_host_table = shrinkTable(second_host_table, max_num)
-- Normalize values
local ratio = max_radius / MAX_RADIUS_PX
for i,v in pairs(first_host_table) do
first_host_table[i].z = math.floor(MIN_RADIUS_PX + first_host_table[i].z / ratio)
end
if (show_remote) then
for i,v in pairs(second_host_table) do
second_host_table[i].z = math.floor(MIN_RADIUS_PX + second_host_table[i].z / ratio)
end
end
local base_url = ntop.getHttpPrefix() .. "/lua/host_details.lua"
-- Formatting Answer
rest_utils.answer(rc, {
series = {
{data = first_host_table, name = first_table_name, base_url = base_url},
{data = second_host_table, name = second_table_name, base_url = base_url},
},
chart = {
zoom = {
autoScaleYaxis = true
},
},
events = {
dataPointSelection = "standard",
},
grid = {
padding = {
left = 6
},
},
colors = {"rgba(153, 102, 255, 0.45)", "rgba(255, 159, 64, 0.45)"},
xaxis = {
type = 'numeric',
title = {
text = MODES[bubble_mode + 1].x_label,
},
labels = {
ntop_utils_formatter = MODES[bubble_mode + 1].x_formatter or 'fnone',
}
},
yaxis = {
type = 'numeric',
forceNiceScale = true,
title = {
text = MODES[bubble_mode + 1].y_label,
offsetX = 6
},
labels = {
ntop_utils_formatter = MODES[bubble_mode + 1].y_formatter or 'fnone',
}
},
dataLabels = {
enabled = false
},
tooltip = {
custom = "format_label_from_xy",
}
})