--
-- (C) 2013-18 - ntop.org
--
dirs = ntop.getDirs()
package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path
local shaper_utils
require "lua_utils"
local have_nedge = ntop.isnEdge()
local NfConfig = nil
if ntop.isPro() then
package.path = dirs.installdir .. "/scripts/lua/pro/modules/?.lua;" .. package.path
shaper_utils = require("shaper_utils")
if ntop.isnEdge() then
package.path = dirs.installdir .. "/scripts/lua/pro/nedge/modules/?.lua;" .. package.path
NfConfig = require("nf_config")
end
end
require "historical_utils"
require "flow_utils"
require "voip_utils"
local template = require "template_utils"
local categories_utils = require "categories_utils"
local discover = require("discover_utils")
local json = require ("dkjson")
local page_utils = require("page_utils")
sendHTTPContentTypeHeader('text/html')
page_utils.print_header(i18n("flow_details.flow_details"))
warn_shown = 0
local alert_banners = {}
if isAdministrator() then
if _POST["custom_hosts"] and _POST["category"] then
local lists_utils = require("lists_utils")
local category_id = tonumber(split(_POST["category"], "cat_")[2])
if categories_utils.addCustomCategoryHost(category_id, _POST["custom_hosts"]) then
lists_utils.reloadLists()
alert_banners[#alert_banners + 1] = {
type="success",
text=i18n("flow_details.host_successfully_added_to_category",
{host=_POST["custom_hosts"], category=interface.getnDPICategoryName(category_id),
url = ntop.getHttpPrefix() .. "/lua/admin/edit_categories.lua?l7proto=" .. category_id})
}
else
alert_banners[#alert_banners + 1] = {
type="danger",
text=i18n("flow_details.could_not_add_host_to_category",
{host=_POST["custom_hosts"], category=interface.getnDPICategoryName(category_id)})
}
end
end
end
local function printAddHostoToCustomizedCategories(full_url)
if not isAdministrator() then
return
end
local categories = interface.getnDPICategories()
local short_url = categories_utils.getSuggestedHostName(full_url)
-- Fill the dropdown
local cat_select_dropdown = '"
-- Put a note if the URL is already assigned to another customized category
local existing_note = ""
local matched_category = ntop.matchCustomCategory(full_url)
if matched_category ~= nil then
existing_note = "
" .. i18n("details.note") .. ": " ..
i18n("custom_categories.similar_host_found", {host=full_url, category=interface.getnDPICategoryName(matched_category)})
end
print(
template.gen("modal_confirm_dialog.html", {
dialog={
id = "add_to_customized_categories",
action = "addToCustomizedCategories()",
custom_alert_class = "",
custom_dialog_class = "dialog-body-full-height",
title = i18n("custom_categories.custom_host_category"),
message = i18n("custom_categories.select_url_category") .. "
" ..
cat_select_dropdown .. "
" .. i18n("custom_categories.the_following_url_will_be_added") ..
'
' .. existing_note,
confirm = i18n("custom_categories.add"),
}
})
)
print(' ')
print[[]]
end
function displayProc(proc, label)
if(proc.pid == 0) then return end
print(label)
print("
| ") if(ifstats.sprobe) then print(i18n("details.source_id")) else print(i18n("details.vlan_id")) end print(" | " .. flow["vlan"].. " | |||
|---|---|---|---|---|
| "..i18n("flow_details.flow_peers_client_server").." | "..getFlowLabel(flow, true, true).." | |||
| "..i18n("db_explorer.l4_proto").." / "..i18n("application").." | ") if((ifstats.inline and flow["verdict.pass"]) or (flow.vrfId ~= nil)) then print("") else print(" | ")
end
if(flow["verdict.pass"] == false) then print(" | ')
if(flow.vrfId ~= nil) then
print("VRF Id "..flow.vrfId.." | ") end print("|
| "..i18n("flow_details.flow_shapers").." | ") c = flowinfo2hostname(flow,"cli") s = flowinfo2hostname(flow,"srv") if flow["cli.pool_id"] ~= nil then c = c .. " (".. host_pools_utils.poolIdToUsername(flow["cli.pool_id"]) ..")" end if flow["srv.pool_id"] ~= nil then s = s .. " (".. host_pools_utils.poolIdToUsername(flow["srv.pool_id"]) ..")" end local shaper = shaper_utils.nedge_shaper_id_to_shaper(flow["shaper.cli2srv_egress"]) print(""..c.." | ".. shaper.icon .. " " .. shaper.text .." | "..s.." | ".. shaper.icon .. " " .. shaper.text.." | ") print("") if flow["cli.pool_id"] ~= nil and flow["srv.pool_id"] ~= nil then print("
| "..i18n("flow_details.flow_quota").." | ") print(""..c.." | ") print("") printFlowQuota(ifstats.id, flow, true --[[ client ]]) print(" | "..s.." | ") print("") printFlowQuota(ifstats.id, flow, false --[[ server ]]) print(" | ") print("") end -- ENABLE MARKER DEBUG if ntop.isnEdge() and false then print("
| "..i18n("flow_details.flow_marker").." | ") print("".. NfConfig.formatMarker(flow["marker"]) .." | ") print("|||
| "..i18n("device_protocols.device_protocol_policy").." | ") local proto = status_info["devproto_forbidden_id"] or flow["proto.ndpi_id"] if cli_show then print(""..i18n("device_protocols.devtype_as_proto_client", {devtype=discover.devtype2string(status_info["cli.devtype"]), proto=interface.getnDPIProtoName(proto)}).." | ") print("") print(i18n(ternary(status_info["devproto_forbidden_peer"] ~= "cli", "allowed", "forbidden"))) print(" | ||
| "..i18n("device_protocols.devtype_as_proto_server", {devtype=discover.devtype2string(status_info["srv.devtype"]), proto=interface.getnDPIProtoName(proto)}).." | ") print("") print(i18n(ternary(status_info["devproto_forbidden_peer"] ~= "srv", "allowed", "forbidden"))) print(" | |||
| "..i18n("details.first_last_seen").." | " .. formatEpoch(flow["seen.first"]) .. " [" .. secondsToTime(os.time()-flow["seen.first"]) .. " "..i18n("details.ago").."]" .. " | \n")
print("" .. formatEpoch(flow["seen.last"]) .. " [" .. secondsToTime(os.time()-flow["seen.last"]) .. " "..i18n("details.ago").."]" .. " | ||
| "..i18n("details.total_traffic").." | "..i18n("total")..": " .. bytesToSize(flow["bytes"]) .. " | ") if((ifstats.type ~= "zmq") and ((flow["proto.l4"] == "TCP") or (flow["proto.l4"] == "UDP")) and (flow["goodput_bytes"] > 0)) then print(""..i18n("details.goodput")..": " .. bytesToSize(flow["goodput_bytes"]) .. " (") pctg = round(((flow["goodput_bytes"]*100)/flow["bytes"]), 2) if(pctg < 50) then pctg = ""..pctg.."" elseif(pctg < 60) then pctg = ""..pctg.."" end print(pctg.."") print(" %) | \n") end print(" | |
| " .. i18n("client") .. " " .. i18n("server") .. ": " .. formatPackets(flow["cli2srv.packets"]) .. " / ".. bytesToSize(flow["cli2srv.bytes"]) .. " | " .. i18n("client") .. " " .. i18n("server") .. ": " .. formatPackets(flow["srv2cli.packets"]) .. " / ".. bytesToSize(flow["srv2cli.bytes"]) .. " | |||
| ")
cli2srv = round((flow["cli2srv.bytes"] * 100) / flow["bytes"], 0)
cli_name = shortHostName(getResolvedAddress(hostkey2hostinfo(flow["cli.ip"])))
srv_name = shortHostName(getResolvedAddress(hostkey2hostinfo(flow["srv.ip"])))
if(flow["cli.port"] > 0) then
cli_name = cli_name .. ":" .. flow["cli.port"]
srv_name = srv_name .. ":" .. flow["srv.port"]
end
print(' ')
print(" | ||||
| "..i18n("flow_details.rtt_breakdown").." | ")
print(' ')
print(' ')
print(" | |||
| "..i18n("flow_details.rtt_distance").." | ") local c_vacuum_km_s = 299792 local c_vacuum_mi_s = 186000 local fiber_vf = .67 local delta_t = rtt/1000 local dd_fiber_km = delta_t * c_vacuum_km_s * fiber_vf local dd_fiber_mi = delta_t * c_vacuum_mi_s * fiber_vf print(formatValue(toint(dd_fiber_km)).." Km | "..formatValue(toint(dd_fiber_mi)).." Miles") print(" | ||
| "..i18n("flow_details.application_latency").." | "..msToTime(flow["tcp.appl_latency"]).." | |||
| "..i18n("flow_details.packet_inter_arrival_time").." | "..i18n("client").." "..i18n("server")..": ") print(msToTime(flow["interarrival.cli2srv"]["min"]).." / "..msToTime(flow["interarrival.cli2srv"]["avg"]).." / "..msToTime(flow["interarrival.cli2srv"]["max"])) print(" | \n") if(flow["srv2cli.packets"] < 2) then print("") else print(" | "..i18n("client").." "..i18n("server")..": ") print(msToTime(flow["interarrival.srv2cli"]["min"]).." / "..msToTime(flow["interarrival.srv2cli"]["avg"]).." / "..msToTime(flow["interarrival.srv2cli"]["max"])) end print(" | |
| "..i18n("flow_details.looks_like_idle_flow_message").." | ||||
| "..i18n("flow_details.tcp_packet_analysis").." | ||||
| "..i18n("client").." "..i18n("server").." / "..i18n("client").." "..i18n("server").." | ||||
| "..i18n("details.retransmissions").." | ".. formatPackets(flow["cli2srv.retransmissions"]) .." / ".. formatPackets(flow["srv2cli.retransmissions"]) .." | |||
| "..i18n("details.out_of_order").." | ".. formatPackets(flow["cli2srv.out_of_order"]) .." / ".. formatPackets(flow["srv2cli.out_of_order"]) .." | |||
| "..i18n("details.lost").." | ".. formatPackets(flow["cli2srv.lost"]) .." / ".. formatPackets(flow["srv2cli.lost"]) .." | |||
| "..i18n("details.keep_alive").." | ".. formatPackets(flow["cli2srv.keep_alive"]) .." / ".. formatPackets(flow["srv2cli.keep_alive"]) .." | |||
| "..i18n("flow_details.ssl_certificate").." | ") print(i18n("flow_details.client_requested")..": "..flow["protos.ssl.certificate"].." ") if(flow["category"] ~= nil) then print(" "..getCategoryIcon(flow["protos.ssl.certificate"], flow["category"])) end historicalProtoHostHref(ifid, nil, nil, nil, flow["protos.ssl.certificate"]) printAddHostoToCustomizedCategories(flow["protos.ssl.certificate"]) print(" | ") if(flow["protos.ssl.server_certificate"] ~= nil) then print(""..i18n("flow_details.server_certificate")..": "..flow["protos.ssl.server_certificate"].."")
if(flow["flow.status"] == 10) then
print("\n "..i18n("flow_details.certificates_not_match").."") end print(" | ")
end
print("||
| ".. ''.. i18n("flow_details.max_estimated_tcp_throughput").." | "..i18n("client").." "..i18n("server")..": ") print(bitsToSize(flow["tcp.max_thpt.cli2srv"])) print(" | "..i18n("client").." "..i18n("server")..": ") print(bitsToSize(flow["tcp.max_thpt.srv2cli"])) print(" | ||
| "..i18n("flow_details.throughput_trend").." | "..flow["cli.ip"].." "..flow["srv.ip"]..": ") print(flow["cli2srv.trend"]) print(" | "..flow["cli.ip"].." "..flow["srv.ip"]..": ") print(flow["srv2cli.trend"]) print(" | ||
| "..i18n("tcp_flags").." | "..i18n("client").." "..i18n("server")..": ") printTCPFlags(flow["cli2srv.tcp_flags"]) print(" | "..i18n("client").." "..i18n("server")..": ") printTCPFlags(flow["srv2cli.tcp_flags"]) print(" | ||
| ") flow_completed = false flow_reset = false flows_syn_seen = false resetter = "" if(hasbit(flags,0x01)) then flow_completed = true end if(hasbit(flags,0x02)) then flows_syn_seen = true end if(hasbit(flags,0x04)) then flow_completed = true flow_reset = true if(hasbit(flow["cli2srv.tcp_flags"],0x04)) then resetter = "client" else resetter = "server" end end local flow_msg="" if flow_reset == true then flow_msg = " " if resetter ~= nil and resetter ~= "" then flow_msg = flow_msg..i18n("flow_details.flow_reset_by_resetter_msg",{resetter=resetter}) else flow_msg = flow_msg..i18n("flow_details.flow_reset_msg") end flow_msg = flow_msg.."." elseif flow_completed == true then flow_msg = flow_msg.." "..i18n("flow_details.flow_completed_msg").."." else flow_msg = flow_msg.." "..i18n("flow_details.flow_active_msg").."." if flows_syn_seen == false then flow_msg = flow_msg.." "..i18n("flow_details.flow_peer_roles_inaccurate_msg").."" end end print(flow_msg) print(" | ||||
| "..i18n("flow_details.icmp_info").." | ".. getICMPTypeCode(icmp) .. " | |||
| "..i18n("flow_details.flow_status").." | "..getFlowStatus(flow["flow.status"], flow2statusinfo(flow)).." | |||
| "..i18n("flow_details.actual_peak_throughput").." | ") if (throughput_type == "bps") then print("" .. bitsToSize(8*flow["throughput_bps"]) .. " ") elseif (throughput_type == "pps") then print("" .. pktsToSize(flow["throughput_bps"]) .. " ") end if (throughput_type == "bps") then print(" / " .. bitsToSize(8*flow["top_throughput_bps"]) .. " ") elseif (throughput_type == "pps") then print(" / " .. pktsToSize(flow["top_throughput_bps"]) .. " ") end print(" | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0") print(" | ||
| ') width = 1024 height = 200 url = ntop.getHttpPrefix().."/lua/get_flow_process_tree.lua?flow_key="..flow_key dofile(dirs.installdir .. "/scripts/lua/inc/sprobe.lua") print(' | ||||
| "..i18n("flow_details.client_process_information").." | ||||
| "..i18n("flow_details.server_process_information").." | ||||
| "..i18n("flow_details.dns_query").." | ") if(string.ends(flow["protos.dns.last_query"], "arpa")) then print(flow["protos.dns.last_query"]) else print(""..flow["protos.dns.last_query"].." ") end if(flow["category"] ~= nil) then print(" "..getCategoryIcon(flow["protos.dns.last_query"], flow["category"])) end printAddHostoToCustomizedCategories(flow["protos.dns.last_query"]) print(" | |||
| "..i18n("flow_details.bittorrent_hash").." | ".. flow["bittorrent_hash"].." | |||
| "..i18n("flow_details.ssh_signature").." | "..i18n("client")..": "..(flow["protos.ssh.client_signature"] or '').." | "..i18n("server")..": "..(flow["protos.ssh.server_signature"] or '').." | ||
| "..i18n("http").." | ") print(""..i18n("flow_details.http_method").." | "..(flow["protos.http.last_method"] or '').." | ") print("||
| "..i18n("flow_details.server_name").." | ") local s = flowinfo2hostname(flow,"srv") if(not isEmptyString(flow["host_server_name"])) then s = flow["host_server_name"] end print(""..s.." ") if(flow["category"] ~= nil) then print(" "..getCategoryIcon(flow["host_server_name"], flow["category"])) end printAddHostoToCustomizedCategories(s) print(" | |||
| "..i18n("flow_details.url").." | ") print(""..shortenString(flow["protos.http.last_url"] or '', 64).." ") print(" | |||
| "..i18n("flow_details.response_code").." | "..(flow["protos.http.last_return_code"] or '').." | |||
| "..i18n("flow_details.server_name").." | "..flow["host_server_name"].." ") if not isEmptyString(flow["protos.http.server_name"]) then printAddHostoToCustomizedCategories(flow["protos.http.server_name"]) end print(" | |||
| "..i18n("flow_details.profile_name").." | "..flow["profile"].." | |||
| "..i18n("flow_details.additional_flow_elements").." | ||||
| " .. getFlowKey(key) .. " | " .. handleCustomFlowField(key, value, snmpdevice) .. " | |||