-- -- (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(""..i18n("flow_details.user_name").."".. proc.user_name .."\n") print(""..i18n("flow_details.process_pid_name").."".. proc.pid .. "/" .. proc.name .. "") print(" ["..i18n("flow_details.son_of_father_process",{url=ntop.getHttpPrefix().."/lua/get_process_info.lua?pid="..proc.father_pid,proc_father_pid=proc.father_pid,proc_father_name=proc.father_name}).."]\n") if(false) then if(proc.actual_memory > 0) then print(""..i18n("flow_details.average_cpu_load").."") cpu_load = round(proc.average_cpu_load, 2).."" if(proc.average_cpu_load < 33) then if(proc.average_cpu_load == 0) then proc.average_cpu_load = "< 1" end print(""..cpu_load.." %") elseif(proc.average_cpu_load < 66) then print(""..cpu_load.." %") else print(""..cpu_load.." %") end print(" \n") print(""..i18n("flow_details.io_wait_time_percentage").."") cpu_load = round(proc.percentage_iowait_time, 2).."" if(proc.percentage_iowait_time < 33) then if(proc.percentage_iowait_time == 0) then proc.percentage_iowait_time = "< 1" end print(""..cpu_load.." %") elseif(proc.percentage_iowait_time < 66) then print(""..cpu_load.." %") else print(""..cpu_load.." %") end print(" \n") print(""..i18n("flow_details.memory_actual_peak").."".. bytesToSize(proc.actual_memory) .. " / ".. bytesToSize(proc.peak_memory) .. " [" .. round((proc.actual_memory*100)/proc.peak_memory, 1) .."%]\n") print(""..i18n("flow_details.vm_page_faults").."") if(proc.num_vm_page_faults > 0) then print(""..proc.num_vm_page_faults.."") else print(""..proc.num_vm_page_faults.."") end print("\n") end -- fix end if(proc.actual_memory == 0) then if(warn_shown == 0) then warn_shown = 1 print(' '..i18n("flow_details.process_information_report_warning",{url="http://www.ntop.org/products/nprobe/"})..'\n') end end end active_page = "flows" dofile(dirs.installdir .. "/scripts/lua/inc/menu.lua") printMessageBanners(alert_banners) if not table.empty(alert_banners) then print("
") end throughput_type = getThroughputType() flow_key = _GET["flow_key"] interface.select(ifname) if(flow_key == nil) then flow = nil else flow = interface.findFlowByKey(tonumber(flow_key)) end local ifid = interface.name2id(ifname) local label = getFlowLabel(flow) print [[
]] if(flow == nil) then print('
'..i18n("flow_details.flow_cannot_be_found_message")..' '.. purgedErrorString()..'
') else if isAdministrator() then if(_POST["drop_flow_policy"] == "true") then interface.dropFlowTraffic(tonumber(flow_key)) flow["verdict.pass"] = false end end ifstats = interface.getStats() print("\n") if ifstats.vlan and flow["vlan"] > 0 then print("\n") end print("\n") print("") if((ifstats.inline and flow["verdict.pass"]) or (flow.vrfId ~= nil)) then print("') if(flow.vrfId ~= nil) then print("") end print("\n") if(ntop.isPro() and ifstats.inline and (flow["shaper.cli2srv_ingress"] ~= nil)) then local host_pools_utils = require("host_pools_utils") print("") 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("") local shaper = shaper_utils.nedge_shaper_id_to_shaper(flow["shaper.cli2srv_ingress"]) print("") print("") if flow["cli.pool_id"] ~= nil and flow["srv.pool_id"] ~= nil then print("") print("") print("") print("") print("") print("") end -- ENABLE MARKER DEBUG if ntop.isnEdge() and false then print("") print("") print("") end local status_info = flow2statusinfo(flow) if status_info then local cli_mac = flow["cli.mac"] and interface.getMacInfo(flow["cli.mac"]) local srv_mac = flow["srv.mac"] and interface.getMacInfo(flow["srv.mac"]) local cli_show = (cli_mac and cli_mac.location == "lan" and flow["cli.pool_id"] == 0) local srv_show = (srv_mac and srv_mac.location == "lan" and flow["srv.pool_id"] == 0) local num_rows = 0 if cli_show then num_rows = num_rows + 1 end if srv_show then num_rows = num_rows + 1 end if num_rows > 0 then print("") local proto = status_info["devproto_forbidden_id"] or flow["proto.ndpi_id"] if cli_show then print("") print("") end if srv_show then print("") print("") end end end end print("\n") print("\n") print("") if((ifstats.type ~= "zmq") and ((flow["proto.l4"] == "TCP") or (flow["proto.l4"] == "UDP")) and (flow["goodput_bytes"] > 0)) then print("\n") else print("\n") end print("\n") print("\n") if(flow["tcp.nw_latency.client"] ~= nil) then local rtt = flow["tcp.nw_latency.client"] + flow["tcp.nw_latency.server"] if(rtt > 0) then local cli2srv = round(((flow["tcp.nw_latency.client"] * 100) / rtt), 2) local srv2cli = round(((flow["tcp.nw_latency.server"] * 100) / rtt), 2) print("\n") -- Inspired by https://gist.github.com/geraldcombs/d38ed62650b1730fb4e90e2462f16125 print("\n") end end if(flow["tcp.appl_latency"] ~= nil and flow["tcp.appl_latency"] > 0) then print("\n") end if(not string.starts(ifname, "nf:")) then if((flow["cli2srv.packets"] > 1) and (flow["interarrival.cli2srv"]["max"] > 0)) then print("\n") if(flow["srv2cli.packets"] < 2) then print("\n") if(flow["flow.idle"] == true) then print("") end end if(flow["tcp.seq_problems"] ~= nil) then rowspan = 2 if((flow["cli2srv.retransmissions"] + flow["srv2cli.retransmissions"]) > 0) then rowspan = rowspan+1 end if((flow["cli2srv.out_of_order"] + flow["srv2cli.out_of_order"]) > 0) then rowspan = rowspan+1 end if((flow["cli2srv.lost"] + flow["srv2cli.lost"]) > 0) then rowspan = rowspan+1 end if((flow["cli2srv.keep_alive"] + flow["srv2cli.keep_alive"]) > 0) then rowspan = rowspan+1 end if((flow["cli2srv.retransmissions"] + flow["srv2cli.retransmissions"] + flow["cli2srv.out_of_order"] + flow["srv2cli.out_of_order"] + flow["cli2srv.lost"] + flow["srv2cli.lost"] + flow["cli2srv.keep_alive"] + flow["srv2cli.keep_alive"]) > 0) then print("") print("\n") if((flow["cli2srv.retransmissions"] + flow["srv2cli.retransmissions"]) > 0) then print("\n") end if((flow["cli2srv.out_of_order"] + flow["srv2cli.out_of_order"]) > 0) then print("\n") end if((flow["cli2srv.lost"] + flow["srv2cli.lost"]) > 0) then print("\n") end if((flow["cli2srv.keep_alive"] + flow["srv2cli.keep_alive"]) > 0) then print("\n") end end end end if(flow["protos.ssl.certificate"] ~= nil) then print("") if(flow["protos.ssl.server_certificate"] ~= nil) then print("") end print("\n") end if((flow["tcp.max_thpt.cli2srv"] ~= nil) and (flow["tcp.max_thpt.cli2srv"] > 0)) then print("\n") end if((flow["cli2srv.trend"] ~= nil) and false) then print("\n") end flags = flow["cli2srv.tcp_flags"] or flow["srv2cli.tcp_flags"] if((flags ~= nil) and (flags > 0)) then print("\n") print("\n") end local icmp = flow["icmp"] if(icmp ~= nil) then print("\n") end if interface.isPacketInterface() then print("\n") end if((flow.client_process == nil) and (flow.server_process == nil)) then print("\n") else if((flow.client_process ~= nil) or (flow.server_process ~= nil)) then print('\n') end if(flow.client_process ~= nil) then displayProc(flow.client_process, "\n") end if(flow.server_process ~= nil) then displayProc(flow.server_process, "\n") end end if(flow["protos.dns.last_query"] ~= nil) then print("\n") end if(not isEmptyString(flow["bittorrent_hash"])) then print("\n") end if(not isEmptyString(flow["protos.ssh.client_signature"])) then print("\n") end if(flow["protos.http.last_url"] ~= nil) then print("") print("") print("") print("\n") print("\n") if not have_nedge then print("\n") end else if((flow["host_server_name"] ~= nil) and (flow["protos.dns.last_query"] == nil)) then print("\n") end end if(flow["profile"] ~= nil) then print("\n") end if (flow["moreinfo.json"] ~= nil) then local flow_field_value_maps = require "flow_field_value_maps" local info, pos, err = json.decode(flow["moreinfo.json"], 1, nil) local isThereSIP = 0 local isThereRTP = 0 -- Convert the array to symbolic identifiers if necessary local syminfo = {} for key, value in pairs(info) do key, value = flow_field_value_maps.map_field_value(key, value) local k = rtemplate[tonumber(key)] if(k ~= nil) then syminfo[k] = value else syminfo[key] = value end end info = syminfo -- get SIP rows if(ntop.isPro() and (flow["proto.ndpi"] == "SIP")) then local sip_table_rows = getSIPTableRows(info) print(sip_table_rows) isThereSIP = isThereProtocol("SIP", info) if(isThereSIP == 1) then isThereSIP = isThereSIPCall(info) end end info = removeProtocolFields("SIP",info) -- get RTP rows if(ntop.isPro() and (flow["proto.ndpi"] == "RTP")) then local rtp_table_rows = getRTPTableRows(info) print(rtp_table_rows) -- io.write(flow["proto.ndpi"].."\n") isThereRTP = isThereProtocol("RTP", info) end info = removeProtocolFields("RTP",info) local snmpdevice = nil if(ntop.isPro() and not isEmptyString(syminfo["EXPORTER_IPV4_ADDRESS"])) then snmpdevice = syminfo["EXPORTER_IPV4_ADDRESS"] elseif(ntop.isPro() and not isEmptyString(syminfo["NPROBE_IPV4_ADDRESS"])) then snmpdevice = syminfo["NPROBE_IPV4_ADDRESS"] end if not isEmptyString(snmpdevice) and syminfo["INPUT_SNMP"] and syminfo["OUTPUT_SNMP"] then printFlowSNMPInfo(snmpdevice, syminfo["INPUT_SNMP"], syminfo["OUTPUT_SNMP"]) end local num = 0 for key,value in pairs(info) do if(num == 0) then print("\n") end if(value ~= "") then print("\n") end num = num + 1 end end 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").."") else print("") end if(flow["verdict.pass"] == false) then print("") end print(flow["proto.l4"].." / ") print(getApplicationLabel(flow["proto.ndpi"]).." ") print("(") print(getCategoryLabel(flow["proto.ndpi_cat"])) print(") ".. formatBreed(flow["proto.ndpi_breed"])) if(flow["verdict.pass"] == false) then print("") end historicalProtoHostHref(ifid, flow["cli.ip"], nil, flow["proto.ndpi_id"], flow["protos.ssl.certificate"]) if(ifstats.inline) then if(flow["verdict.pass"]) then print('
') print('') print('') print('\n') print('
') end end print('
VRF Id "..flow.vrfId.."
"..i18n("flow_details.flow_shapers")..""..c.."".. shaper.icon .. " " .. shaper.text .."
"..s.."".. shaper.icon .. " " .. shaper.text.."
"..i18n("flow_details.flow_quota")..""..c.."") printFlowQuota(ifstats.id, flow, true --[[ client ]]) print("
"..s.."") printFlowQuota(ifstats.id, flow, false --[[ server ]]) print("
"..i18n("flow_details.flow_marker").."".. NfConfig.formatMarker(flow["marker"]) .."
"..i18n("device_protocols.device_protocol_policy")..""..i18n("device_protocols.devtype_as_proto_client", {devtype=discover.devtype2string(status_info["cli.devtype"]), proto=interface.getnDPIProtoName(proto)}).."") 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(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").."]" .. "
" .. formatEpoch(flow["seen.last"]) .. " [" .. secondsToTime(os.time()-flow["seen.last"]) .. " "..i18n("details.ago").."]" .. "
"..i18n("details.total_traffic")..""..i18n("total")..": " .. bytesToSize(flow["bytes"]) .. " "..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(" %)
 
" .. 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('
'.. cli_name..'
' .. srv_name .. '
') print("
"..i18n("flow_details.rtt_breakdown").."") print('
'.. cli2srv ..' ms (client)
') print('
' .. round(flow["tcp.nw_latency.server"],2) .. ' ms (server)
') 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(" ") 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(""..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("
".. ''.. 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")..""..i18n("flow_details.http_method")..""..(flow["protos.http.last_method"] or '').."
"..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) .. "
\n") end print [[ ]] dofile(dirs.installdir .. "/scripts/lua/inc/footer.lua")