--
-- (C) 2013-21 - ntop.org
--
local dirs = ntop.getDirs()
package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path
require "lua_utils"
require "flow_utils"
local alerts_api = require "alerts_api"
local format_utils = require("format_utils")
local alert_consts = require "alert_consts"
local flow_utils = require "flow_utils"
local icmp_utils = require "icmp_utils"
local json = require "dkjson"
local have_nedge = ntop.isnEdge()
sendHTTPContentTypeHeader('application/json')
local debug = false
local debug_process = false -- Show flow processed information
local ifstats = interface.getStats()
local delta_cache = "ntopng.interface_filtered_traffic_" .. ifstats.id
-- System host parameters
local hosts = _GET["hosts"]
local host = _GET["host"] -- TODO: merge
local flows_to_update = _GET["custom_hosts"]
-- Get from redis the throughput type bps or pps
local throughput_type = getThroughputType()
local flows_filter = getFlowsFilter()
local flows_stats
local total = 0
if not flows_to_update then
flows_stats = interface.getFlowsInfo(flows_filter["hostFilter"], flows_filter)
total = flows_stats["numFlows"]
flows_stats = flows_stats["flows"]
else
flows_stats = {}
-- Only update the requested rows
for _, k in pairs(split(flows_to_update, ",")) do
local flow_key_and_hash = string.split(k, "@") or {}
if(#flow_key_and_hash == 2) then
local flow = interface.findFlowByKeyAndHashId(tonumber(flow_key_and_hash[1]), tonumber(flow_key_and_hash[2]))
if flow then
flows_stats[#flows_stats + 1] = flow
end
end
end
end
-- Prepare host
local host_list = {}
local num_host_list = 0
local single_host = 0
if(hosts ~= nil) then host_list, num_host_list = getHostCommaSeparatedList(hosts) end
if(host ~= nil) then
single_host = 1
num_host_list = 1
end
if(flows_stats == nil) then flows_stats = { } end
for key, value in ipairs(flows_stats) do
local info = ""
-- use an italic font to indicate extra information added after sorting
local italic = true
if(not isEmptyString(flows_stats[key]["info"])) then
info = flows_stats[key]["info"]
italic = false
elseif(not isEmptyString(flows_stats[key]["icmp"])) then
info = icmp_utils.get_icmp_label(ternary(isIPv4(flows_stats[key]["cli.ip"]), 4, 6), flows_stats[key]["icmp"]["type"], flows_stats[key]["icmp"]["code"])
elseif(flows_stats[key]["proto.ndpi"] == "SIP") then
info = getSIPInfo(flows_stats[key])
elseif(flows_stats[key]["proto.ndpi"] == "RTP") then
info = getRTPInfo(flows_stats[key])
end
if(starts(info, "%s", info)
end
info = shortenString(info)
flows_stats[key]["info"] = ""..info..""
end
if(flows_stats[key]["profile"] ~= nil) then
flows_stats[key]["info"] = formatTrafficProfile(flows_stats[key]["profile"])..flows_stats[key]["info"]
end
end
local formatted_res = {}
for _key, value in ipairs(flows_stats) do -- pairsByValues(vals, funct) do
local record = {}
local key = value["ntopng.key"]
local info_cli = interface.getHostMinInfo(value["cli.ip"], value["cli.vlan"])
local info_srv = interface.getHostMinInfo(value["srv.ip"], value["srv.vlan"])
-- Retrieving first Alt Name then Name if no value is found then use ip
local srv_name = getHostAltName(value["srv.ip"])
if isEmptyString(srv_name) then
srv_name = info_srv["name"]
end
if isEmptyString(srv_name) then
srv_name = value["srv.ip"]
end
local cli_name = getHostAltName(value["cli.ip"])
if isEmptyString(cli_name) then
cli_name = info_cli["name"]
end
if isEmptyString(cli_name) then
cli_name = value["cli.ip"]
end
local src_port, dst_port = '', ''
local src_process, dst_process = '', ''
local src_container, dst_container = '', ''
if(cli_name == nil) then cli_name = "???" end
if(srv_name == nil) then srv_name = "???" end
local cli_tooltip = cli_name:gsub("'","'")
local srv_tooltip = srv_name:gsub("'","'")
if((value["tcp.nw_latency.client"] ~= nil) and (value["tcp.nw_latency.client"] > 0)) then
cli_tooltip = cli_tooltip.."
nw latency: "..string.format("%.3f", value["tcp.nw_latency.client"]).." ms"
end
if((value["tcp.nw_latency.server"] ~= nil) and (value["tcp.nw_latency.server"] > 0)) then
srv_tooltip = srv_tooltip.."
nw latency: "..string.format("%.3f", value["tcp.nw_latency.server"]).." ms"
end
if value["cli.allowed_host"] and not ifstats.isViewed then
local src_name = shortenString(stripVlan(cli_name))
if(value["cli.systemhost"] == true) then src_name = src_name .. " " end
src_key = hostinfo2detailshref(flow2hostinfo(value, "cli"), nil, src_name, cli_tooltip, false)
if value["cli.port"] > 0 or value["proto.l4"] == "TCP" or value["proto.l4"] == "UDP" then
src_port = ""..ntop.getservbyport(value["cli.port"], string.lower(value["proto.l4"]))..""
end
--record["column_client_process"] = flowinfo2process(value["client_process"], hostinfo2url(value,"cli"))
src_process = flowinfo2process(value["client_process"], hostinfo2url(value,"cli"))
src_container = flowinfo2container(value["client_container"])
else
src_key = shortenString(stripVlan(cli_name))
if value["cli.port"] > 0 then
src_port = value["cli.port"]..''
end
end
if value["srv.allowed_host"] and not ifstats.isViewed then
local dst_name = shortenString(stripVlan(srv_name))
if(value["srv.systemhost"] == true) then dst_name = dst_name .. " " end
dst_key = hostinfo2detailshref(flow2hostinfo(value, "srv"), nil, dst_name, srv_tooltip, false)
if value["srv.port"] > 0 or value["proto.l4"] == "TCP" or value["proto.l4"] == "UDP" then
dst_port=""..ntop.getservbyport(value["srv.port"], string.lower(value["proto.l4"]))..""
else
dst_port=""
end
--record["column_server_process"] = flowinfo2process(value["server_process"], hostinfo2url(value,"srv"))
dst_process = flowinfo2process(value["server_process"], hostinfo2url(value,"srv"))
dst_container = flowinfo2container(value["server_container"])
if value["server_container"] and value["server_container"].id then
record["column_server_container"] = '' .. format_utils.formatContainer(value["server_container"]) .. ''
if value["server_container"]["k8s.pod"] then
record["column_server_pod"] = '' .. shortenString(value["server_container"]["k8s.pod"]) .. ''
end
end
else
dst_key = shortenString(stripVlan(srv_name))
if value["srv.port"] > 0 then
dst_port = value["srv.port"]..""
end
end
if(value["client_tcp_info"] ~= nil) then
record["column_client_rtt"] = format_utils.formatMillis(value["client_tcp_info"]["rtt"])
end
if(value["server_tcp_info"] ~= nil) then
record["column_server_rtt"] = format_utils.formatMillis(value["server_tcp_info"]["rtt"])
end
local column_key = ""
if(have_nedge) then
if (value["verdict.pass"]) then
column_key = column_key.." "
else
column_key = column_key.." "
end
end
record["column_key"] = column_key
record["key"] = string.format("%u", value["ntopng.key"])
record["hash_id"] = string.format("%u", value["hash_entry_id"])
record["key_and_hash"] = string.format("%s@%s", record["key"], record["hash_id"])
local column_client = src_key
if info_cli then
column_client = column_client..format_utils.formatMainAddressCategory(info_cli)
end
column_client = string.format("%s%s%s %s %s",
column_client,
ternary(src_port ~= '', ':', ''),
src_port, src_process, src_container)
if(value["verdict.pass"] == false) then
column_client = ""..column_client..""
end
record["column_client"] = column_client
local column_server = dst_key
if info_srv then
column_server = column_server..format_utils.formatMainAddressCategory(info_srv)
end
column_server = string.format("%s%s%s %s %s",
column_server,
ternary(dst_port ~= '', ':', ''),
dst_port, dst_process, dst_container)
if(value["verdict.pass"] == false) then
column_server = ""..column_server..""
end
record["column_server"] = column_server
record["column_vlan"] = ''
if((value["vlan"] ~= nil)) then
record["column_vlan"] = value["vlan"]
end
local column_proto_l4 = ''
if value["predominant_alert"] then
local alert_info = alert_consts.alertTypeLabel(value["predominant_alert"], true)
column_proto_l4 = alert_consts.alertTypeIcon(value["predominant_alert"], value["alerted_severity"]) -- " "
end
column_proto_l4 = column_proto_l4..value["proto.l4"]
if(value["verdict.pass"] == false) then
column_proto_l4 = ""..column_proto_l4..""
end
record["column_proto_l4"] = column_proto_l4
local app = getApplicationLabel(value["proto.ndpi"])
if(value["verdict.pass"] == false) then
app = ""..app..""
end
record["column_ndpi"] = app -- can't set the hosts_stats hyperlink for viewed interfaces
if not ifstats.isViewed then
record["column_ndpi"] = ""..app.." " .. formatBreed(value["proto.ndpi_breed"]) ..""
end
record["column_duration"] = secondsToTime(value["duration"])
record["column_bytes"] = value["bytes"]
local column_thpt = ''
if(throughput_type == "pps") then
column_thpt = value["throughput_pps"]
else
column_thpt = 8 * value["throughput_bps"]
end
if false then
if((value["throughput_trend_"..throughput_type] ~= nil)
and (value["throughput_trend_"..throughput_type] > 0)) then
if(value["throughput_trend_"..throughput_type] == 1) then
column_thpt = column_thpt..""
elseif(value["throughput_trend_"..throughput_type] == 2) then
column_thpt = column_thpt..""
elseif(value["throughput_trend_"..throughput_type] == 3) then
column_thpt = column_thpt..""
end
end
end
record["column_thpt"] = column_thpt
local cli2srv = round((value["cli2srv.bytes"] * 100) / value["bytes"], 0)
record["column_breakdown"] = "