-- -- (C) 2013-24 - ntop.org -- dirs = ntop.getDirs() package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path require "template" require "voip_utils" require "lua_utils" local graph_utils = require "graph_utils" local tcp_flow_state_utils = require("tcp_flow_state_utils") local format_utils = require("format_utils") local flow_consts = require "flow_consts" local alert_consts = require "alert_consts" local json = require("dkjson") if ntop.isPro() then package.path = dirs.installdir .. "/scripts/lua/pro/modules/?.lua;" .. package.path shaper_utils = require("shaper_utils") end -- The same base id of the ntop_flow.h file local ntop_base_id = 57472 -- Keep in sync with the defines in ntop_flow.h, -- otherwise it could happen that some fields are not mapped local flow_label_id = { [tostring(ntop_base_id + 524)] = 'COMMUNITY_ID' } -- ####################### local flow_verdict_mapping = {"Unknown", -- 0 "Pass", -- 1 "Drop" -- 2 } local flow_verdict_icon = {'', '', ''} -- ####################### function getFlowLabelFromId(id) local label = flow_label_id[tostring(id)] if label == nil then label = id end return label end -- ####################### -- Given a field and a flow, checks if the flow already has a non empty field function fieldAlreadyPresent(field, flow) field = string.lower(field) if (flow[field]) and (not isEmptyString(flow[field])) then return true end return false end -- ####################### function parseFlowVerdict(flow_verdict, minimal) if flow_verdict_mapping[flow_verdict + 1] then if minimal then return flow_verdict_mapping[flow_verdict + 1] .. " " .. flow_verdict_icon[flow_verdict + 1] else return (flow_verdict .. " (" .. flow_verdict_mapping[flow_verdict + 1] .. " " .. flow_verdict_icon[flow_verdict + 1] .. ")") end end return flow_verdict end -- ####################### function addFlowVerdictBadge(flow_verdict, minimal) local flow_verdict_class = "badge bg-secondary" if tonumber(flow_verdict) == 1 then flow_verdict_class = "badge bg-success" elseif tonumber(flow_verdict) == 2 then flow_verdict_class = "badge bg-danger" end local flow_verdict_formatted = parseFlowVerdict(flow["flow_verdict"], minimal) return '' .. flow_verdict_formatted .. '' end -- ####################### function formatInterfaceId(id, idx, snmpdevice) if (id == 65535) then return ("Unknown") else if (snmpdevice ~= nil) then return ('' .. id .. '') else return (id) end end end -- ####################### function formatTrafficProfile(profile) local res = "" if not isEmptyString(profile) then res = "" .. profile .. " " end return res end -- ####################### -- Extracts the information serialized into alert_info from the flow -- checks function flow2alertinfo(flow) local alert_info = flow["alert_info"] if (alert_info and (string.sub(alert_info, 1, 1) == "{")) then local res = json.decode(alert_info) if (res ~= nil) then return (res) end end return (alert_info) end -- ####################### function getFlowsFilter() -- Pagination local sortColumn = _GET["sortColumn"] local sortOrder = _GET["sortOrder"] local currentPage = _GET["currentPage"] local perPage = _GET["perPage"] -- Other Filters local port = _GET["port"] local application = _GET["application"] local category = _GET["category"] local network_id = _GET["network"] local traffic_profile = _GET["traffic_profile"] local traffic_type = _GET["traffic_type"] local flowhosts_type = _GET["flowhosts_type"] local ipversion = _GET["version"] local l4proto = _GET["l4proto"] local vlan = _GET["vlan"] local username = _GET["username"] local host = _GET["host"] local pid_name = _GET["pid_name"] local container = _GET["container"] local pod = _GET["pod"] local icmp_type = _GET["icmp_type"] local icmp_code = _GET["icmp_cod"] local dscp_filter = _GET["dscp"] local host_pool = _GET["host_pool_id"] local flow_status = _GET["flow_status"] local flow_status_severity = _GET["flow_status_severity"] local alert_type = _GET["alert_type"] local alert_type_severity = _GET["alert_type_severity"] local deviceIP = _GET["deviceIP"] local inIfIdx = _GET["inIfIdx"] local outIfIdx = _GET["outIfIdx"] local asn = _GET["asn"] local tcp_state = _GET["tcp_flow_state"] local talking_with = _GET["talking_with"] local client = _GET["client"] local server = _GET["server"] local flow_info = _GET["flow_info"] local iface_index = tonumber(_GET["interface_filter"] or -1) if sortColumn == nil or sortColumn == "column_" or sortColumn == "" then sortColumn = getDefaultTableSort("flows") elseif sortColumn ~= "column_" and sortColumn ~= "" then tablePreferences("sort_flows", sortColumn) else sortColumn = "column_client" end if sortOrder == nil then sortOrder = getDefaultTableSortOrder("flows") elseif sortColumn ~= "column_" and sortColumn ~= "" then tablePreferences("sort_order_flows", sortOrder) end if currentPage == nil then currentPage = 1 else currentPage = tonumber(currentPage) end if perPage == nil then perPage = getDefaultTableSize() else perPage = tonumber(perPage) tablePreferences("rows_number", perPage) end if port ~= nil then port = tonumber(port) end if network_id ~= nil then network_id = tonumber(network_id) end local to_skip = (currentPage - 1) * perPage local a2z = false if sortOrder == "desc" then a2z = false else a2z = true end local pageinfo = { ["perPage"] = perPage, ["currentPage"] = currentPage, ["sortOrder"] = sortOrder or "", ["sortColumn"] = sortColumn or "", ["toSkip"] = to_skip, ["maxHits"] = perPage, ["a2zSortOrder"] = a2z, ["hostFilter"] = host, ["portFilter"] = port, ["LocalNetworkFilter"] = network_id, ["ifaceIndex"] = iface_index } if application ~= nil and application ~= "" then local param = string.split(application, "%.") if param and #param == 2 then -- Example 5.26 pageinfo["l7protoFilter"] = application else if not tonumber(application) then pageinfo["l7protoFilter"] = interface.getnDPIProtoId(application) else pageinfo["l7protoFilter"] = tonumber(application) end end end if category ~= nil and category ~= "" then if tonumber(category) then pageinfo["l7categoryFilter"] = tonumber(category) else pageinfo["l7categoryFilter"] = interface.getnDPICategoryId(category) end end if traffic_profile ~= nil then pageinfo["trafficProfileFilter"] = traffic_profile end if not isEmptyString(flowhosts_type) then if flowhosts_type == "local_origin_remote_target" then pageinfo["clientMode"] = "local" pageinfo["serverMode"] = "remote" elseif flowhosts_type == "local_only" then pageinfo["clientMode"] = "local" pageinfo["serverMode"] = "local" elseif flowhosts_type == "remote_origin_local_target" then pageinfo["clientMode"] = "remote" pageinfo["serverMode"] = "local" elseif flowhosts_type == "remote_only" then pageinfo["clientMode"] = "remote" pageinfo["serverMode"] = "remote" end end if not isEmptyString(traffic_type) then if traffic_type:contains("unicast") then pageinfo["unicast"] = true else pageinfo["unicast"] = false end if traffic_type:contains("one_way") then pageinfo["unidirectional"] = true end end if not isEmptyString(alert_type) then if alert_type == "normal" then pageinfo["alertedFlows"] = false pageinfo["filteredFlows"] = false elseif alert_type == "alerted" then pageinfo["alertedFlows"] = true elseif alert_type == "periodic" then pageinfo["periodicFlows"] = true pageinfo["filteredFlows"] = false elseif alert_type == "filtered" then pageinfo["filteredFlows"] = true else pageinfo["statusFilter"] = tonumber(alert_type) or alert_type end end if not isEmptyString(alert_type_severity) then local s = alert_consts.severity_groups[alert_type_severity] if s then pageinfo["statusSeverityFilter"] = s.severity_group_id end end if not isEmptyString(ipversion) then pageinfo["ipVersion"] = tonumber(ipversion) end if not isEmptyString(l4proto) then pageinfo["L4Protocol"] = tonumber(l4proto) end if not isEmptyString(vlan) then pageinfo["vlanIdFilter"] = tonumber(vlan) end if not isEmptyString(username) then pageinfo["usernameFilter"] = username end if not isEmptyString(pid_name) then pageinfo["pidnameFilter"] = pid_name end if not isEmptyString(container) then pageinfo["container"] = container end if not isEmptyString(pod) then pageinfo["pod"] = pod end if not isEmptyString(deviceIP) then pageinfo["deviceIpFilter"] = deviceIP if not isEmptyString(inIfIdx) then pageinfo["inIndexFilter"] = tonumber(inIfIdx) end if not isEmptyString(outIfIdx) then pageinfo["outIndexFilter"] = tonumber(outIfIdx) end end if not isEmptyString(asn) then pageinfo["asnFilter"] = tonumber(asn) end pageinfo["icmp_type"] = tonumber(icmp_type) pageinfo["icmp_code"] = tonumber(icmp_code) if not isEmptyString(dscp_filter) then pageinfo["dscpFilter"] = tonumber(dscp_filter) end if not isEmptyString(talking_with) then pageinfo["talkingWith"] = talking_with end if not isEmptyString(host_pool) then pageinfo["poolFilter"] = tonumber(host_pool) end if not isEmptyString(tcp_state) then pageinfo["tcpFlowStateFilter"] = tcp_state end if not isEmptyString(client) then pageinfo["client"] = client end if not isEmptyString(server) then pageinfo["server"] = server end if not isEmptyString(flow_info) then pageinfo["flow_info"] = flow_info end return pageinfo end -- ####################### function handleCustomFlowField(key, value, snmpdevice) if key == 'TCP_FLAGS' then return (formatTcpFlags(value)) elseif key == 'INPUT_SNMP' then return (formatInterfaceId(value, "inIfIdx", snmpdevice)) elseif key == 'OUTPUT_SNMP' then return (formatInterfaceId(value, "outIfIdx", snmpdevice)) elseif key == 'TOTAL_FLOWS_EXP' then return (format_utils.formatValue(value)) elseif key == 'EXPORTER_IPV4_ADDRESS' or key == 'NPROBE_IPV4_ADDRESS' then if ntop.isPro() then return ("" .. value .. "") else return (value) end elseif key == 'FLOW_USER_NAME' then elems = string.split(value, ';') if ((elems ~= nil) and (#elems == 6)) then r = '' imsi = elems[1] mcc = string.sub(imsi, 1, 3) if (flow_consts.mobile_country_code[mcc] ~= nil) then mcc_name = " [" .. flow_consts.mobile_country_code[mcc] .. "]" else mcc_name = "" end r = r .. "" r = r .. "" r = r .. "" r = r .. "" r = r .. "" r = r .. "" r = r .. "
" .. i18n("flow_details.imsi") .. "" .. elems[1] .. mcc_name r = r .. "
" .. i18n("flow_details.nsapi") .. "" .. elems[2] .. "
" .. i18n("flow_details.gsm_cell_lac") .. "" .. elems[3] .. "
" .. i18n("flow_details.gsm_cell_identifier") .. "" .. elems[4] .. "
" .. i18n("flow_details.sac_service_area_code") .. "" .. elems[5] .. "
" .. i18n("ip_address") .. "" .. ntop.inet_ntoa(elems[6]) .. "
" return (r) else return (value) end elseif key == 'SIP_TRYING_TIME' or key == 'SIP_RINGING_TIME' or key == 'SIP_INVITE_TIME' or key == 'SIP_INVITE_OK_TIME' or key == 'SIP_INVITE_FAILURE_TIME' or key == 'SIP_BYE_TIME' or key == 'SIP_BYE_OK_TIME' or key == 'SIP_CANCEL_TIME' or key == 'SIP_CANCEL_OK_TIME' then if (value ~= '0') then return (formatEpoch(value)) else return "0" end elseif key == 'RTP_IN_JITTER' or key == 'RTP_OUT_JITTER' then if (value ~= nil and value ~= '0') then return (value / 1000) else return 0 end elseif key == 'RTP_IN_MAX_DELTA' or key == 'RTP_OUT_MAX_DELTA' or key == 'RTP_MOS' or key == 'RTP_R_FACTOR' or key == 'RTP_IN_MOS' or key == 'RTP_OUT_MOS' or key == 'RTP_IN_R_FACTOR' or key == 'RTP_OUT_R_FACTOR' or key == 'RTP_IN_TRANSIT' or key == 'RTP_OUT_TRANSIT' then if (value ~= nil and value ~= '0') then return (value / 100) else return 0 end end -- Unformatted value if (type(value) == "boolean") then if (value) then value = i18n("yes") else value = i18n("no") end end return value end -- ####################### function formatTcpFlags(flags) if (flags == 0) then return ("") end rsp = "" if ((flags & 1) == 2) then rsp = rsp .. " SYN " end if ((flags & 16) == 16) then rsp = rsp .. " ACK " end if ((flags & 1) == 1) then rsp = rsp .. " FIN " end if ((flags & 4) == 4) then rsp = rsp .. " RST " end if ((flags & 8) == 8) then rsp = rsp .. " PUSH " end return (rsp .. "") end -- ####################### local dns_types = { ['A'] = 1, ['NS'] = 2, ['MD'] = 3, ['MF'] = 4, ['CNAME'] = 5, ['SOA'] = 6, ['MB'] = 7, ['MG'] = 8, ['MR'] = 9, ['NULL'] = 10, ['WKS'] = 11, ['PTR'] = 12, ['HINFO'] = 13, ['MINFO'] = 14, ['MX'] = 15, ['TXT'] = 16, ['AAAA'] = 28, ['A6'] = 38, ['SPF'] = 99, ['AXFR'] = 252, ['MAILB'] = 253, ['MAILA'] = 254, ['ANY'] = 255 } -- ####################### function get_dns_type(dns_type_name) if dns_types[dns_type_name] then return dns_types[dns_type_name] else return 0 end end -- ####################### function get_dns_type_label(dns_type) dns_type = tonumber(dns_type) if dns_type then for k, v in pairs(dns_types) do if v == dns_type then return k end end end return string.format("%u", dns_type) end -- ####################### function extractSIPCaller(caller) local i local j -- find string between \" and \" i = string.find(caller, "\\\"") if (i ~= nil) then j = string.find(caller, "\\\"", i + 2) if (j ~= nil) then return string.sub(caller, i + 2, j - 1) end end -- find string between " and " i = string.find(caller, "\"") if (i ~= nil) then j = string.find(caller, "\"", i + 1) if (j ~= nil) then return string.sub(caller, i + 1, j - 1) end end -- find string between : and @ i = string.find(caller, ":") if (i ~= nil) then j = string.find(caller, "@", i + 1) if (j ~= nil) then return string.sub(caller, i + 1, j - 1) end end return caller end -- ####################### function map_failure_resp_code(fail_resp_code_string) if (fail_resp_code_string ~= nil) then if (fail_resp_code_string == "200") then return "OK" end if (fail_resp_code_string == "100") then return "TRYING" end if (fail_resp_code_string == "180") then return "RINGING" end if (tonumber(fail_resp_code_string) > 399) then return "FAILURE" end end return fail_resp_code_string end -- ####################### local function formatFlowHost(flow, cli_or_srv, historical_bounds, hyperlink_suffix) local hyperlink_params if historical_bounds then hyperlink_params = { page = "historical", epoch_begin = historical_bounds[1], epoch_end = historical_bounds[2], detail_view = "top_l7_contacts" } elseif type(hyperlink_suffix) == "table" then hyperlink_params = hyperlink_suffix end local host local tooltip = '' if (cli_or_srv) then host = interface.getHostMinInfo(flow[cli_or_srv .. ".ip"], flow[cli_or_srv .. ".vlan"]) else host = interface.getHostMinInfo(flow[cli_or_srv .. ".ip"], flow[cli_or_srv .. ".vlan"]) end local host_name if (host ~= nil) then host_name = host["name"] tooltip = host["ip"] if isEmptyString(host_name) then host_name = host["ip"] tooltip = '' end end if (host_name == nil) then host_name = "" end host_name = host_name .. format_utils.formatFullAddressCategory(host) local mac if (host == nil) then mac = nil else mac = host["mac"] end return hostinfo2detailshref(flow2hostinfo(flow, cli_or_srv), hyperlink_params, host_name, tooltip, true --[[ perform link existance checks --]] ), mac end local function formatFlowPort(flow, cli_or_srv, port, historical_bounds) if not historical_bounds then return "" .. port .. "" end -- TODO port filter return hostinfo2detailshref(flow2hostinfo(flow, cli_or_srv), { page = "historical", epoch_begin = historical_bounds[1], epoch_end = historical_bounds[2], detail_view = "flows", port = port }, port, port, true --[[ check href existance --]] ) end function getFlowLabel(flow, show_macs, add_hyperlinks, historical_bounds, hyperlink_suffix, add_flag, add_hostnames, nohtml) if flow == nil then return "" end local cli_name = flowinfo2hostname(flow, "cli", nil, add_hostnames) local srv_name = flowinfo2hostname(flow, "srv", nil, add_hostnames) local cli_mac = flow["cli.mac"] local srv_mac = flow["srv.mac"] local cli_as = nil local srv_as = nil if ((not isIPv4(cli_name)) and (not isIPv6(cli_name))) then cli_name = shortenString(cli_name) end if ((not isIPv4(srv_name)) and (not isIPv6(srv_name))) then srv_name = shortenString(srv_name) end local cli_port local srv_port if flow["cli.port"] and (flow["cli.port"] > 0 or flow["proto.l4"] == "TCP" or flow["proto.l4"] == "UDP") then cli_port = flow["cli.port"] end if flow["srv.port"] and (flow["srv.port"] > 0 or flow["proto.l4"] == "TCP" or flow["proto.l4"] == "UDP") then srv_port = flow["srv.port"] end if add_hyperlinks then cli_name, cli_mac = formatFlowHost(flow, "cli", historical_bounds, hyperlink_suffix) srv_name, srv_mac = formatFlowHost(flow, "srv", historical_bounds, hyperlink_suffix) if cli_port then cli_port = formatFlowPort(flow, "cli", cli_port, historical_bounds) end if srv_port then srv_port = formatFlowPort(flow, "srv", srv_port, historical_bounds) end if ((flow.cli_as ~= nil) and (flow.cli_as ~= 0)) then cli_as = "" .. shortenString(flow.cli_as_name or "", 14) .. "" cli_mac = "" else if cli_mac and (cli_mac ~= "00:00:00:00:00:00") and not interface.isView() then cli_mac = "" .. cli_mac .. "" elseif interface.isView() and (cli_mac ~= "00:00:00:00:00:00") then cli_mac = cli_mac or "" else cli_mac = "" end end if ((flow.dst_as ~= nil) and (flow.dst_as ~= 0)) then dst_as = "" .. shortenString(flow.dst_as_name or "", 14) .. "" srv_mac = "" else if srv_mac and (srv_mac ~= "00:00:00:00:00:00") and not interface.isView() then srv_mac = "" .. srv_mac .. "" elseif interface.isView() and (srv_mac ~= "00:00:00:00:00:00") then srv_mac = srv_mac or "" else srv_mac = "" end end end local label = "" if not isEmptyString(cli_name) then label = label .. cli_name end if add_flag then local info = interface.getHostInfo(flow["cli.ip"], flow["cli.vlan"]) if (info ~= nil) then label = label .. getFlag(info["country"]) end end if cli_port then label = label .. ":" .. cli_port end if (cli_as ~= nil) then label = label .. " [ " .. cli_as .. " ]" else if show_macs and not isEmptyString(cli_mac) then label = label .. " [ " .. cli_mac .. " ]" end end if (not nohtml) then label = label .. "   " else label = label .. " -> " end if not isEmptyString(srv_name) then label = label .. srv_name end if add_flag then local info = interface.getHostInfo(flow["srv.ip"], flow["srv.vlan"]) if (info ~= nil) then label = label .. getFlag(info["country"]) end end if srv_port then label = label .. ":" .. srv_port end if (dst_as ~= nil) then label = label .. " [ " .. dst_as .. " ]" else if show_macs and not isEmptyString(srv_mac) then label = label .. " [ " .. srv_mac .. " ]" end end local s_info = flow2alertinfo(flow) if (s_info ~= nil) then if (not isEmptyString(s_info.info)) then label = label .. " [" .. s_info.info .. "]" end end return label end -- ####################### function getFlowKey(name) if tonumber(name) then name = getFlowLabelFromId(name) end local s = flow_consts.flow_fields_description[name] if (s == nil) then -- Try to decode the name as . -- then try to look up the name or directly the field -- in the rtemplate (pen is ignored). -- TODO: currently rtemplate is flat and PENs are ignored, we should add PEN there local pen, field = name:match("^(%d+)%.(%d+)$") local v = (rtemplate[tonumber(name)] or rtemplate[tonumber(field)]) if (v == nil) then return (name) end s = flow_consts.flow_fields_description[v] end if (s ~= nil) then s = string.gsub(s, "<", "<") s = string.gsub(s, ">", ">") return (s) else return (name) end end -- ####################### function fieldIDToFieldName(id) local id_num local name local pen_id = string.split(id, "%.") if pen_id then id_num = tonumber(pen_id[2]) else id_num = tonumber(id) end if id_num then name = rtemplate[id_num] else name = id end return name end -- ####################### function isFieldProtocol(protocol, field) if not field or not protocol then return false end local key_name = fieldIDToFieldName(field) if not key_name then return false end if starts(key_name, protocol) then return true end return false end -- ####################### function removeProtocolFields(protocol, array) elements_to_remove = {} n = 0 for key, value in pairs(array) do if (isFieldProtocol(protocol, key)) then elements_to_remove[n] = key n = n + 1 end end for key, value in pairs(elements_to_remove) do if (value ~= nil) then array[value] = nil end end return array end -- ####################### function isFlowValueDefined(info, field) if (info[field] ~= nil) then return true else for key, value in pairs(info) do local key_name = fieldIDToFieldName(key) if (key_name == field) then return true end end end return false end -- ####################### function getFlowValue(info, field) local return_value = "0" local value_original = "0" if ((info == nil) or (table.len(info) == 0)) then return ("") end if (info[field] ~= nil) then return_value = handleCustomFlowField(field, info[field]) value_original = info[field] else for key, value in pairs(info) do local key_name = fieldIDToFieldName(key) if (key_name == field) then return_value = handleCustomFlowField(key_name, value) value_original = value end end end return_value = string.gsub(return_value, "<", "<") return_value = string.gsub(return_value, ">", ">") return_value = string.gsub(return_value, "\"", "\\\"") -- io.write(field.." = ["..return_value..","..value_original.."]\n") return return_value, value_original end -- ####################### function mapCallState(call_state) -- return call_state if (call_state == "CALL_STARTED") then return (i18n("flow_details.call_started")) elseif (call_state == "CALL_IN_PROGRESS") then return (i18n("flow_details.ongoing_call")) elseif (call_state == "CALL_COMPLETED") then return ("" .. i18n("flow_details.call_completed") .. "") elseif (call_state == "CALL_ERROR") then return ("" .. i18n("flow_details.call_error") .. "") elseif (call_state == "CALL_CANCELED") then return ("" .. i18n("flow_details.call_canceled") .. "") else return (call_state) end end -- ####################### function isThereProtocol(protocol, info) local found = 0 for key, value in pairs(info) do if isFieldProtocol(protocol, key) then found = 1 break end end return found end -- ####################### function isThereSIPCall(info) local retVal = 0 local call_state = getFlowValue(info, "SIP_CALL_STATE") if ((call_state ~= nil) and (call_state ~= "")) then retVal = 1 end return retVal end -- ####################### function getSIPInfo(infoPar) local called_party = "" local calling_party = "" local sip_found_flow local returnString = "" local infoFlow, posFlow, errFlow = json.decode(infoPar["moreinfo.json"], 1, nil) if (infoFlow ~= nil) then sip_found_flow = isThereSIPCall(infoFlow) if (sip_found_flow == 1) then called_party = getFlowValue(infoFlow, "SIP_CALLED_PARTY") calling_party = getFlowValue(infoFlow, "SIP_CALLING_PARTY") called_party = string.gsub(called_party, "\\\"", "\"") calling_party = string.gsub(calling_party, "\\\"", "\"") called_party = extractSIPCaller(called_party) calling_party = extractSIPCaller(calling_party) if (((called_party == nil) or (called_party == "")) and ((calling_party == nil) or (calling_party == ""))) then returnString = "" else returnString = calling_party .. " " .. called_party end end end return returnString end -- ####################### function getRTPInfo(infoPar) local call_id local returnString = "" local infoFlow, posFlow, errFlow = json.decode(infoPar["moreinfo.json"], 1, nil) if infoFlow ~= nil then call_id = getFlowValue(infoFlow, "RTP_SIP_CALL_ID") if tostring(call_id) ~= "" then call_id = " " .. call_id else call_id = "" end returnString = call_id end if (infoPar.rtp_stream_type ~= nil) then if (infoPar.rtp_stream_type == "screen_share") then returnString = ' ' .. i18n("rtp.screen_share") ..'' elseif (infoPar.rtp_stream_type == "audio") then returnString = ' ' .. i18n("rtp.audio") .. '' elseif (infoPar.rtp_stream_type == "video") then returnString = ' ' .. i18n("rtp.video") .. '' elseif (infoPar.rtp_stream_type == "audio_video") then returnString = ' ' .. i18n("rtp.audio_video") .. '' end end return returnString end -- ####################### function getSIPTableRows(info) local string_table = "" local call_id = "" local call_id_ico = " " local called_party = "" local calling_party = "" local rtp_codecs = "" local sip_rtp_src_addr = 0 local sip_rtp_dst_addr = 0 local print_second = 0 local print_second_2 = 0 -- check if there is a SIP field sip_found = isThereProtocol("SIP", info) if (sip_found == 1) then sip_found = isThereSIPCall(info) end if (sip_found == 1) then string_table = string_table .. "" .. i18n("flow_details.sip_protocol_information") .. "\n" call_id = getFlowValue(info, "SIP_CALL_ID") if ((call_id == nil) or (call_id == "")) then string_table = string_table .. " " .. i18n("flow_details.call_id") .. " " .. call_id_ico .. "
\n" else string_table = string_table .. " " .. i18n("flow_details.call_id") .. " " .. call_id_ico .. "
" .. call_id .. "
\n" end called_party = getFlowValue(info, "SIP_CALLED_PARTY") calling_party = getFlowValue(info, "SIP_CALLING_PARTY") called_party = string.gsub(called_party, "\\\"", "\"") calling_party = string.gsub(calling_party, "\\\"", "\"") called_party = extractSIPCaller(called_party) calling_party = extractSIPCaller(calling_party) if (((called_party == nil) or (called_party == "")) and ((calling_party == nil) or (calling_party == ""))) then string_table = string_table .. "" .. i18n("flow_details.call_initiator") .. " " .. i18n("flow_details.called_party") .. "
\n" else string_table = string_table .. "" .. i18n("flow_details.call_initiator") .. " " .. i18n("flow_details.called_party") .. "
" .. calling_party .. " " .. called_party .. "
\n" end rtp_codecs = getFlowValue(info, "SIP_RTP_CODECS") if ((rtp_codecs == nil) or (rtp_codecs == "")) then string_table = string_table .. "" .. i18n("flow_details.rtp_codecs") .. "
\n" else string_table = string_table .. "" .. i18n("flow_details.rtp_codecs") .. "
" .. rtp_codecs .. "\n" end local string_table_1 = "" local string_table_2 = "" local string_table_3 = "" local string_table_4 = "" local string_table_5 = "" local show_rtp_stream = 0 if ((getFlowValue(info, "SIP_RTP_IPV4_SRC_ADDR") ~= nil) and (getFlowValue(info, "SIP_RTP_IPV4_SRC_ADDR") ~= "")) then sip_rtp_src_addr = 1 string_table_1 = getFlowValue(info, "SIP_RTP_IPV4_SRC_ADDR") if (string_table_1 ~= "0.0.0.0") then sip_rtp_src_address_ip = string_table_1 interface.select(ifname) rtp_host = interface.getHostInfo(string_table_1) if (rtp_host ~= nil) then string_table_1 = hostinfo2detailshref(rtp_host, nil, sip_rtp_src_address_ip) end end show_rtp_stream = 1 end if ((getFlowValue(info, "SIP_RTP_L4_SRC_PORT") ~= nil) and (getFlowValue(info, "SIP_RTP_L4_SRC_PORT") ~= "") and (sip_rtp_src_addr == 1)) then -- string_table = string_table ..":"..getFlowValue(info, "SIP_RTP_L4_SRC_PORT") -- string_table_2 = ":"..getFlowValue(info, "SIP_RTP_L4_SRC_PORT") sip_rtp_src_port = getFlowValue(info, "SIP_RTP_L4_SRC_PORT") string_table_2 = ":" string_table_2 = string_table_2 .. sip_rtp_src_port string_table_2 = string_table_2 .. "" show_rtp_stream = 1 end if ((sip_rtp_src_addr == 1) or ((getFlowValue(info, "SIP_RTP_IPV4_DST_ADDR") ~= nil) and (getFlowValue(info, "SIP_RTP_IPV4_DST_ADDR") ~= ""))) then -- string_table = string_table.." " string_table_3 = " " show_rtp_stream = 1 end if ((getFlowValue(info, "SIP_RTP_IPV4_DST_ADDR") ~= nil) and (getFlowValue(info, "SIP_RTP_IPV4_DST_ADDR") ~= "")) then sip_rtp_dst_addr = 1 string_table_4 = getFlowValue(info, "SIP_RTP_IPV4_DST_ADDR") if (string_table_4 ~= "0.0.0.0") then sip_rtp_dst_address_ip = string_table_4 interface.select(ifname) rtp_host = interface.getHostInfo(string_table_4) if (rtp_host ~= nil) then string_table_4 = hostinfo2detailshref(rtp_host, nil, sip_rtp_dst_address_ip) end end show_rtp_stream = 1 end if ((getFlowValue(info, "SIP_RTP_L4_DST_PORT") ~= nil) and (getFlowValue(info, "SIP_RTP_L4_DST_PORT") ~= "") and (sip_rtp_dst_addr == 1)) then -- string_table = string_table ..":"..getFlowValue(info, "SIP_RTP_L4_DST_PORT") -- string_table_5 = ":"..getFlowValue(info, "SIP_RTP_L4_DST_PORT") sip_rtp_dst_port = getFlowValue(info, "SIP_RTP_L4_DST_PORT") string_table_5 = ":" string_table_5 = string_table_5 .. sip_rtp_dst_port string_table_5 = string_table_5 .. "" show_rtp_stream = 1 end if (show_rtp_stream == 1) then string_table = string_table .. "" .. i18n("flow_details.rtp_stream_peers") .. " (src dst)
" else string_table = string_table .. "" .. i18n("flow_details.rtp_stream_peers") .. " (src dst)
" end string_table = string_table .. string_table_1 .. string_table_2 .. string_table_3 .. string_table_4 .. string_table_5 local rtp_flow_key = interface.getFlowKey(sip_rtp_src_address_ip or "", tonumber(sip_rtp_src_port) or 0, sip_rtp_dst_address_ip or "", tonumber(sip_rtp_dst_port) or 0, 17 --[[ UDP --]] ) -- TODO: fix if tonumber(rtp_flow_key) ~= nil and interface.findFlowByKeyAndHashId(tonumber(rtp_flow_key), 0) ~= nil then string_table = string_table .. ' ' string_table = string_table .. " " string_table = string_table .. sip_rtp_dst_address_ip .. ":" .. sip_rtp_dst_port .. "\">" string_table = string_table .. '' end string_table = string_table .. "
\n" val, val_original = getFlowValue(info, "SIP_REASON_CAUSE") if (val_original ~= "0") then string_table = string_table .. " " .. i18n("flow_details.cancel_bye_failure_reason_cause") .. "
" string_table = string_table .. val else string_table = string_table .. " " .. i18n("flow_details.cancel_bye_failure_reason_cause") .. "
" end string_table = string_table .. "
\n" if isFlowValueDefined(info, "SIP_C_IP") then string_table = string_table .. " " .. i18n("flow_details.c_ip_addresses") .. "
" .. getFlowValue(info, "SIP_C_IP") .. "
\n" end if ((getFlowValue(info, "SIP_CALL_STATE") == nil) or (getFlowValue(info, "SIP_CALL_STATE") == "")) then string_table = string_table .. " " .. i18n("flow_details.call_state") .. "
\n" else string_table = string_table .. " " .. i18n("flow_details.call_state") .. "
" .. mapCallState(getFlowValue(info, "SIP_CALL_STATE")) .. "
\n" end end return string_table end -- ####################### function getRTPTableRows(info) local string_table = "" -- check if there is a RTP field local rtp_found = isThereProtocol("RTP", info) if (rtp_found == 1) then -- SSRC string_table = string_table .. "" .. i18n("flow_details.rtp_protocol_information") .. "\n" if isFlowValueDefined(info, "RTP_SSRC") then sync_source_var = getFlowValue(info, "RTP_SSRC") if ((sync_source_var == nil) or (sync_source_var == "")) then sync_source_hide = "style=\"display: none;\"" else sync_source_hide = "style=\"display: table-row;\"" end string_table = string_table .. " " .. i18n("flow_details.sync_source_id") .. "
" .. sync_source_var .. "\n" end -- ROUND-TRIP-TIME if isFlowValueDefined(info, "RTP_RTT") then local rtp_rtt_var = getFlowValue(info, "RTP_RTT") if ((rtp_rtt_var == nil) or (rtp_rtt_var == "")) then rtp_rtt_hide = "style=\"display: none;\"" else rtp_rtt_hide = "style=\"display: table-row;\"" end string_table = string_table .. "" .. i18n("flow_details.round_trip_time") .. "" if ((rtp_rtt_var ~= nil) and (rtp_rtt_var ~= "")) then string_table = string_table .. rtp_rtt_var .. " ms " end string_table = string_table .. " \n" end -- RTP-IN-TRASIT if isFlowValueDefined(info, "RTP_IN_TRANSIT") then local rtp_in_transit = getFlowValue(info, "RTP_IN_TRANSIT") / 100 local rtp_out_transit = getFlowValue(info, "RTP_OUT_TRANSIT") / 100 if (((rtp_in_transit == nil) or (rtp_in_transit == "")) and ((rtp_out_transit == nil) or (rtp_out_transit == ""))) then rtp_transit_hide = "style=\"display: none;\"" else rtp_transit_hide = "style=\"display: table-row;\"" end string_table = string_table .. "" .. i18n("flow_details.rtp_transit_in_out") .. "
" .. getFlowValue(info, "RTP_IN_TRANSIT") .. "
" .. getFlowValue(info, "RTP_OUT_TRANSIT") .. "
\n" end -- TONES if isFlowValueDefined(info, "RTP_DTMF_TONES") then local rtp_dtmf_var = getFlowValue(info, "RTP_DTMF_TONES") if ((rtp_dtmf_var == nil) or (rtp_dtmf_var == "")) then rtp_dtmf_hide = "style=\"display: none;\"" else rtp_dtmf_hide = "style=\"display: table-row;\"" end string_table = string_table .. "" .. i18n("flow_details.dtmf_tones_sent") .. "" .. rtp_dtmf_var .. "\n" end -- FIRST REQUEST if isFlowValueDefined(info, "RTP_FIRST_SEQ") then local first_flow_sequence_var = getFlowValue(info, "RTP_FIRST_SEQ") local last_flow_sequence_var = getFlowValue(info, "RTP_FIRST_SEQ") if (((first_flow_sequence_var == nil) or (first_flow_sequence_var == "")) and ((last_flow_sequence_var == nil) or (last_flow_sequence_var == ""))) then first_last_flow_sequence_hide = "style=\"display: none;\"" else first_last_flow_sequence_hide = "style=\"display: table-row;\"" end string_table = string_table .. "" .. i18n("flow_details.first_last_flow_sequence") .. "
" .. first_flow_sequence_var .. "
" .. last_flow_sequence_var .. "
\n" end -- CALL-ID if isFlowValueDefined(info, "RTP_SIP_CALL_ID") then local sip_call_id_var = getFlowValue(info, "RTP_SIP_CALL_ID") if ((sip_call_id_var == nil) or (sip_call_id_var == "")) then sip_call_id_hide = "style=\"display: none;\"" else sip_call_id_hide = "style=\"display: table-row;\"" end string_table = string_table .. " " .. i18n("flow_details.sip_call_id") .. "  
" .. sip_call_id_var .. "
\n" end -- TWO-WAY CALL-QUALITY INDICATORS string_table = string_table .. "" .. i18n("flow_details.call_quality_indicators") .. "" .. i18n("flow_details.forward") .. "" .. i18n("flow_details.reverse") .. "" -- JITTER if isFlowValueDefined(info, "RTP_IN_JITTER") then local rtp_in_jitter = getFlowValue(info, "RTP_IN_JITTER") / 100 local rtp_out_jitter = getFlowValue(info, "RTP_OUT_JITTER") / 100 if (((rtp_in_jitter == nil) or (rtp_in_jitter == "")) and ((rtp_out_jitter == nil) or (rtp_out_jitter == ""))) then rtp_out_jitter_hide = "style=\"display: none;\"" else rtp_out_jitter_hide = "style=\"display: table-row;\"" end string_table = string_table .. "" .. i18n("flow_details.jitter") .. "" if ((rtp_in_jitter ~= nil) and (rtp_in_jitter ~= "")) then string_table = string_table .. rtp_in_jitter .. " ms " end string_table = string_table .. " " if ((rtp_out_jitter ~= nil) and (rtp_out_jitter ~= "")) then string_table = string_table .. rtp_out_jitter .. " ms " end string_table = string_table .. " \n" end -- PACKET LOSS if isFlowValueDefined(info, "RTP_IN_PKT_LOST") then local rtp_in_pkt_lost = getFlowValue(info, "RTP_IN_PKT_LOST") local rtp_out_pkt_lost = getFlowValue(info, "RTP_OUT_PKT_LOST") if (((rtp_in_pkt_lost == nil) or (rtp_in_pkt_lost == "")) and ((rtp_out_pkt_lost == nil) or (rtp_out_pkt_lost == ""))) then rtp_packet_loss_hide = "style=\"display: none;\"" else rtp_packet_loss_hide = "style=\"display: table-row;\"" end string_table = string_table .. "" .. i18n("flow_details.lost_packets") .. "" if ((rtp_in_pkt_lost ~= nil) and (rtp_in_pkt_lost ~= "")) then string_table = string_table .. formatPackets(rtp_in_pkt_lost) end string_table = string_table .. " " if ((rtp_out_pkt_lost ~= nil) and (rtp_out_pkt_lost ~= "")) then string_table = string_table .. formatPackets(rtp_out_pkt_lost) end string_table = string_table .. " \n" end -- PACKET DROPS if isFlowValueDefined(info, "RTP_IN_PKT_DROP") then local rtp_in_pkt_drop = getFlowValue(info, "RTP_IN_PKT_DROP") local rtp_out_pkt_drop = getFlowValue(info, "RTP_OUT_PKT_DROP") if (((rtp_in_pkt_drop == nil) or (rtp_in_pkt_drop == "")) and ((rtp_out_pkt_drop == nil) or (rtp_out_pkt_drop == ""))) then rtp_pkt_drop_hide = "style=\"display: none;\"" else rtp_pkt_drop_hide = "style=\"display: table-row;\"" end string_table = string_table .. "" .. i18n("flow_details.dropped_packets") .. "" if ((rtp_in_pkt_drop ~= nil) and (rtp_in_pkt_drop ~= "")) then string_table = string_table .. formatPackets(rtp_in_pkt_drop) end string_table = string_table .. " " if ((rtp_out_pkt_drop ~= nil) and (rtp_out_pkt_drop ~= "")) then string_table = string_table .. formatPackets(rtp_out_pkt_drop) end string_table = string_table .. " \n" end -- MAXIMUM DELTA BETWEEN CONSECUTIVE PACKETS if isFlowValueDefined(info, "RTP_IN_MAX_DELTA") then local rtp_in_max_delta = getFlowValue(info, "RTP_IN_MAX_DELTA") local rtp_out_max_delta = getFlowValue(info, "RTP_OUT_MAX_DELTA") if (((rtp_in_max_delta == nil) or (rtp_in_max_delta == "")) and ((rtp_out_max_delta == nil) or (rtp_out_max_delta == ""))) then rtp_max_delta_hide = "style=\"display: none;\"" else rtp_max_delta_hide = "style=\"display: table-row;\"" end string_table = string_table .. "" .. i18n("flow_details.max_packet_interarrival_time") .. "" if ((rtp_in_max_delta ~= nil) and (rtp_in_max_delta ~= "")) then string_table = string_table .. rtp_in_max_delta .. " ms " end string_table = string_table .. " " if ((rtp_out_max_delta ~= nil) and (rtp_out_max_delta ~= "")) then string_table = string_table .. rtp_out_max_delta .. " ms " end string_table = string_table .. " \n" end -- PAYLOAD TYPE if isFlowValueDefined(info, "RTP_IN_PAYLOAD_TYPE") then local rtp_payload_in_var = formatRtpPayloadType(getFlowValue(info, "RTP_IN_PAYLOAD_TYPE")) local rtp_payload_out_var = formatRtpPayloadType(getFlowValue(info, "RTP_OUT_PAYLOAD_TYPE")) if (((rtp_payload_in_var == nil) or (rtp_payload_in_var == "")) and ((rtp_payload_out_var == nil) or (rtp_payload_out_var == ""))) then rtp_payload_hide = "style=\"display: none;\"" else rtp_payload_hide = "style=\"display: table-row;\"" end string_table = string_table .. "" .. i18n("flow_details.payload_type") .. "
" .. rtp_payload_in_var .. "
" .. rtp_payload_out_var .. "
\n" end -- MOS if isFlowValueDefined(info, "RTP_IN_MOS") then local rtp_in_mos = getFlowValue(info, "RTP_IN_MOS") local rtp_out_mos = getFlowValue(info, "RTP_OUT_MOS") if (rtp_in_mos == nil or rtp_in_mos == "") and (rtp_out_mos == nil or rtp_out_mos == "") then quality_mos_hide = "style=\"display: none;\"" else quality_mos_hide = "style=\"display: table-row;\"" end string_table = string_table .. "" .. "" .. i18n("flow_details.pseudo_mos") .. "" .. "" if ((rtp_in_mos ~= nil) and (rtp_in_mos ~= "")) then string_table = string_table .. MosPercentageBar(rtp_in_mos) end string_table = string_table .. " " string_table = string_table .. "" if ((rtp_out_mos ~= nil) and (rtp_out_mos ~= "")) then string_table = string_table .. MosPercentageBar(rtp_out_mos) end string_table = string_table .. " " .. "" end -- R_FACTOR if isFlowValueDefined(info, "RTP_IN_R_FACTOR") then local rtp_in_r_factor = getFlowValue(info, "RTP_IN_R_FACTOR") / 100 local rtp_out_r_factor = getFlowValue(info, "RTP_OUT_R_FACTOR") / 100 if (rtp_in_r_factor == nil or rtp_in_r_factor == "" or rtp_in_r_factor == "0") and (rtp_out_r_factor == nil or rtp_out_r_factor == "" or rtp_out_r_factor == "0") then quality_r_factor_hide = "style=\"display: none;\"" else quality_r_factor_hide = "style=\"display: table-row;\"" end string_table = string_table .. "" .. i18n("flow_details.r_factor") .. "" if ((rtp_in_r_factor ~= nil) and (rtp_in_r_factor ~= "")) then string_table = string_table .. RFactorPercentageBar(rtp_in_r_factor) end string_table = string_table .. " " string_table = string_table .. "" if ((rtp_out_r_factor ~= nil) and (rtp_out_r_factor ~= "")) then string_table = string_table .. RFactorPercentageBar(rtp_out_r_factor) end string_table = string_table .. " " end end return string_table end -- ####################### function getFlowQuota(ifid, info, as_client) local pool_id, quota_source if as_client then pool_id = info["cli.pool_id"] quota_source = info["cli.quota_source"] else pool_id = info["srv.pool_id"] quota_source = info["srv.quota_source"] end local master_proto, app_proto = splitProtocol(info["proto.ndpi"]) app_proto = app_proto or master_proto local pools_stats = interface.getHostPoolsStats() local pool_stats = pools_stats and pools_stats[tonumber(pool_id)] local quota_and_protos = shaper_utils.getPoolProtoShapers(ifid, pool_id) if pool_stats ~= nil then local key = nil if quota_source == "policy_source_protocol" then proto_stats = pool_stats.ndpi -- determine if the quota is on the app or master proto if (quota_and_protos[master_proto] ~= nil) then key = master_proto else key = app_proto end elseif quota_source == "policy_source_category" then key = flow["proto.ndpi_cat"] proto_stats = nil category_stats = pool_stats.ndpi_categories elseif quota_source == "policy_source_pool" then key = "Default" proto_stats = nil category_stats = { default = pool_stats.cross_application } end if key ~= nil then local proto_info = nil if key ~= "Default" then proto_info = quota_and_protos[key] else proto_info = shaper_utils.getCrossApplicationShaper(ifid, pool_id) end if proto_info ~= nil then return proto_info, proto_stats, category_stats end end end return nil end -- ####################### function printFlowQuota(ifid, info, as_client) local flow_quota, proto_stats, category_stats = getFlowQuota(ifid, info, as_client) if flow_quota ~= nil then print("") print(string.gsub(graph_utils.printProtocolQuota(flow_quota, proto_stats, category_stats, { traffic = true, time = true }, true), "\n", "")) print("
") else print(i18n("shaping.no_quota_applied")) end end -- ####################### function printFlowSNMPInfo(snmpdevice, input_idx, output_idx) local inputidx_name = format_portidx_name(snmpdevice, tostring(input_idx)) local outputidx_name = format_portidx_name(snmpdevice, tostring(output_idx)) print( "" .. i18n("details.flow_snmp_localization") .. "" .. i18n("flows_page.inIfIdx") .. "" .. (inputidx_name or "") .. "") print("" .. i18n("flows_page.outIfIdx") .. "" .. (outputidx_name or "") .. "") end -- ####################### function printBlockFlowJs() print [[ var block_flow_csrf = "]] print(ntop.getRandomCSRFValue()) print [["; function block_flow(flow_key, flow_hash_id) { var url = "]] print(ntop.getHttpPrefix()) print [[/lua/pro/nedge/block_flow.lua"; $.ajax({ type: 'GET', url: url, cache: false, data: { csrf: block_flow_csrf, flow_key: flow_key, flow_hash_id: flow_hash_id, }, success: function(content) { var data = jQuery.parseJSON(content); var row_id = flow_key + "_" + flow_hash_id; if (data.status == "BLOCKED") { $('#'+row_id+'_block') .removeClass('bg-secondary') .addClass('bg-danger') .attr('title', ']] print(i18n("flow_details.flow_traffic_is_dropped")) print [['); } }, error: function(content) { console.log("error"); } }); } ]] end -- ####################### function printL4ProtoDropdown(base_url, page_params, l4_proto) local l4proto = _GET["l4proto"] local l4proto_filter if not isEmptyString(l4proto) then l4proto_filter = '' else l4proto_filter = '' end -- table.clone needed to modify some parameters while keeping the original unchanged local l4proto_params = table.clone(page_params) l4proto_params["l4proto"] = nil -- Used to possibly remove tcp state filters when selecting a non-TCP l4 protocol local l4proto_params_non_tcp = table.clone(l4proto_params) if l4proto_params_non_tcp["tcp_flow_state"] then l4proto_params_non_tcp["tcp_flow_state"] = nil end print [[\ \ ]] end -- ####################### local function printFlowDevicesFilterDropdown(base_url, page_params) local snmp_cached_dev = require "snmp_cached_dev" local flowdevs = interface.getFlowDevices() local observationPointId = ntop.getUserObservationPointId() or 0 --[[ if observationPointId ~= 0 then local obs_info = interface.getObsPointsInfo()["ObsPoints"] local exporter_list = {} tprint(obs_info) for k, v in ipairs(obs_info) do if (v.obs_point == observationPointId) then exporter_list = v.exporter_list break end end flowdevs = exporter_list end ]] local devips = getProbesName(flowdevs, false, false) local ordering_fun = pairsByKeys local devips_order = ntop.getPref("ntopng.prefs.flow_table_probe_order") == "1" -- Order by Probe Name if devips_order then ordering_fun = pairsByValues end local cur_dev = _GET["deviceIP"] local cur_dev_filter = '' local snmp_community = '' if not isEmptyString(cur_dev) then cur_dev_filter = '' end -- table.clone needed to modify some parameters while keeping the original unchanged local dev_params = table.clone(page_params) for _, p in pairs({"deviceIP", "outIfIdx", "inIfIdx"}) do dev_params[p] = nil end print [[, '
\ \ \
']] if cur_dev ~= nil then -- also print dropddowns for input and output interface index local ports_table = interface.getFlowDeviceInfo(cur_dev) for _, direction in pairs({"outIfIdx", "inIfIdx"}) do local cur_if = _GET[direction] local cur_if_filter = '' if not isEmptyString(cur_if) then cur_if_filter = '' end -- table.clone needed to modify some parameters while keeping the original unchanged local if_params = table.clone(page_params) if_params[direction] = nil print [[, '
\ \ \
']] end end end -- ####################### local function printDropdownEntries(entries, base_url, param_arr, param_filter, curr_filter) for _, htype in ipairs(entries) do if type(htype) == "string" then -- plain html print(htype) goto continue end param_arr[param_filter] = htype[1] print [[]] print(htype[2]) print [[]] ::continue:: end end local function getParamFilter(page_params, param_name) if page_params[param_name] then return '' end return '' end function printTabList(base_url, page_params, active) if (ntop.isEnterpriseM() or (ntop.isnEdge() and ntop.isnEdgeEnterprise())) then print [[
]] end end function printFlowPagesDropdown(base_url, page_params) local flowhosts_type_params = table.clone(page_params) if (ntop.isEnterpriseM()) then print [[
]] else print [[
]] end end function printActiveFlowsDropdown(base_url, page_params, ifstats, flowstats, is_ebpf_flows) -- Local / Remote hosts selector -- table.clone needed to modify some parameters while keeping the original unchanged local flowhosts_type_params = table.clone(page_params) flowhosts_type_params["flowhosts_type"] = nil print [['\
\ \ \
\ ']] local talking_with_params = table.clone(page_params) talking_with_params["talking_with"] = nil if talking_with_params["host"] then local talking_with_list = {} for host, num_flows in pairs(flowstats["talking_with"] or {}) do if talking_with_params["host"] ~= host then local hinfo = hostkey2hostinfo(host) talking_with_list[#talking_with_list + 1] = {host, hostinfo2label(hinfo) .. " (" .. format_utils.formatValue(num_flows) .. ")"} end end print [[, '\
\ \ \
\ ']] end if (not (talking_with_params["server"] and talking_with_params["client"])) then if talking_with_params["client"] then local talking_with_list = {} for host, num_flows in pairs(flowstats["talking_with"] or {}) do if talking_with_params["client"] ~= host then local hinfo = hostkey2hostinfo(host) talking_with_list[#talking_with_list + 1] = {host, hostinfo2label(hinfo) .. " (" .. format_utils.formatValue(num_flows) .. ")"} end end print [[, '\
\ \ \
\ ']] end if talking_with_params["server"] then local talking_with_list = {} for host, num_flows in pairs(flowstats["talking_with"] or {}) do if talking_with_params["server"] ~= host then local hinfo = hostkey2hostinfo(host) talking_with_list[#talking_with_list + 1] = {host, hostinfo2label(hinfo) .. " (" .. format_utils.formatValue(num_flows) .. ")"} end end print [[, '\
\ \ \
\ ']] end end -- Status selector -- table.clone needed to modify some parameters while keeping the original unchanged local alert_type_params = table.clone(page_params) alert_type_params["alert_type"] = nil print [[, '\
\ \ \
\ ']] -- Flow Status Severity local alert_type_severity_params = table.clone(page_params) alert_type_severity_params["alert_type_severity"] = nil print [[, '\
\ \ \
\ ']] if not is_ebpf_flows then if page_params["l4proto"] and page_params["l4proto"] == "6" then -- TCP flow state filter -- table.clone needed to modify some parameters while keeping the original unchanged local tcp_state_params = table.clone(page_params) tcp_state_params["tcp_flow_state"] = nil print [[, '\
\ \ \
\ ']] end -- Unidirectional flows selector -- table.clone needed to modify some parameters while keeping the original unchanged local traffic_type_params = table.clone(page_params) traffic_type_params["traffic_type"] = nil print [[, '\
\ \ \
\ ']] else -- is_ebpf_flows if not page_params.container then -- POD filter local pods = interface.getPodsStats() -- table.clone needed to modify some parameters while keeping the original unchanged local pods_params = table.clone(page_params) pods_params["pod"] = nil if not table.empty(pods) then print [[, '\
\ \ \
\ ']] end end if not page_params.pod then -- Container filter local containers = interface.getContainersStats() -- table.clone needed to modify some parameters while keeping the original unchanged local container_params = table.clone(page_params) container_params["container"] = nil if not table.empty(containers) then print [[, '\
\ \ \
\ ']] end end end -- L7 Application print(', \'
'") -- L7 Application Category print(', \'
'") -- DSCP selector -- table.clone needed to modify some parameters while keeping the original unchanged local dscp_params = table.clone(page_params) dscp_params["dscp"] = nil print [[, '
]] printDSCPDropdown(base_url, dscp_params, flowstats["dscps"] or {}, format_utils) print [[
']] -- Host Pool selector -- table.clone needed to modify some parameters while keeping the original unchanged local host_pool_params = table.clone(page_params) host_pool_params["host_pool"] = nil print [[, '
]] printHostPoolDropdown(base_url, host_pool_params, flowstats["host_pool_id"] or {}, format_utils) print [[
']] -- Host Pool selector -- table.clone needed to modify some parameters while keeping the original unchanged local local_network_params = table.clone(page_params) local_network_params["network"] = nil print [[, '
]] printLocalNetworksDropdown(base_url, local_network_params) print [[
']] -- IP version selector -- table.clone needed to modify some parameters while keeping the original unchanged local ipversion_params = table.clone(page_params) ipversion_params["version"] = nil print [[, '
]] printIpVersionDropdown(base_url, ipversion_params) print [[
']] -- L4 protocol selector -- table.clone needed to modify some parameters while keeping the original unchanged local l4proto_params = table.clone(page_params) l4proto_params["l4proto"] = nil print [[, '
]] printL4ProtoDropdown(base_url, l4proto_params, flowstats["l4_protocols"]) print [[
']] -- VLAN selector -- table.clone needed to modify some parameters while keeping the original unchanged local vlan_params = table.clone(page_params) if ifstats.vlan then print [[, '
]] printVLANFilterDropdown(base_url, vlan_params) print [[
']] end if ntop.isPro() then local hashname = "ntopng.prefs.profiles" local profiles = ntop.getHashKeysCache(hashname) or {} local profiles_defined = false for k, _ in pairsByKeys(profiles) do profiles_defined = true break end if profiles_defined then -- Traffic Profiles print( ', \'
'") end end if ntop.isPro() and interface.isPacketInterface() == false then printFlowDevicesFilterDropdown(base_url, vlan_params) end end -- ####################### function getFlowsTableTitle(base_url) local active_msg = "" local status_type if _GET["alert_type"] then local alert_type_id = tonumber(_GET["alert_type"]) if (alert_type_id ~= nil) then status_type = alert_consts.alertTypeLabel(tonumber(_GET["alert_type"]), true) else status_type = firstToUpper(_GET["alert_type"]) end end if _GET["alert_type_severity"] then local alert_type_severity = _GET["alert_type_severity"] local s = alert_consts.severity_groups[alert_type_severity] active_msg = active_msg .. " " .. i18n(s.i18n_title) end if _GET["application"] then local application = _GET["application"] local application_split = string.split(application, "%.") if application_split and #application_split == 2 then application = string.format("%s.%s", interface.getnDPIProtoName(tonumber(application_split[1])), interface.getnDPIProtoName(tonumber(application_split[2]))) else local _application = tonumber(application) if (_application) then application = interface.getnDPIProtoName(_application) end end active_msg = active_msg .. " " .. application end if _GET["category"] then active_msg = active_msg .. " " .. _GET["category"] end if _GET["vhost"] then active_msg = active_msg .. " " .. _GET["vhost"] end if status_type then active_msg = active_msg .. " " .. status_type end if (_GET["network_name"] ~= nil) then active_msg = active_msg .. i18n("network", { network = _GET["network_name"] }) end if (_GET["host"] ~= nil) then local host_info = interface.getHostInfo(_GET["host"]) local host_name = "" if (host_info) then host_name = host_info.names.resolved end if isEmptyString(base_url) then base_url = ntop.getHttpPrefix() end active_msg = active_msg .. i18n("flows_page.host", { host = _GET["host"], host_name = ternary(isEmptyString(host_name), _GET["host"], host_name), base_url = base_url }) end if (_GET["client"] ~= nil) then local client_info = interface.getHostInfo(_GET["client"]) local client_name = "" if (client_info) then client_name = client_info.names.resolved end if (_GET["server"] ~= nil) then local server_info = interface.getHostInfo(_GET["server"]) local server_name = "" if (server_info) then server_name = server_info.names.resolved end active_msg = active_msg .. i18n("flows_page.client_to_server", { client = _GET["client"], client_name = ternary(isEmptyString(client_name), _GET["client"], client_name), server = _GET["server"], server_name = ternary(isEmptyString(server_name), _GET["server"], server_name), base_url = base_url }) else active_msg = active_msg .. i18n("flows_page.client", { client = _GET["client"], client_name = ternary(isEmptyString(client_name), _GET["client"], client_name), base_url = base_url }) end else if (_GET["server"] ~= nil) then local server_info = interface.getHostInfo(_GET["server"]) local server_name = "" if (server_info) then server_name = server_info.names.resolved end active_msg = active_msg .. i18n("flows_page.server", { server = _GET["server"], base_url = base_url, server_name = ternary(isEmptyString(server_name), _GET["server"], server_name) }) end end if (_GET["flow_info"] ~= nil) then active_msg = active_msg .. i18n("flows_page.flow_info", { flow_info = _GET["flow_info"] }) end if (_GET["port"] ~= nil) then active_msg = active_msg .. i18n("flows_page.port", { port = _GET["port"], base_url = base_url }) end if (_GET["inIfIdx"] ~= nil) then active_msg = active_msg .. " [" .. i18n("flows_page.inIfIdx") .. " " .. _GET["inIfIdx"] .. "]" end if (_GET["outIfIdx"] ~= nil) then active_msg = active_msg .. " [" .. i18n("flows_page.outIfIdx") .. " " .. _GET["outIfIdx"] .. "]" end if (_GET["deviceIP"] ~= nil) then active_msg = active_msg .. " [" .. i18n("flows_page.device_ip") .. " " .. _GET["deviceIP"] .. "]" end if (_GET["container"] ~= nil) then active_msg = active_msg .. " [" .. i18n("containers_stats.container") .. " " .. format_utils.formatContainerFromId(_GET["container"]) .. "]" end if (_GET["pod"] ~= nil) then active_msg = active_msg .. " [" .. i18n("containers_stats.pod") .. " " .. shortenString(_GET["pod"]) .. "]" end if ((_GET["icmp_type"] ~= nil) and (_GET["icmp_cod"] ~= nil)) then local is_v4 = true if (_GET["version"] ~= nil) then is_v4 = (_GET["version"] == "4") end local icmp_utils = require "icmp_utils" local icmp_label = icmp_utils.get_icmp_label(ternary(is_v4, 4, 6), _GET["icmp_type"], _GET["icmp_cod"]) active_msg = active_msg .. " [" .. icmp_label .. "]" end if (_GET["tcp_flow_state"] ~= nil) then active_msg = active_msg .. " [" .. tcp_flow_state_utils.state2i18n(_GET["tcp_flow_state"]) .. "]" end if not interface.isPacketInterface() then active_msg = i18n("flows_page.recently_active_flows", { filter = active_msg }) elseif interface.isPcapDumpInterface() then active_msg = i18n("flows_page.flows", { filter = active_msg }) else active_msg = i18n("flows_page.active_flows", { filter = active_msg }) end return active_msg end -- ####################### -- A one line flow description -- This uses the information from flow.getInfo() function shortFlowLabel(flow) local info = "" if not isEmptyString(flow["info"]) then info = " [" .. flow["info"] .. "]" end return (string.format("[%s] %s %s:%d -> %s:%s%s", flow["proto.ndpi"], flow["proto.l4"], flow["cli.ip"], flow["cli.port"], flow["srv.ip"], flow["srv.port"], info)) end -- #######################