ntopng/scripts/lua/if_stats.lua
Simone Mainardi c7082a4647 Implements new alerts database and drilldown
alert store skeleton

Alert database type changes

Implement alert store for host alerts. All alert store skeletons.

Fix class method access

Enable tracing

Implements simple queries for host alerts

Implement flow alert store

Fixes escaping of INSERT queries

Flow alerts database schema fixes

Adds escaping for alert JSON in flows and hosts

Implements queries .select() for alerts store

Adds limit and offset to perform paginated queries

Adds new REST getter for flow alerts

Name changes alert_severity to severity, alert_json to json

Fixes alert message not shown

Implement active monitoring alerts store

Implements sort of queries in the new dataabase

Changes alert_type to alert_id

Implement mac alerts store

Fixes flow alert messages

Implement system alerts store

Implement snmp alert store

Add missing items to the flow alerts

Add missing items to the host alerts

Add missing items to the mac alerts

Implements COUNT aplerts api

Add device_name to snmp alerts

add flow alerts templates

updated gitignore

fix for missing order field

add families defined in `alert_store_schema.sql`

Reworks and simplifies alert store subclasses

Implements REST API to fetch alert timeseries

Fixes date in flow REST api

Host alert json fix

Add get/host/alert/list.lua

Move alert/list.lua to alert/past/list.lua

Add alert/past/list.lua for all alert families

Add entity_id to system table to identify the alert type based on <alert_id, entity_id>

Add missing field

Implements facilities to query engaged alerts via REST

Handle both historical and past alerts in alert/list.lua

Fix count

Update params of select_historical

Implement method to add family-specific filters

Add alert/ts.lua for all alert families

Implements facilities and REST endpoints to delete alerts

Implements ordering of alert queries

Fix add_order_by group_by

Rest API tests update

Tests output update

Remove debug trace

Use alert_id instead of type. Add more flow alert info.

Update http lint

Format obsolete tlv version alerts. Add more host info.

Add row_id to list of alerts

Fix selection of engaged alerts

Add test for mac alerts (bcast domains)

Removes attempt to format alerts as flow alerts

Fixes interface selection for active monitoring

Update test output with rest changes

Add more fields to be ignores

Set alert count to 1 for the time being

add bar timeseries chart

add apexcharts

improvements on timeseries bar chart

registered chart callbakcs

working on alert page

fix for date format

Fixes acrive monitoring REST API

Fixes alignment of grouped alert data

Additional fix for alert histogram

remove useless if

formatting alerts page

fixes on flows alert stats table

rename local networks to device

format host pagie in alert_stats

add tag support for hosts and flow

implemented single delete action

add release modal

Fixes format of threshold cross interface alerts

Fixes wrong increase of dropped alerts

Implements exclusion list for invalid dns queries

Reworks exclusions lists for hosts and flows

Addresses #5212
Addresses #5113

Adds host alert keys in host callbacks definitions

Adds alert ids to flow callbacks

fix for not working button (#5215)

Fixes reported timeseries name

removed any additional button inside chart's toolbar (#5200)

Add tables for interfaces, networks, users to the schema. Skeleton alert_store classes

fixed broken range picker layout in firefox (#5199)

Alert insert fixes

Add more info to network alerts

Add rest endpoint for interface, network, user alerts

Fix endpoint selection in alerts_stats

Unifies columns between engaged and past alerts

Fixes Missing mandatory 'alert_granularity'

Minor fixes for missing alert_severity

Fixes arithmetic on a nil value (field 'last_seen')

Fixes get/system/alert/list.lua

use tstamp for column names (#5221)

Implements host alert formatter

Add alerts_store format_record_common

Use common format_record for am, system alerts

Use common format_record for all alerts

Fixes formatting of alerts of all types

Fixes nil in function 'hostinfo2label'

fixes on disable modal

add pages for network, user and interface endpoint (#5224)

Set alert_entity in all classes

Unifies influxdb alerts into system alerts

Addresses #5224

Unifies process alerts into system alerts

Addresses #5224

Cleanup unused periodicActivityEntity

Unifies category lists alerts into system alerts

Addresses #5224

Aligns new alert enums

Addresses #5224

Fixes alert page links

Fixes insertion of interface alerts

Implement filters for Host alerts

Fixes active monitoring alerts not triggering

Implement filters on flow alerts

Fixes for internal alerts timestamp and subtype

implements disable for the alerts

formatted alert disable label

Add address and device type to mac alert records

fix for delete alert toggle

Fix access to entity_val in alert_unexpected_new_device

add mac address and device type inside table

Fixes for new alert fields not handled

Fixes alert_definitions to handle new fields

Add ip/port to snmp alert records

Implements deletion of stored flow alerts

Add alert_name to all alert records via rest. Fix duration.

fixes for snmp tab

Implements delete of past host alerts

Add name to snmp alert records

fixes on system tab

Fix Date column

fixes link

Update menu

Fixes bad argument #3 to 'format' in snmp alerts

updated interface link

new alerts url for host (#5228)

Fixes sort of engaged alert

Minor cleanup

Fixes data returned for local network alerts

Fix duration for one shot. Note.

Fix duration override

Fixes interface selection for system alerts

Move host alert page

fixes for local network tab

Minor fix

Fix engaged host alerts

fixes on user tab

Fix alert_user_activity message
2021-04-26 19:41:34 +02:00

2533 lines
99 KiB
Lua

--
-- (C) 2013-21 - ntop.org
--
local dirs = ntop.getDirs()
package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path
if((dirs.scriptdir ~= nil) and (dirs.scriptdir ~= "")) then package.path = dirs.scriptdir .. "/lua/modules/?.lua;" .. package.path end
local top_sites_update
local snmp_utils
if ntop.isPro() then
package.path = dirs.installdir .. "/scripts/lua/pro/modules/?.lua;" .. package.path
package.path = dirs.installdir .. "/pro/scripts/callbacks/?.lua;" .. package.path
snmp_utils = require "snmp_utils"
top_sites_update = require("host_sites_update")
end
local json = require "dkjson"
local template = require "template_utils"
local os_utils = require "os_utils"
local format_utils = require "format_utils"
local top_talkers_utils = require "top_talkers_utils"
local internals_utils = require "internals_utils"
local page_utils = require("page_utils")
local ui_utils = require("ui_utils")
local interface_pools = require ("interface_pools")
require "lua_utils"
require "prefs_utils"
local graph_utils = require "graph_utils"
local alert_utils = require "alert_utils"
require "db_utils"
local recording_utils = require "recording_utils"
local companion_interface_utils = require "companion_interface_utils"
local storage_utils = require "storage_utils"
local have_nedge = ntop.isnEdge()
local sites_granularities = nil
if ntop.isPro() then
shaper_utils = require("shaper_utils")
end
sendHTTPContentTypeHeader('text/html')
page = _GET["page"]
ifid = _GET["ifid"]
-- parse interface names and possibly fall back to the selected interface:
-- priority goes to the interface id
if ifid ~= nil and ifid ~= "" then
if_name = getInterfaceName(ifid)
else
-- fall-back to the default interface
if_name = ifname
ifid = interface.name2id(ifname)
end
interface.select(ifname)
ifname_clean = "iface_"..tostring(ifid)
msg = ""
local is_packet_interface = interface.isPacketInterface()
local is_pcap_dump = interface.isPcapDumpInterface()
local ifstats = interface.getStats()
if page == "syslog_producers" and not ifstats.isSyslog then
page = "overview"
end
local is_mirrored_traffic = false
local is_mirrored_traffic_pref = string.format("ntopng.prefs.ifid_%d.is_traffic_mirrored", interface.getId())
if not ntop.isnEdge() and is_packet_interface then
is_mirrored_traffic = ternary(ntop.getPref(is_mirrored_traffic_pref) == '1', true, false)
end
local service_map = interface.serviceMap()
local service_map_available = false
if(service_map and (table.len(service_map) > 0)) then
service_map_available = true
end
local disaggregation_criterion_key = "ntopng.prefs.dynamic_sub_interfaces.ifid_"..tostring(ifid)..".mode"
local charts_available = areInterfaceTimeseriesEnabled(ifid)
function inline_input_form(name, placeholder, tooltip, value, can_edit, input_opts, input_class, measure_unit)
if(can_edit) then
print('<input style="width:12em;" title="'..tooltip..'" '..(input_opts or "")..' class="form-control '..(input_class or "")..'" name="'..name..'" placeholder="'..placeholder..'" value="')
if(value ~= nil) then print(value.."") end
print[[">]]
if (measure_unit) then
print([[<span class='ml-1 align-middle'>]].. i18n(measure_unit) ..[[</span>]])
end
else
if(value ~= nil) then print(value) end
end
end
function inline_select_form(name, keys, values, curval)
print[[<select class="form-control" style="width:12em; display:inline;" name="]] print(name) print[[">]]
for idx, k in ipairs(keys) do
local v = values[idx]
print[[<option value="]] print(v) print[[" ]]
if curval == v then
print("selected")
end
print[[>]] print(k) print[[</option>]]
end
print[[</select>]]
end
-- this is a user-browseable page, so we must return counters from
-- the latest reset as the user may have chosen to reset statistics at some point
if ifstats.stats and ifstats.stats_since_reset then
-- override stats with the values calculated from the latest user reset
for k, v in pairs(ifstats.stats_since_reset) do
ifstats.stats[k] = v
end
end
if ifstats.zmqRecvStats and ifstats.zmqRecvStats_since_reset then
-- override stats with the values calculated from the latest user reset
for k, v in pairs(ifstats.zmqRecvStats_since_reset) do
ifstats.zmqRecvStats[k] = v
end
end
local ext_interfaces = {}
-- refresh traffic recording availability as one may have installed n2disk
-- with a running instance of ntopng
recording_utils.checkAvailable()
if recording_utils.isAvailable() and recording_utils.isSupportedZMQInterface(ifid) then
ext_interfaces = recording_utils.getExtInterfaces(ifid)
end
if (isAdministrator()) then
if (page == "config") and (not table.empty(_POST)) then
local custom_name = _POST["custom_name"]
if starts(custom_name, "tcp:__") then
-- Was mangled by sanitization
custom_name = "tcp://" .. string.sub(custom_name, 7)
end
ntop.setCache('ntopng.prefs.ifid_'..ifstats.id..'.name', custom_name)
local ifspeed_cache = 'ntopng.prefs.ifid_'..ifstats.id..'.speed'
if isEmptyString(_POST["ifSpeed"]) then
ntop.delCache(ifspeed_cache)
else
ntop.setCache(ifspeed_cache, _POST["ifSpeed"])
end
local hide_set = getHideFromTopSet(ifstats.id)
ntop.delCache(hide_set)
for _, net in pairs(split(_POST["hide_from_top"] or "", ",")) do
net = trimSpace(net)
if not isEmptyString(net) then
local address, prefix, vlan = splitNetworkWithVLANPrefix(net)
if isIPv6(address) and prefix == "128" then
net = address
elseif isIPv4(address) and prefix == "32" then
net = address
end
ntop.setMembersCache(hide_set, net)
end
end
interface.reloadHideFromTop()
if is_packet_interface then
if _POST["gw_macs"] ~= nil then
-- Gw MAC addresses - used to compute traffic direction
local gw_macs_set = getGwMacsSet(ifstats.id)
ntop.delCache(gw_macs_set)
for _, mac in pairs(split(_POST["gw_macs"] or "", ",")) do
mac = trimSpace(mac)
if not isEmptyString(mac) then
ntop.setMembersCache(gw_macs_set, mac)
end
end
interface.reloadGwMacs()
end
end
if not ntop.isnEdge() and is_packet_interface then
if _POST["is_mirrored_traffic"] == "1" then
is_mirrored_traffic = true
else
is_mirrored_traffic = false
end
ntop.setPref(is_mirrored_traffic_pref, ternary(is_mirrored_traffic == true, '1', '0'))
interface.updateTrafficMirrored()
end
setInterfaceRegreshRate(ifstats.id, tonumber(_POST["ifRate"]))
local sf = tonumber(_POST["scaling_factor"])
if(sf == nil) then sf = 1 end
ntop.setCache("ntopng.prefs.iface_" .. tostring(ifid)..'.scaling_factor',tostring(sf))
interface.loadScalingFactorPrefs()
end
end
page_utils.set_active_menu_entry(page_utils.menu_entries.interface, { ifname=getHumanReadableInterfaceName(if_name) })
print("<link href=\""..ntop.getHttpPrefix().."/css/tablesorted.css\" rel=\"stylesheet\">")
dofile(dirs.installdir .. "/scripts/lua/inc/menu.lua")
print(msg)
if _SERVER["REQUEST_METHOD"] == "POST" and _POST["companion_interface"] ~= nil then
companion_interface_utils.setCompanion(ifstats.id, _POST["companion_interface"])
end
if _SERVER["REQUEST_METHOD"] == "POST" and _POST["disaggregation_criterion"] ~= nil then
if _POST["disaggregation_criterion"] == "none" then
ntop.delCache(disaggregation_criterion_key)
else
ntop.setCache(disaggregation_criterion_key, _POST["disaggregation_criterion"])
end
end
if _SERVER["REQUEST_METHOD"] == "POST" and not isEmptyString(_POST["traffic_recording_provider"]) then
local prev_provider = recording_utils.getCurrentTrafficRecordingProvider(ifstats.id)
-- if the current provider is the builtin ntopng and we are changing to another provider
-- then it may be necessary to stop the builtin ntopng
if prev_provider == "ntopng" and _POST["traffic_recording_provider"] ~= "ntopng" then
recording_utils.stop(ifstats.id)
ntop.setCache('ntopng.prefs.ifid_'..ifstats.id..'.traffic_recording.enabled', "false")
end
recording_utils.setCurrentTrafficRecordingProvider(ifstats.id, _POST["traffic_recording_provider"])
end
local has_traffic_recording_page = (recording_utils.isAvailable()
and (is_packet_interface
or ((recording_utils.isSupportedZMQInterface(ifid) and not table.empty(ext_interfaces)))
or (recording_utils.getCurrentTrafficRecordingProvider(ifid) ~= "ntopng")))
local dismiss_recording_providers_reminder = recording_utils.isExternalProvidersReminderDismissed(ifstats.id)
local url = ntop.getHttpPrefix()..'/lua/if_stats.lua?ifid=' .. ifid
-- Added global javascript variable, in order to disable the refresh of pie chart in case
-- of historical interface
print('\n<script>var refresh = '..getInterfaceRefreshRate(ifstats.id)..' * 1000; /* ms */;</script>\n')
local short_name = getHumanReadableInterfaceName(ifname)
local title = i18n("interface") .. ": " .. shortenCollapse(short_name)
if (ntop.isPro()) then
sites_granularities = top_sites_update.getGranularitySites(nil, nil, ifId, true)
end
local periodicity_map_available = false
local service_map_available = false
if(ntop.isEnterpriseL() and (ntop.getPref("ntopng.prefs.is_behaviour_analysis_enabled") == "1")) then
local service_map = interface.serviceMap(_GET["host"])
if service_map and (table.len(service_map) > 0) then
service_map_available = true
end
end
if(ntop.isEnterpriseL() and (ntop.getPref("ntopng.prefs.is_behaviour_analysis_enabled") == "1")) then
local periodicity_map = interface.periodicityMap(_GET["host"])
if periodicity_map and (table.len(periodicity_map) > 0) then
periodicity_map_available = true
end
end
page_utils.print_navbar(title, url,
{
{
hidden = only_historical,
active = page == "overview" or page == nil,
page_name = "overview",
label = "<i class=\"fas fa-lg fa-home\"></i>",
},
{
hidden = not is_packet_interface or ntop.isnEdge() or interface.isView(),
active = page == "networks",
page_name = "networks",
label = i18n("networks"),
},
{
hidden = have_nedge or not ifstats or ifstats.stats.packets == 0 or ntop.isnEdge(),
active = page == "packets",
page_name = "packets",
label = i18n("packets"),
},
{
hidden = not ifstats or not ifstats["has_macs"] or ntop.isnEdge(),
active = page == "DSCP",
page_name = "DSCP",
label = i18n("dscp"),
},
{
active = page == "ndpi",
page_name = "ndpi",
label = i18n("applications"),
},
{
hidden = have_nedge,
active = page == "ICMP",
page_name = "ICMP",
label = i18n("icmp"),
},
{
hidden = not ifstats or not ifstats["has_macs"] or ntop.isnEdge(),
active = page == "ARP",
page_name = "ARP",
label = i18n("arp"),
},
{
hidden = (table.len(sites_granularities) == 0),
active = page == "sites",
page_name = "sites",
label = i18n("sites_page.sites"),
},
{
hidden = not charts_available,
active = page == "historical",
page_name = "historical",
label = "<i class='fas fa-lg fa-chart-area'></i>",
},
{
hidden = have_nedge or not ifstats or table.empty(ifstats.profiles),
active = page == "trafficprofiles",
page_name = "trafficprofiles",
label = "<i class=\"fas fa-lg fa-user-md\"></i>",
},
{
hidden = not has_traffic_recording_page,
active = page == "traffic_recording",
page_name = "traffic_recording",
label = "<i class=\"fas fa-lg fa-hdd\"></i>",
},
{
hidden = not isAdministrator() or not areAlertsEnabled(),
active = page == "alerts",
page_name = "alerts",
url = ntop.getHttpPrefix() .. "/lua/alert_stats.lua?&page=interface",
label = "<i class=\"fas fa-lg fa-exclamation-triangle\"></i>",
},
{
hidden = not hasTrafficReport(),
active = page == "traffic_report",
page_name = "traffic_report",
label = "<i class='fas fa-lg fa-file-alt report-icon'></i>",
},
{
hidden = not isAdministrator() or is_pcap_dump,
active = page == "config",
page_name = "config",
label = "<i class=\"fas fa-lg fa-cog\"></i>",
},
{
active = page == "internals",
page_name = "internals",
label = "<i class=\"fas fa-lg fa-wrench\"></i>",
},
{
hidden = have_nedge or not isAdministrator() or not ntop.isEnterpriseM() or ifstats.isDynamic or ifstats.isView,
active = page == "sub_interfaces",
page_name = "sub_interfaces",
label = "<i class=\"fas fa-lg fa-code-branch\"></i>",
},
{
hidden = have_nedge or not isAdministrator() or not ifstats.isSyslog,
active = page == "syslog_producers",
page_name = "syslog_producers",
label = "<i class=\"fas fa-lg fa-hand-holding\"></i>",
},
{
hidden = not isAdministrator() or not ifstats.has_macs or have_nedge,
active = page == "unassigned_pool_devices",
page_name = "unassigned_pool_devices",
label = "<i class=\"fas fa-lg fa-user-slash\"></i>",
},
{
hidden = not isAdministrator() or is_pcap_dump,
active = page == "dhcp",
page_name = "dhcp",
label = "<i class=\"fas fa-lg fa-bolt\"></i>",
},
{
hidden = (not periodicity_map_available),
page_name = "service_map",
url = ntop.getHttpPrefix() .. "/lua/pro/enterprise/periodicity_map.lua",
label = "<i class=\"fas fa-lg fa-clock\"></i>",
},
{
hidden = (not service_map_available),
page_name = "service_map",
url = ntop.getHttpPrefix() .. "/lua/pro/enterprise/service_map.lua",
label = "<i class=\"fas fa-lg fa-concierge-bell\"></i>",
},
}
)
print(
template.gen("modal_confirm_dialog.html", {
dialog={
id = "reset_stats_dialog",
action = "resetCounters(false)",
title = i18n("reset_if_title"),
message = i18n("reset_if_message"),
confirm = i18n("reset"),
confirm_button = "btn-danger",
}
})
)
print(
template.gen("modal_confirm_dialog.html", {
dialog={
id = "reset_drops_dialog",
action = "resetCounters(true)",
title = i18n("reset_drops_if_title"),
message = i18n("reset_drops_if_message"),
confirm = i18n("reset"),
confirm_button = "btn-danger",
}
})
)
if((page == "overview") or (page == nil)) then
local tags = {ifid = ifstats.id}
print("<div class='table-responsive-xl'>")
print[[
]]
print("<table class=\"table table-striped table-bordered\">\n")
print("<tr><th width=15%>"..i18n("if_stats_overview.id").."</th><td colspan=6>" .. ifstats.id .. " ")
if(ifstats.description ~= ifstats.name) then print(" ("..ifstats.description..")") end
print("</td></tr>\n")
if not is_pcap_dump and ifstats["type"] ~= "netfilter" then
print("<tr><th width=250>"..i18n("if_stats_overview.state").."</th><td colspan=6>")
state = toggleTableButton("", "", i18n("if_stats_overview.active"), "1","primary", i18n("if_stats_overview.paused"), "0","primary", "toggle_local", "ntopng.prefs.ifid_"..tostring(ifid).."_not_idle")
if(state == "0") then
on_state = true
else
on_state = false
end
interface.setInterfaceIdleState(on_state)
print("</td></tr>\n")
end
if(ifstats["remote.name"] ~= nil) then
local max_items_per_row = 3
local cur_i = 0
local title = i18n("if_stats_overview.remote_probe")
if ifstats["remote.name"] == "none" then
title = title .. " [" .. i18n("if_stats_overview.remote_probe_collector_mode") .. "]"
end
print("<tr><th colspan=7 nowrap>".. title .."</th></tr><tr>")
if(ifstats["remote.name"] ~= "none") then
if cur_i >= max_items_per_row then print("</tr><tr>"); cur_i = 0 end
print("<th nowrap>".. i18n("if_stats_overview.interface_name") .."</th><td nowrap>".. string.format("%s [%s]", ifstats["remote.name"], bitsToSize(ifstats.speed*1000000)) .."</td>")
cur_i = cur_i + 1
end
if not isEmptyString(ifstats["probe.probe_version"]) then
if cur_i >= max_items_per_row then print("</tr><tr>"); cur_i = 0 end
print("<th nowrap>".. i18n("if_stats_overview.remote_probe") .."</th><td nowrap>" .. ifstats["probe.probe_version"])
if not isEmptyString(ifstats["probe.probe_os"]) then
print(" ("..ifstats["probe.probe_os"]..")")
end
print("</td>")
cur_i = cur_i + 1
end
if not isEmptyString(ifstats["probe.ip"]) then
if cur_i >= max_items_per_row then print("</tr><tr>"); cur_i = 0 end
print("<th nowrap>".. i18n("if_stats_overview.probe_ip"))
if not isEmptyString(ifstats["probe.public_ip"]) then
print(" / ".. i18n("if_stats_overview.public_probe_ip"))
end
print("</th><td nowrap>" .. ifstats["probe.ip"])
if not isEmptyString(ifstats["probe.public_ip"]) then
print(" / <A HREF=\"http://"..ifstats["probe.public_ip"].."\">"..ifstats["probe.public_ip"].."</A> <i class='fas fa-external-link-alt'><i>")
end
print("</td>")
cur_i = cur_i + 1
end
if not isEmptyString(ifstats["remote_pps"]) or not isEmptyString(ifstats["remote_bps"]) then
if cur_i >= max_items_per_row then print("</tr><tr>"); cur_i = 0 end
print("<th nowrap>".. i18n("if_stats_overview.probe_throughput").."</th>")
print('<td nowrap><span id="if_zmq_remote_bps">' .. format_utils.bitsToSize(ifstats["remote_bps"]) .. '</span>')
print(' [<span id="if_zmq_remote_pps">' .. format_utils.pktsToSize(ifstats["remote_pps"]) .. '</span>]</td>')
cur_i = cur_i + 1
end
if ifstats["timeout.lifetime"] > 0 then
if cur_i >= max_items_per_row then print("</tr><tr>"); cur_i = 0 end
print("<th nowrap>"..i18n("if_stats_overview.probe_timeout_lifetime")..
" <sup><i class='fas fa-question-circle ' title='"..i18n("if_stats_overview.note_probe_zmq_timeout_lifetime").."'></i></sup></th><td nowrap>")
if((ifstats["timeout.collected_lifetime"] ~= nil) and (ifstats["timeout.collected_lifetime"] > 0)) then
-- We're in collector mode on the nProbe side
print(" "..secondsToTime(ifstats["timeout.lifetime"]).." [".. i18n("if_stats_overview.remote_flow_lifetime")..": "..secondsToTime(ifstats["timeout.collected_lifetime"]).."]")
else
-- Modern nProbe in non-flow collector mode or old nProbe
print(secondsToTime(ifstats["timeout.lifetime"]))
end
print("</td>")
cur_i = cur_i + 1
end
if ifstats["timeout.idle"] > 0 then
if cur_i >= max_items_per_row then print("</tr><tr>"); cur_i = 0 end
print("<th nowrap><b>"..i18n("if_stats_overview.probe_timeout_idle").."</th><td nowrap>"..secondsToTime(ifstats["timeout.idle"]).."</td>")
cur_i = cur_i + 1
end
if not isEmptyString(ifstats["probe.local_time"]) and not isEmptyString(ifstats["probe.remote_time"]) then
local tdiff = math.abs(ifstats["probe.local_time"]-ifstats["probe.remote_time"])
if cur_i >= max_items_per_row then print("</tr><tr>"); cur_i = 0 end
print("<th nowrap>"..i18n("if_stats_overview.remote_probe_time")..
" <sup><i class='fas fa-question-circle ' title='"..i18n("if_stats_overview.note_remote_probe_time").."'></i></sup>" ..
"</th><td nowrap>")
if(tdiff > 10) then print("<font color=red><b>") end
print(formatValue(tdiff).." sec")
if(tdiff > 10) then print("</b></font>") end
print("</td>")
cur_i = cur_i + 1
end
local has_drops_export_queue_full = (tonumber(ifstats["zmq.drops.export_queue_full"]) and tonumber(ifstats["zmq.drops.export_queue_full"]) > 0)
local has_drops_flow_collection_drops = (tonumber(ifstats["zmq.drops.flow_collection_drops"]) or 0) > 0
local has_drops_flow_collection_udp_socket_drops = (tonumber(ifstats["zmq.drops.flow_collection_udp_socket_drops"]) or 0) > 0
local has_remote_drops = (has_drops_export_queue_full or has_drops_flow_collection_drops)
if has_drops_export_queue_full then
local span_class = ' '
if cur_i >= max_items_per_row then print("</tr><tr>"); cur_i = 0 end
print("<th nowrap>"..i18n("if_stats_overview.probe_zmq_drops_export_queue_full").." <sup><i class='fas fa-question-circle ' title='"..i18n("if_stats_overview.note_probe_zmq_drops_export_queue_full").."'></i></sup></th>")
print("<td nowrap><span "..span_class.." id=if_zmq_drops_export_queue_full>"..formatValue(ifstats["zmq.drops.export_queue_full"]).."</span> <span id=if_zmq_drops_export_queue_full_trend></span></td>")
cur_i = cur_i + 1
end
if has_drops_flow_collection_drops then
local span_class = ' '
if cur_i >= max_items_per_row then print("</tr><tr>"); cur_i = 0 end
print("<th nowrap>"..i18n("if_stats_overview.probe_zmq_drops_flow_collection_drops").." <sup><i class='fas fa-question-circle ' title='"..i18n("if_stats_overview.note_probe_zmq_drops_flow_collection_drops").."'></i></sup></th>")
print("<td nowrap><span "..span_class.." id=if_zmq_drops_flow_collection_drops>"..formatValue(ifstats["zmq.drops.flow_collection_drops"]).."</span> <span id=if_zmq_drops_flow_collection_drops_trend></span></td>")
cur_i = cur_i + 1
end
if has_drops_flow_collection_udp_socket_drops then
local span_class = ' '
if cur_i >= max_items_per_row then print("</tr><tr>"); cur_i = 0 end
print("<th nowrap>"..i18n("if_stats_overview.probe_zmq_drops_flow_collection_udp_socket_drops").." <sup><i class='fas fa-question-circle ' title='"..i18n("if_stats_overview.note_probe_zmq_drops_flow_collection_udp_socket_drops").."'></i></sup></th>")
print("<td nowrap><span "..span_class.." id=if_zmq_drops_flow_collection_udp_socket_drops>"..formatValue(ifstats["zmq.drops.flow_collection_udp_socket_drops"]).."</span> <span id=if_zmq_drops_flow_collection_udp_socket_drops_trend></span></td>")
cur_i = cur_i + 1
end
print("</tr>")
end
local is_physical_iface = is_packet_interface and (not is_pcap_dump)
local label = getHumanReadableInterfaceName(ifstats.name)
local s
if ((not isEmptyString(label)) and (label ~= ifstats.name)) then
s = label.." (" .. ifstats.name .. ")"
else
s = ifstats.name
end
if((isAdministrator()) and (not is_pcap_dump)) then
s = s .. " <a href=\""..url.."&page=config\"><i class=\"fas fa-cog fa-sm\" title=\"Configure Interface Name\"></i></a>"
end
print('<tr><th width="250">'..i18n("name")..'</th><td colspan="2"><p style="word-break: break-all">')
print(s)
if(ifstats.mac and ifstats.mac ~= "00:00:00:00:00:00") then print(" [" .. ifstats.mac .. "]"); end
print('</p></td>\n')
print("<th>"..i18n("if_stats_overview.family").."</th><td colspan=2>")
if(ifstats.type == "zmq") then
print("ZMQ")
else
print(ifstats.type)
end
if(ifstats.inline) then
print(" "..i18n("if_stats_overview.in_path_interface"))
end
if(ifstats.has_traffic_directions) then
print(" ".. i18n("if_stats_overview.has_traffic_directions") .. " ")
end
print("</tr>")
if ifstats.encryption and ifstats.encryption.public_key then
print("<tr><th width=250>"..i18n("if_stats_overview.zmq_encryption_public_key").."</th><td colspan=6><span>")
print(ifstats.encryption.public_key)
print("<br><small><b>"..i18n("if_stats_overview.note").."</b>:<ul><li> ".. i18n("if_stats_overview.zmq_encryption_public_key_note", {key="&lt;key&gt;"}).."")
print("<li>nprobe --zmq "..ifstats.name.." --zmq-encryption-key '"..ifstats.encryption.public_key.."' ...")
print("</small></ul></td></tr>\n")
end
if is_physical_iface and not ifstats.isView then
print("<tr>")
print("<th>"..i18n("mtu").."</th><td colspan=2 nowrap>"..ifstats.mtu.." "..i18n("bytes").."</td>\n")
local speed_key = 'ntopng.prefs.ifid_'..tostring(interface.name2id(ifname))..'.speed'
local speed = ntop.getCache(speed_key)
if (tonumber(speed) == nil) then
speed = ifstats.speed
end
print("<th width=250>"..i18n("speed").."</th><td colspan=2>" .. bitsToSize(speed * 1000000) .. "</td>")
print("</tr>")
end
if (not hasAllowedNetworksSet()) and ((ifstats.num_alerts_engaged > 0) or (ifstats.num_dropped_alerts > 0)) then
print("<tr>")
local warning = "<i class='fas fa-exclamation-triangle fa-lg' style='color: #B94A48;'></i> "
print("<th>".. ternary(ifstats.num_alerts_engaged > 0, warning, "") ..i18n("show_alerts.engaged_alerts")..
ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=iface:alerts_stats'><i class='fas fa-chart-area fa-sm'></i></A>", "").."</th><td colspan=2 nowrap><a href='".. ntop.getHttpPrefix() .."/lua/alert_stats.lua?ifid="..ifstats.id.."'>".. formatValue(ifstats.num_alerts_engaged) .."</a> <span id=engaged_alerts_trend></span></td>\n")
print("<th width=250>".. ternary(ifstats.num_dropped_alerts > 0, warning, "")..i18n("show_alerts.dropped_alerts")..
" <i class='fas fa-sm fa-question-circle ' title='".. i18n("if_stats_overview.dropped_alerts_info") .."'></i>"..
ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=iface:alerts_stats'><i class='fas fa-chart-area fa-sm'></i></A>", "")
.."</th><td colspan=2><span id=dropped_alerts>" .. formatValue(ifstats.num_dropped_alerts) .. "</span> <span id=dropped_alerts_trend></span></td>\n</td>")
end
label = i18n("pkts")
print[[ <tr><th colspan=1 nowrap>]] print(i18n("if_stats_overview.traffic_breakdown")) print[[</th> ]]
if(ifstats.type ~= "zmq") then
print [[ <td colspan=2><div class="pie-chart" id="ifaceTrafficBreakdown"></div></td><td colspan=3> <div class="pie-chart" id="ifaceTrafficDistribution"></div></td></tr> ]]
else
print [[ <td colspan=5><div class="pie-chart" id="ifaceTrafficBreakdown"></div></td></tr> ]]
end
print [[
<script type='text/javascript'>
window.onload=function() {
do_pie("#ifaceTrafficBreakdown", ']]
print (ntop.getHttpPrefix())
print [[/lua/iface_local_stats.lua', { ifid: ]] print(ifstats.id .. " }, \"\", refresh); \n")
if(ifstats.type ~= "zmq") then
print [[ do_pie("#ifaceTrafficDistribution", ']]
print (ntop.getHttpPrefix())
print [[/lua/iface_local_stats.lua', { ifid: ]] print(ifstats.id .. ", iflocalstat_mode: \"distribution\" }, \"\", refresh); \n")
end
print [[ }
]]
print("</script>\n")
if(ifstats.zmqRecvStats ~= nil) then
print("<tr><th colspan=7 nowrap>"..i18n("if_stats_overview.zmq_rx_statistics").."</th></tr>\n")
print("<tr>")
print("<th nowrap>"..i18n("if_stats_overview.collected_flows")..ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=iface:zmq_recv_flows'><i class='fas fa-chart-area fa-sm'></i></A>", "").."</th><td width=20%><span id=if_zmq_flows>"..formatValue(ifstats.zmqRecvStats.flows).."</span></td>")
print("<th nowrap> <i class='fas fa-tint' aria-hidden='true'></i> "..i18n("if_stats_overview.unhandled_flows").."</th><td width=20%><span id=if_zmq_dropped_flows>"..formatValue(ifstats.zmqRecvStats.dropped_flows).."</span></td>")
print("<th nowrap></th><td width=20%></td>")
print("</tr>")
print("<tr>")
print("<th nowrap>"..i18n("if_stats_overview.zmq_message_rcvd")..ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=custom:zmq_msg_rcvd_vs_drops'><i class='fas fa-chart-area fa-sm'></i></A>", "").."</th><td width=20%><span id=if_zmq_msg_rcvd>"..formatValue(ifstats.zmqRecvStats.zmq_msg_rcvd).."</span></td>")
print("<th nowrap> <i class='fas fa-tint' aria-hidden='true'></i> "..i18n("if_stats_overview.zmq_message_drops")..ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=custom:zmq_msg_rcvd_vs_drops'><i class='fas fa-chart-area fa-sm'></i></A>", "").."</th><td width=20%><span id=if_zmq_msg_drops>"..formatValue(ifstats.zmqRecvStats.zmq_msg_drops).."</span></td>")
print("<th nowrap> "..i18n("if_stats_overview.zmq_avg_msg_flows").."</th><td width=20%><span id=if_zmq_avg_msg_flows></span></td>")
print("</tr>")
print("<tr>")
print("<th nowrap>"..i18n("if_stats_overview.interface_rx_updates").."</th><td width=20%><span id=if_zmq_events>"..formatValue(ifstats.zmqRecvStats.events).."</span></td>")
print("<th nowrap>"..i18n("if_stats_overview.sflow_counter_updates").."</th><td width=20%><span id=if_zmq_counters>"..formatValue(ifstats.zmqRecvStats.counters).."</span></td>")
print("<th nowrap></th><td width=20%></td>")
print("</tr>")
end
print("<tr><th colspan=7 nowrap>"..i18n("if_stats_overview.traffic_statistics").."</th></tr>\n")
print("<tr><th nowrap>"..i18n("report.traffic_anomalies")..ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=iface:hosts_anomalies'><i class='fas fa-chart-area fa-sm'></i></A>", "").."</th>")
print("<th width=20%>"..i18n("report.traffic_anomalies_local_hosts").."</th><td><span id=local_hosts_anomalies>"..formatValue(ifstats.anomalies.num_local_hosts_anomalies).."</span> <span id=local_hosts_anomalies_trend></span></td>")
print("<th width=20%>"..i18n("report.traffic_anomalies_remote_hosts").."</th><td><span id=remote_hosts_anomalies>"..formatValue(ifstats.anomalies.num_remote_hosts_anomalies).."</span> <span id=remote_hosts_anomalies_trend></span></td>")
print("</tr>\n")
print("<tr><th nowrap>"..i18n("report.total_traffic")..ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=iface:traffic'><i class='fas fa-chart-area fa-sm'></i></A>", "").."</th><td width=20%><span id=if_bytes>"..bytesToSize(ifstats.stats.bytes).."</span> [<span id=if_pkts>".. formatValue(ifstats.stats.packets) .. " ".. label .."</span>] ")
print("<span id=pkts_trend></span></td>")
if not ifstats.isDynamic then
print("<th width=20%><span id='if_packet_drops_drop'><i class='fas fa-tint' aria-hidden='true'></i></span> ")
print(i18n("if_stats_overview.dropped_packets")..ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=iface:packets_vs_drops'><i class='fas fa-chart-area fa-sm'></i></A>", "").."</th>")
print("<td width=20% colspan=3><span id=if_drops>")
if(ifstats.stats.drops > 0) then
print('<span class="badge badge-danger">')
end
print(formatValue(ifstats.stats.drops).. " " .. label)
if((ifstats.stats.packets+ifstats.stats.drops) > 0) then
local pctg = round((ifstats.stats.drops*100)/(ifstats.stats.packets+ifstats.stats.drops), 2)
if(pctg > 0) then print(" [ " .. pctg .. " % ] ") end
end
if(ifstats.stats.drops > 0) then print('</span>') end
print("</span>&nbsp;<span id=drops_trend></span>")
if(ifstats.zmqRecvStats ~= nil) then
print("<p><small> <b>"..i18n("if_stats_overview.note").."</b>:<br>".. i18n("if_stats_overview.note_drops_sflow").."</small>")
end
print("</td>")
else
print("<td width=20% colspan=3>")
print("<small><b>"..i18n("if_stats_overview.note")..":</b> "..i18n("if_stats_overview.note_drop_ifstats_dynamic").."</small>")
print("</td>")
end
print("</tr>")
if(ifstats.has_traffic_directions) then
local tx = ifstats.eth.egress.bytes
local rx = ifstats.eth.ingress.bytes
local tot = rx+tx
print("<tr><th nowrap>"..i18n("http_page.traffic_sent")..ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=iface:traffic_rxtx'><i class='fas fa-chart-area fa-sm'></i></A>", "").."</th><td width=20%><span id=if_out_bytes>"..bytesToSize(tx).."</span> [<span id=if_out_pkts>".. formatValue(ifstats.eth.egress.packets) .. " ".. label .."</span>] <span id=pkts_out_trend></span></td>")
print("<th nowrap>"..i18n("http_page.traffic_received")..ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=iface:traffic_rxtx'><i class='fas fa-chart-area fa-sm'></i></A>", "").."</th><td width=20%><span id=if_in_bytes>"..bytesToSize(rx).."</span> [<span id=if_in_pkts>".. formatValue(ifstats.eth.ingress.packets) .. " ".. label .."</span>] <span id=pkts_in_trend></span></td>")
print('<td><div class="progress"><div class="progress-bar bg-warning" style="width: ' .. (tx * 100 / tot) .. '%;">'.. i18n("sent") ..'</div>')
print('<div class="progress-bar bg-info" style="width: ' .. (rx * 100 / tot) .. '%;">'.. i18n("received")..'</div></div></td>')
print("</tr>")
end
if interface.isSyslogInterface() then
-- Syslog Stats
print("<tr>")
print("<th colspan=7 nowrap>"..i18n("if_stats_overview.syslog_statistics").."</th>")
print("</tr>")
print("<tr>")
print("<th nowrap>"..i18n("if_stats_overview.collected_logs").."</th>")
print("<td><span id=syslog_tot_events>"..formatValue(ifstats.syslog.tot_events).."</span></td>")
print("<th>"..i18n("if_stats_overview.dispatched_logs").."</th>")
print("<td><span id=syslog_dispatched>"..formatValue(ifstats.syslog.dispatched).."</span></td>")
print("<th>"..i18n("if_stats_overview.unhandled_logs").."</th>")
print("<td><span id=syslog_unhandled>"..formatValue(ifstats.syslog.unhandled).."</span></td>")
print("</tr>")
print("<tr>")
print("<th nowrap>"..i18n("if_stats_overview.malformed_logs").."</th>")
print("<td><span id=syslog_malformed>"..formatValue(ifstats.syslog.malformed).."</span></td>")
print("<th>"..i18n("if_stats_overview.host_correlations").."</th>")
print("<td><span id=syslog_host_correlations>"..formatValue(ifstats.syslog.host_correlations).."</span></td>")
print("<th>"..i18n("if_stats_overview.alert_events").."</th>")
print("<td><span id=syslog_alerts>"..formatValue(ifstats.syslog.alerts).."</span></td>")
print("</tr>")
-- Additional stats (e.g. Suricata)
local external_json_stats = ntop.getCache("ntopng.prefs.ifid_"..tostring(ifid)..".external_stats")
if not isEmptyString(external_json_stats) then
local external_stats = json.decode(external_json_stats)
if external_stats ~= nil then
local external_stats_title = i18n("external_stats.title")
if external_stats.i18n_title then
external_stats_title = i18n(external_stats.i18n_title)
external_stats.i18n_title = nil
end
print("<tr><th colspan=7 nowrap>"..external_stats_title.."</th></tr>\n")
for key, value in pairsByKeys(external_stats, asc) do
print("<tr>")
print("<th nowrap>"..ternary(i18n("external_stats."..key), i18n("external_stats."..key), key).."</th>")
print("<td colspan=4>"..ternary(type(value) == "number", formatValue(value), value).."</td>")
print("</tr>")
end
end
end
end
if prefs.is_dump_flows_enabled and not ifstats.isViewed then
local dump_to = "MySQL"
if prefs.is_dump_flows_to_es_enabled == true then
dump_to = "ElasticSearch"
end
if prefs.is_dump_flows_to_syslog_enabled == true then
dump_to = "Syslog"
end
if prefs.is_nindex_enabled == true then
dump_to = "nIndex"
end
local export_count = ifstats.stats.flow_export_count
local export_rate = ifstats.stats.flow_export_rate
local export_drops = ifstats.stats.flow_export_drops
local export_drops_pct = 0
if not export_drops or not export_count then
-- Nothing to do
elseif export_drops > 0 and export_count > 0 then
export_drops_pct = export_drops / (export_count + export_drops) * 100
elseif export_drops > 0 then
export_drops_pct = 100
end
print("<tr><th colspan=7 nowrap>")
if prefs.is_dump_flows_runtime_enabled then
print(dump_to.." "..i18n("if_stats_overview.flows_export_statistics"))
else
print(i18n("if_stats_overview.export_disabled"))
end
print("</th></tr>\n")
print("<tr>")
print("<th nowrap>"..i18n("if_stats_overview.exported_flows")..ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=iface:dumped_flows'><i class='fas fa-chart-area fa-sm'></i></A>", "").."</th>")
print("<td><span id=exported_flows>"..formatValue(export_count).."</span>")
if export_rate == nil then
export_rate = 0
end
print("&nbsp;[<span id=exported_flows_rate>"..formatValue(round(export_rate, 2)).." fps</span>]</td>")
print("<th><span id='if_flow_drops_drop'<i class='fas fa-tint' aria-hidden='true'></i></span> ")
print(i18n("if_stats_overview.dropped_flows")..ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=iface:dumped_flows'><i class='fas fa-chart-area fa-sm'></i></A>", "").."</th>")
local span_danger = ""
if not export_drops then
elseif export_drops > 0 then
span_danger = ' class="badge badge-danger"'
end
print("<td><span id=exported_flows_drops "..span_danger..">"..formatValue(export_drops).."</span>&nbsp;")
print("<span id=exported_flows_drops_pct "..span_danger..">["
..formatValue(round(export_drops_pct, 2)).."%]</span></td>")
if not is_packet_interface then
print("<th nowrap>"..i18n("if_stats_overview.direct_mode").."</th>")
print("<td>"..ternary(prefs.is_dump_flows_direct_enabled, i18n("enabled"), i18n("disabled")).."</td>")
else
print("<td colspan=2></td>")
end
print("</tr>")
end
if ifstats.stats.discarded_probing_packets then
print("<tr><td colspan=2></td><th nowrap> <i class='fas fa-trash' aria-hidden='true'></i> "..i18n("if_stats_overview.discarded_probing_traffic")..ternary(charts_available, " <A HREF='"..url.."&page=historical&ts_schema=iface:disc_prob_pkts'><i class='fas fa-chart-area fa-sm'></i></A>", "").."</th><td colspan=4width=20%><span id=if_discarded_probing_bytes>"..bytesToSize(ifstats.stats.discarded_probing_bytes).."</span> [<span id=if_discarded_probing_pkts>".. formatPackets(ifstats.stats.discarded_probing_packets) .."</span>] ")
print("<span id=if_discarded_probing_trend></span></td></tr>\n")
end
local an = ifstats.anomalies.tot_num_anomalies or {}
local tot_an = 0
if table.len(an) > 0 then
tot_an = an.local_hosts + an.remote_hosts
end
if(tot_an > 0) then
-- TODO: Add JSON update
print("<tr><th>"..i18n("if_stats_overview.counter_anomalies").."</th>")
print("<td><b>"..i18n("total").."</b>: <span id=total_anomalies>"..formatValue(tot_an).."</span><span id=total_anomalies_trend></span></td>")
print("<td><b>"..i18n("local_hosts").."</b>: <span id=local_anomalies>"..formatValue(an.local_hosts).."</span><span id=local_anomalies_trend></span></td>")
print("<td><b>"..i18n("remote_hosts").."</b>: <span id=remote_anomalies>"..formatValue(an.remote_hosts).."</span><span id=remote_anomalies_trend></span></td>")
print("<td>&nbsp;</td></tr>\n") -- Cell for future usage
end
if isAdministrator() and ifstats.isView == false then
local ts_utils = require "ts_utils_core"
local storage_info = storage_utils.interfaceStorageInfo(ifid)
local storage_items = {}
if storage_info then
if ts_utils.getDriverName() == "rrd" then
if storage_info.rrd ~= nil and storage_info.rrd > 0 then
table.insert(storage_items, {
title = i18n("if_stats_overview.rrd_timeseries"),
value = storage_info.rrd,
class = "primary",
})
end
end
if storage_info.flows ~= nil and storage_info.flows > 0 then
table.insert(storage_items, {
title = i18n("flows"),
value = storage_info.flows,
class = "info",
})
end
if storage_info.pcap ~= nil and storage_info.pcap > 0 then
local link = nil
if recording_utils.isAvailable(ifstats.id) then
link = ntop.getHttpPrefix() .. "/lua/if_stats.lua?ifid=" .. ifid .. "&page=traffic_recording"
end
table.insert(storage_items, {
title = i18n("traffic_recording.packet_dumps"),
value = storage_info.pcap,
class = "warning",
link = link
})
end
if #storage_items > 0 then
print("<tr><th>"..i18n("traffic_recording.storage_utilization").."</th><td colspan=5>")
print(graph_utils.stackedProgressBars(storage_info.total, storage_items, nil, bytesToSize))
print("</td></tr>\n")
end
end
end
if ntop.isPcapDownloadAllowed() and ifstats.isView == false and ifstats.isDynamic == false and is_packet_interface then
print("<tr><th>"..i18n("download").."&nbsp;<i class=\"fas fa-download fa-lg\"></i></th><td colspan=4>")
local live_traffic_utils = require("live_traffic_utils")
live_traffic_utils.printLiveTrafficForm(interface.getId())
print("</td></tr>\n")
end
if isAdministrator() then
print("<tr><th width=250>"..i18n("if_stats_overview.reset_counters").."</th>")
print("<td colspan=5>")
local tot = ifstats.stats.bytes + ifstats.stats.packets + ifstats.stats.drops
if(ifstats.stats.flow_export_count ~= nil) then
tot = tot + ifstats.stats.flow_export_count + ifstats.stats.flow_export_drops
end
print('<button id="btn_reset_all" type="button" class="btn btn-danger" onclick="resetInterfaceCounters(false);">'..i18n("if_stats_overview.all_counters")..'</button>&nbsp;')
print('<button id="btn_reset_drops" type="button" class="btn btn-danger" onclick="resetInterfaceCounters(true);">'..i18n("if_stats_overview.drops_only")..'</button>')
print("</td>")
print("</tr>\n")
end
if have_nedge and ifstats.type == "netfilter" and ifstats.netfilter then
local st = ifstats.netfilter
print("<tr><th nowrap>"..i18n("if_stats_overview.nf_queue_total").."</th>")
local span_class = ''
if st.nfq.queue_pct > 80 then
span_class = "class='badge badge-danger'"
end
print("<td width=20%><span id=nfq_queue_total "..span_class..">"..string.format("%s [%s %%]", formatValue(st.nfq.queue_total), formatValue(st.nfq.queue_pct)).." </span> <span id=nfq_queue_total_trend></span></td>")
print("<th nowrap>"..i18n("if_stats_overview.nf_handle_packet_failed").."</th>")
print("<td width=20%><span id=nfq_handling_failed>"..formatValue(st.failures.handle_packet).."</span> <span id=nfq_handling_failed_trend></span></td>")
print("<th nowrap>"..i18n("if_stats_overview.nf_enobufs").."</th>")
print("<td width=20%><span id=nfq_enobufs>"..formatValue(st.failures.no_buffers).."</span> <span id=nfq_enobufs_trend></span></td>")
print("</tr>")
print("<tr><th nowrap>") print(i18n("if_stats_overview.conntrack_flow_entries")) print("</th><td colspan=5>")
print("<span id=num_conntrack_entries>"..formatValue(st.nfq.num_conntrack_entries).."</span></td>")
print("</tr>")
end
print [[
<tr><td colspan=7> <small> <b>]] print(i18n("if_stats_overview.note").."</b>:<p>"..i18n("if_stats_overview.note_packets")) print[[</small> </td></tr>
]]
print("</table>\n")
print("</div>") -- close of table responsive
elseif page == "networks" and is_packet_interface then
print("<table class=\"table table-striped table-bordered\">")
if(ifstats.ip_addresses ~= "") then
local tokens = split(ifstats.ip_addresses, ",")
if(tokens ~= nil) then
print("<tr><th width=250>"..i18n("ip_address").."</th><td colspan=5><ul><li>")
local addresses = {}
for _,s in pairs(tokens) do
t = string.split(s, "/")
host = interface.getHostInfo(t[1])
if(host ~= nil) then
addresses[#addresses+1] = hostinfo2detailshref(host, nil, t[1]).."/"..t[2]
else
addresses[#addresses+1] = s
end
end
print(table.concat(addresses, "\n<li>"))
print("</ul></td></tr>")
end
else
print("<tr><th width=250>"..i18n("ip_address").."</th><td colspan=5>")
print(i18n("if_stats_networks.no_ip_addresses_read"))
print("</td></tr>")
end
local has_ghost_networks = false
local ghost_icon = '<font color=red><i class="fas fa-ghost" aria-hidden="true"></i></font>'
if ifstats.bcast_domains and table.len(ifstats.bcast_domains) > 0 then
print("<tr><th width=250>"..i18n("broadcast_domain").."</th><td colspan=5>")
local bcast_domains = {}
for bcast_domain, domain_info in pairsByKeys(ifstats.bcast_domains) do
bcast_domain = string.format("<a href='%s/lua/hosts_stats.lua?network_cidr=%s'>%s</a>", ntop.getHttpPrefix(), bcast_domain, bcast_domain)
if domain_info.ghost_network then
has_ghost_networks = true
bcast_domain = bcast_domain..' '..ghost_icon
end
bcast_domains[#bcast_domains + 1] = bcast_domain
end
if #bcast_domains > 0 then
print("<ul>")
for _, bcast_domain in ipairs(bcast_domains) do
print("<li>"..bcast_domain.."</li>")
end
print("</ul>")
end
print("</td></tr>")
else
print("<tr><th width=250>"..i18n("broadcast_domain").."</th><td colspan=5>")
print(i18n('if_stats_networks.no_broadcast_domains'))
print("</td></tr>")
end
print("</table>")
print(ui_utils.render_notes({
{content = i18n("if_stats_networks.note_iface_addresses")},
{content = i18n("if_stats_networks.note_iface_bcast_domains")},
{content = i18n("if_stats_networks.note_ghost_bcast_domains", {ghost_icon = ghost_icon}), hidden = not has_ghost_networks}
}))
elseif((page == "packets")) then
local nedge_hidden = ternary(have_nedge, 'class="hidden"', '')
print [[ <table class="table table-bordered table-striped"> ]]
print("<tr " .. nedge_hidden .. "><th width=30% rowspan=3>" .. i18n("packets_page.tcp_packets_analysis") .. "</th><th>" .. i18n("packets_page.retransmissions") .."</th><td align=right><span id=pkt_retransmissions>".. formatPackets(ifstats.tcpPacketStats.retransmissions) .."</span> <span id=pkt_retransmissions_trend></span></td></tr>\n")
print("<tr " .. nedge_hidden .. "></th><th>" .. i18n("packets_page.out_of_order") .. "</th><td align=right><span id=pkt_ooo>".. formatPackets(ifstats.tcpPacketStats.out_of_order) .."</span> <span id=pkt_ooo_trend></span></td></tr>\n")
print("<tr " .. nedge_hidden .. "></th><th>" .. i18n("packets_page.lost") .. "</th><td align=right><span id=pkt_lost>".. formatPackets(ifstats.tcpPacketStats.lost) .."</span> <span id=pkt_lost_trend></span></td></tr>\n")
if(ifstats.type ~= "zmq") then
print [[<tr ]] print(nedge_hidden) print[[><th class="text-left">]] print(i18n("packets_page.size_distribution")) print [[</th><td colspan=5><div class="pie-chart" id="sizeDistro"></div></td></tr>]]
end
print[[
<tr ]] print(nedge_hidden) print[[><th class="text-left">]] print(i18n("packets_page.version_vs_flags_distribution")) print[[</th>
<td colspan=1><div class="pie-chart" id="ipverDistro"></div></td><td colspan=1><div class="pie-chart" id="flagsDistro"></div></td></tr>
</table>
<script type='text/javascript'>
window.onload=function() {
do_pie("#sizeDistro", ']]
print (ntop.getHttpPrefix())
print [[/lua/if_pkt_distro.lua', { distr: "size", ifid: "]] print(ifstats.id.."\"")
print [[
}, "", refresh);
do_pie("#flagsDistro", ']]
print (ntop.getHttpPrefix())
print [[/lua/if_tcpflags_pkt_distro.lua', { ifid: "]] print(ifstats.id.."\"")
print [[
}, "", refresh);
do_pie("#ipverDistro", ']]
print (ntop.getHttpPrefix())
print [[/lua/if_pkt_distro.lua', { distr: "ipver", ifid: "]] print(ifstats.id.."\"")
print [[
}, "", refresh);
}
</script><p>
]]
elseif(page == "DSCP") then
print [[
<table id="dscp_table" class="table table-bordered table-striped tablesorter">
<tr>
<th class="text-left">]] print(i18n("dscp_page.statistics")) print [[</th>
<td colspan=4><div class="pie-chart" id="dscpGroups"></td>
</tr>
</table>
<script>
do_pie("#dscpGroups", ']] print (ntop.getHttpPrefix()) print [[/lua/rest/v1/get/interface/dscp/stats.lua', { ifid: "]] print(ifid) print [[" }, "", refresh);
</script>
]]
elseif(page == "ndpi") then
print[[
<div class='card'>
<div class='card-header'>
<ul id="ndpiNav" class="nav nav-tabs card-header-tabs" role="tablist">
<li class="nav-item active"><a class="nav-link active" data-toggle="tab" role="tab" href="#applications" active>]] print(i18n("applications")) print[[</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab" role="tab" href="#categories">]] print(i18n("categories")) print[[</a></li>
</ul>
</div>
<div class='card-body tab-content'>
<div id="applications" class="tab-pane in active">
<table class="table table-bordered table-striped">
]]
if ntop.isPro() and ifstats["custom_apps"] then
print[[
<tr>
<th class="text-left">]] print(i18n("ndpi_page.overview", {what = i18n("ndpi_page.custom_applications")})) print [[</th>
<td colspan=5><div class="pie-chart" id="topCustomApps"></td>
</tr>
]]
end
print[[
<tr>
<th class="text-left">]] print(i18n("ndpi_page.overview", {what = i18n("applications")})) print [[</th>
<td colspan=3><div class="pie-chart" id="topApplicationProtocols"></td>
<td colspan=2><div class="pie-chart" id="topApplicationBreeds"></td>
</tr>
<tr>
<th class="text-left">]] print(i18n("ndpi_page.live_flows_count")) print [[</th>
<td colspan=3><div class="pie-chart" id="topFlowsCount"></td>
<td colspan=2><div class="pie-chart" id="topTCPFlowsStats">
<br><small><b>]] print(i18n("ndpi_page.note")) print [[ :</b>]] print(i18n("ndpi_page.note_live_flows_chart")) print [[
</td>
</tr>
</table>
<table id="if_stats_ndpi" class="table table-bordered table-striped tablesorter">
<thead>
<tr>
<th>]] print(i18n("application")) print[[</th>
<th>]] print(i18n("ndpi_page.total_since_startup")) print[[</th>
<th>]] print(i18n("percentage")) print[[</th>
</tr>
</thead>
<tbody id="if_stats_ndpi_tbody"></tbody>
</table>
</div>
<div id="categories" class="tab-pane">
<table class="table table-bordered table-striped">
<tr>
<th class="text-left">]] print(i18n("ndpi_page.overview", {what = i18n("categories")})) print [[</th>
<td colspan=5><div class="pie-chart" id="topApplicationCategories"></td>
</tr>
</table>
<table id="if_stats_ndpi_categories" class="table table-bordered table-striped tablesorter">
<thead>
<tr>
<th>]] print(i18n("category")) print[[</th>
<th>]] print(i18n("applications")) print[[</th>
<th>]] print(i18n("ndpi_page.total_since_startup")) print[[</th>
<th>]] print(i18n("percentage")) print[[</th>
</tr>
</thead>
<tbody id="if_stats_ndpi_categories_tbody"></tbody>
</table>
</div>
</div>
</div>
]]
print [[
<script type="text/javascript" src="]] print(ntop.getHttpPrefix()) print [[/js/jquery.tablesorter.js?]] print(ntop.getStaticFileEpoch()) print[["></script>
<script type='text/javascript'>
window.onload=function() {]]
if ntop.isPro() and ifstats["custom_apps"] then
print[[do_pie("#topCustomApps", ']]
print (ntop.getHttpPrefix())
print [[/lua/pro/get_custom_app_stats.lua', { ifid: "]] print(ifid) print [[" }, "", refresh);
]]
end
print[[do_pie("#topApplicationProtocols", ']]
print (ntop.getHttpPrefix())
print [[/lua/rest/v1/get/interface/l7/stats.lua', { ndpistats_mode: "sinceStartup", ifid: "]] print(ifid) print [[" }, "", refresh);
do_pie("#topApplicationBreeds", ']]
print (ntop.getHttpPrefix())
print [[/lua/rest/v1/get/interface/l7/stats.lua', { breed: "true", ndpistats_mode: "sinceStartup", ifid: "]] print(ifid) print [[" }, "", refresh);
do_pie("#topApplicationCategories", ']]
print (ntop.getHttpPrefix())
print [[/lua/rest/v1/get/interface/l7/stats.lua', { ndpi_category: "true", ndpistats_mode: "sinceStartup", ifid: "]] print(ifid) print [[" }, "", refresh);
do_pie("#topFlowsCount", ']]
print (ntop.getHttpPrefix())
print [[/lua/rest/v1/get/interface/l7/stats.lua', { breed: "true", ndpistats_mode: "count", ifid: "]] print(ifid) print [[" }, "", refresh);
do_pie("#topTCPFlowsStats", ']]
print (ntop.getHttpPrefix())
print [[/lua/iface_tcp_stats.lua', { ifid: "]] print(ifid) print [[" }, "", refresh);
}
function update_ndpi_table() {
$.ajax({
type: 'GET',
url: ']]
print (ntop.getHttpPrefix())
print [[/lua/if_stats_ndpi.lua',
data: { ifid: "]] print(ifid) print [[" },
success: function(content) {
if(content) {
$('#if_stats_ndpi_tbody').html(content);
// Let the TableSorter plugin know that we updated the table
$('#if_stats_ndpi_tbody').trigger("update");
}
}
});
}
update_ndpi_table();
setInterval(update_ndpi_table, 5000);
function update_ndpi_categories_table() {
$.ajax({
type: 'GET',
url: ']]
print (ntop.getHttpPrefix())
print [[/lua/if_stats_ndpi_categories.lua',
data: { ifid: "]] print(ifid) print [[" },
success: function(content) {
if(content) {
$('#if_stats_ndpi_categories_tbody').html(content);
// Let the TableSorter plugin know that we updated the table
$('#if_stats_ndpi_categories_tbody').trigger("update");
}
}
});
}
update_ndpi_categories_table();
setInterval(update_ndpi_categories_table, 5000);
</script>
]]
elseif(page == "ICMP") then
print[[
<div class='card'>
<div class='card-header'>
<ul id="icmp_nav" class="nav nav-tabs card-header-tabs" role="tablist">
<li class="nav-item active"><a class="nav-link active" data-toggle="tab" role="tab" href="#icmp" active>]] print(i18n("icmpv4")) print[[</a></li>
<li class="nav-item"><a class="nav-link" data-toggle="tab" role="tab" href="#icmpv6">]] print(i18n("icmpv6")) print[[</a></li>
</ul>
</div>
<div class="card-body tab-content">
<div id="icmp" class="tab-pane in active">
<table id="icmp_table_4" class="table table-bordered table-striped tablesorter">
<thead><tr><th>]] print(i18n("icmp_page.icmp_message")) print [[</th><th>]] print(i18n("icmp_page.icmp_type")) print [[</th><th>]] print(i18n("icmp_page.icmp_code")) print [[</th><th style='text-align:right;'>]] print(i18n("packets")) print[[</th></tr></thead>
<tbody id="iface_details_icmp_tbody_4">
</tbody>
</table>
</div>
<div id="icmpv6" class="tab-pane">
<table id="icmp_table_6" class="table table-bordered table-striped tablesorter">
<thead><tr><th>]] print(i18n("icmp_page.icmp_message")) print [[</th><th>]] print(i18n("icmp_page.icmp_type")) print [[</th><th>]] print(i18n("icmp_page.icmp_code")) print [[</th><th style='text-align:right;'>]] print(i18n("packets")) print[[</th></tr></thead>
<tbody id="iface_details_icmp_tbody_6">
</tbody>
</table>
</div>
</div>
</div>
<script>
function update_icmp_table(ip_version) {
var icmp_table_id = '#icmp_table_' + ip_version;
var icmp_table_body_id = '#iface_details_icmp_tbody_' + ip_version;
$.ajax({
type: 'GET',
url: ']]
print(ntop.getHttpPrefix())
print [[/lua/get_icmp_data.lua',
data: { ifid: "]] print(interface.getId().."") print [[", version: ip_version },
success: function(content) {
if(content) {
$(icmp_table_body_id).html(content);
$(icmp_table_id).trigger("update");
}
}
});
}
function update_icmp_tables() {
update_icmp_table(4);
update_icmp_table(6);
}
update_icmp_tables();
setInterval(update_icmp_tables, 5000);
</script>
]]
elseif(page == "ARP") then
local endpoint = string.format(ntop.getHttpPrefix() .. "/lua/rest/v1/get/interface/arp.lua?ifid=%s", ifId)
local context = {
json = json,
template = template,
sites = {
endpoint = endpoint,
}
}
print(template.gen("pages/arp.template", context))
elseif(page == "sites") then
if not prefs.are_top_talkers_enabled then
local msg = i18n("sites_page.top_sites_not_enabled_message",{url=ntop.getHttpPrefix().."/lua/admin/prefs.lua?tab=protocols"})
print("<div class='alert alert-info'><i class='fas fa-info-circle fa-lg' aria-hidden='true'></i> "..msg.."</div>")
elseif table.len(sites_granularities) > 0 then
local endpoint = string.format(ntop.getHttpPrefix() .. "/lua/pro/rest/v1/get/interface/top/sites.lua?ifid=%s", ifid)
local context = {
json = json,
template = template,
sites = {
endpoint = endpoint,
ifid = ifid,
granularities = sites_granularities,
default_granularity = "current"
}
}
print(template.gen("pages/top_sites.template", context))
else
local msg = i18n("sites_page.top_sites_not_seen")
print("<div class='alert alert-info'><i class='fas fa-info-circle fa-lg' aria-hidden='true'></i> "..msg.."</div>")
end
elseif(page == "historical") then
local schema = _GET["ts_schema"]
local selected_epoch = _GET["epoch"] or ""
local tags = {
ifid = ifid,
protocol = _GET["protocol"],
category = _GET["category"],
l4proto = _GET["l4proto"],
dscp_class = _GET["dscp_class"],
}
url = url.."&page=historical"
if(schema == nil) then
if(ifstats.has_traffic_directions) then
schema = "iface:traffic_rxtx"
else
schema = "iface:traffic"
end
end
local top_enabled = top_talkers_utils.areTopEnabled(ifid)
graph_utils.drawGraphs(ifstats.id, schema, tags, _GET["zoom"], url, selected_epoch, {
top_protocols = "top:iface:ndpi",
top_categories = "top:iface:ndpi_categories",
top_profiles = "top:profile:traffic",
top_senders = ternary(top_enabled, "top:local_senders", nil),
top_receivers = ternary(top_enabled, "top:local_receivers", nil),
l4_protocols = "iface:l4protos",
dscp_classes = "iface:dscp",
show_historical = not ifstats.isViewed,
timeseries = graph_utils.get_default_timeseries()
})
elseif(page == "trafficprofiles") then
print("<table class=\"table table-striped table-bordered\">\n")
print("<tr><th width=15%><a href=\""..ntop.getHttpPrefix().."/lua/pro/admin/edit_profiles.lua\">" .. i18n("traffic_profiles.profile_name") .. "</A></th><th width=5%>" .. i18n("chart") .. "</th><th>" .. i18n("traffic") .. "</th></tr>\n")
for pname,pbytes in pairs(ifstats.profiles) do
local trimmed = trimSpace(pname)
local statschart_icon = ''
if areInterfaceTimeseriesEnabled(ifid) then
statschart_icon = '<A HREF=\"'..ntop.getHttpPrefix()..'/lua/profile_details.lua?profile='..pname..'\"><i class=\'fas fa-chart-area fa-lg\'></i></A>'
end
print("<tr><th>"..pname.."</th><td align=center>"..statschart_icon.."</td><td><span id=profile_"..trimmed..">"..bytesToSize(pbytes).."</span> <span id=profile_"..trimmed.."_trend></span></td></tr>\n")
end
print [[
</table>
<script>
let last_profile = [];
const traffic_profiles_interval = window.setInterval(function() {
$.ajax({
type: 'GET',
url: ']]
print (ntop.getHttpPrefix())
print [[/lua/rest/v1/get/interface/data.lua',
data: { iffilter: "]] print(tostring(interface.name2id(if_name))) print [[" },
success: function(content) {
if(content["rc_str"] == "OK" && content["rsp"] && content["rsp"]["profiles"] != null) {
const profiles = content["rsp"];
for (key in profiles["profiles"]) {
let k = '#profile_'+key.replace(" ", "");
const v = profiles["profiles"][key];
$(k).html(NtopUtils.bytesToVolume(v));
k += "_trend";
let last = last_profile[key];
if(last == null) { last = 0; }
$(k).html(NtopUtils.get_trend(last, v));
}
last_profile = profiles["profiles"];
}
}
});
}, ]] print(getInterfaceRefreshRate(ifstats.id).."") print[[ * 1000);
</script>
]]
elseif(page == "traffic_recording" and has_traffic_recording_page) then
if not dismiss_recording_providers_reminder then
print('<div id="traffic-recording-providers-detected" class="alert alert-info alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-label="close">&times;</button>'..i18n('traffic_recording.msg_external_providers_detected', {url = ntop.getHttpPrefix().."/lua/if_stats.lua?page=config"})..'</div>')
print [[
<script>
$('#traffic-recording-providers-detected').on('close.bs.alert', function () {
var dismiss_notice = $.ajax({
type: 'POST',
url: ']]
print (ntop.getHttpPrefix())
print [[/lua/traffic_recording_config.lua',
data: { ifid: ]] print(tostring(ifstats.id)) print[[,
dismiss_external_providers_reminder: true,
csrf: "]] print(ntop.getRandomCSRFValue()) print[["},
success: function() {},
complete: function() {},
});
});
</script>
]]
end
local tab = _GET["tab"] or "config"
local recording_enabled = recording_utils.isEnabled(ifstats.id)
-- config tab is only shown when the recording service is managed by ntopng
-- otherwise it is assumed that the user is managing the service manually with n2disk
local config_enabled = (recording_utils.getCurrentTrafficRecordingProvider(ifstats.id) == "ntopng")
if tab == "config" and not config_enabled then
if recording_enabled then tab = "status" else tab = "" end
end
if (tab == "status" or tab == "jobs") and not recording_enabled then
if config_enabled then tab = "config" else tab = "" end
end
if(_SERVER["REQUEST_METHOD"] == "POST") and (tab == "config") then
recording_enabled = not isEmptyString(_POST["record_traffic"])
end
print('<ul id="traffic-recording-nav" class="nav nav-tabs" role="tablist">')
if config_enabled then
print('<li class="nav-item '.. ternary(tab == "config", "active", "") ..'"><a class="nav-link '.. ternary(tab == "config", "active", "") ..'" href="?ifid='.. ifstats.id
..'&page=traffic_recording"><i class="fas fa-cog"></i> '.. i18n("traffic_recording.settings") ..'</a></li>')
end
if recording_enabled then
print('<li class="nav-item '.. ternary(tab == "status", "active", "") ..'"><a class="nav-link '.. ternary(tab == "status", "active", "") ..'" href="?ifid='.. ifstats.id
..'&page=traffic_recording&tab=status">'.. i18n("status") ..'</a></li>')
if ntop.isEnterpriseM() then
print('<li class="nav-item '.. ternary(tab == "jobs", "active", "") ..'"><a class="nav-link '.. ternary(tab == "jobs", "active", "") ..'" href="?ifid='.. ifstats.id
..'&page=traffic_recording&tab=jobs">'.. i18n("traffic_recording.jobs") ..'</a></li>')
end
end
print('</ul>')
print('<div class="tab-content">')
if recording_enabled and tab == "status" then
dofile(dirs.installdir .. "/scripts/lua/inc/traffic_recording_status.lua")
elseif recording_enabled and ntop.isEnterpriseM() and tab == "jobs" then
dofile(dirs.installdir .. "/scripts/lua/inc/traffic_recording_jobs.lua")
elseif config_enabled and tab == "config" then -- config, default
dofile(dirs.installdir .. "/scripts/lua/inc/traffic_recording_config.lua")
end
print('</div></div>')
elseif(page == "alerts") then
alert_utils.printAlertTables("interface", ifid,
"if_stats.lua", {ifid=ifid}, if_name,
{enable_label = i18n("show_alerts.trigger_iface_alert_descr", {iface = short_name})})
elseif(page == "config") then
if(not isAdministrator()) then
return
end
local interface_pools_instance = interface_pools:create()
local messages = {}
-- Flow dump check
local interface_flow_dump = true
if prefs.is_dump_flows_enabled then
interface_flow_dump = (ntop.getPref("ntopng.prefs.ifid_"..interface.getId()..".is_flow_dump_disabled") ~= "1")
if _SERVER["REQUEST_METHOD"] == "POST" then
local new_value = (_POST["interface_flow_dump"] == "1")
if new_value ~= interface_flow_dump then
-- Value changed
interface_flow_dump = new_value
ntop.setPref("ntopng.prefs.ifid_"..interface.getId()..".is_flow_dump_disabled", ternary(interface_flow_dump, "0", "1"))
messages[#messages + 1] = {
type = "warning",
text = i18n("prefs.restart_needed", {product=info.product}),
}
end
end
end
if _SERVER["REQUEST_METHOD"] == "POST" then
-- bind interface to pool
if (_POST["pool"]) then
interface_pools_instance:bind_member(ifid, tonumber(_POST["pool"]))
end
end
if not table.empty(messages) then
printMessageBanners(messages)
print("<br>")
end
print[[
<form id="iface_config" lass="form-inline" method="post">
<input name="csrf" type="hidden" value="]] print(ntop.getRandomCSRFValue()) print[[" />
<table id="iface_config_table" class="table table-bordered table-striped">]]
if ((not is_pcap_dump) and
(ifstats.name ~= nil) and
(ifstats.name ~= "dummy")) then
-- Custom name
print[[
<tr>
<th>]] print(i18n("if_stats_config.custom_name")) print[[</th>
<td>]]
local label = getHumanReadableInterfaceName(ifstats.name)
inline_input_form("custom_name", "Custom Name",
i18n("if_stats_config.custom_name_popup_msg"),
label, isAdministrator(), 'autocorrect="off" spellcheck="false"')
print[[
</td>
</tr>]]
-- Interface Pool
print([[
<tr>
<th>]].. i18n("pools.pool") ..[[</th>
<td>
]].. ui_utils.render_pools_dropdown(interface_pools_instance, ifid, "interface") ..[[
</td>
</tr>
]])
-- Interface speed
if not have_nedge then
print[[
<tr>
<th>]] print(i18n("if_stats_config.interface_speed")) print[[</th>
<td>]]
local ifspeed = getInterfaceSpeed(ifstats.id)
inline_input_form("ifSpeed", "Interface Speed",
i18n("if_stats_config.interface_speed_popup_msg"),
ifspeed, isAdministrator(), 'type="number" min="1"', "d-inline-block", "if_stats_config.interface_speed_measure_unit")
print[[
</td>
</tr>]]
end
-- Interface refresh rate
print[[
<tr>
<th>]] print(i18n("if_stats_config.refresh_rate")) print[[</th>
<td>]]
local refreshrate = getInterfaceRefreshRate(ifstats.id)
inline_input_form("ifRate", "Refresh Rate",
i18n("if_stats_config.refresh_rate_popup_msg"),
refreshrate, isAdministrator(), 'type="number" min="1"', "d-inline-block", "if_stats_config.referesh_rate_measure_unit")
print[[
</td>
</tr>]]
end
if not have_nedge then
-- Scaling factor
if is_packet_interface and not have_nedge then
local label = ntop.getCache("ntopng.prefs.iface_"..tostring(ifid)..".scaling_factor")
if((label == nil) or (label == "")) then label = "1" end
print[[
<tr>
<th>]] print(i18n("if_stats_config.scaling_factor")) print[[</th>
<td>]]
inline_input_form("scaling_factor", "Scaling Factor",
i18n("if_stats_config.scaling_factor_popup_msg"),
label, isAdministrator(), 'type="number" min="1" step="1"')
print[[
</td>
</tr>]]
end
end
local serialize_by_mac
local serialize_by_mac_key = string.format("ntopng.prefs.ifid_%u.serialize_local_broadcast_hosts_as_macs", interface.getId())
if(_POST["lbd_hosts_as_macs"] ~= nil) then
serialize_by_mac = _POST["lbd_hosts_as_macs"]
if ntop.getPref(serialize_by_mac_key) ~= serialize_by_mac then
ntop.setPref(serialize_by_mac_key, serialize_by_mac)
interface.updateLbdIdentifier()
end
else
serialize_by_mac = ntop.getPref(serialize_by_mac_key)
end
-- LBD identifier
print[[
<tr>
<th width="30%">]] print(i18n("prefs.toggle_host_tskey_title")) print[[ <i class="fas fa-question-circle " title="]] print(i18n("prefs.toggle_host_tskey_description")) print[["></i></th>
<td>]]
inline_select_form("lbd_hosts_as_macs", {i18n("ip_address"), i18n("mac_address")}, {"0", "1"}, serialize_by_mac)
print[[
</td>
</tr>]]
-- Hidden from top
local rv = ntop.getMembersCache(getHideFromTopSet(ifstats.id)) or {}
local members = {}
-- impose sort order
for _, net in pairsByValues(rv, asc) do
members[#members + 1] = net
end
local hide_top = table.concat(members, ",")
print[[
<tr>
<th>]] print(i18n("if_stats_config.hide_from_top_networks")) print[[</th>
<td>]]
print('<input style="width:36em;" class="form-control" name="hide_from_top" placeholder="'..i18n("if_stats_config.hide_from_top_networks_descr", {example="192.168.1.1,192.168.100.0/24"})..'" value="' .. hide_top .. '">')
print[[
</td>
</tr>]]
-- per-interface Top-Talkers generation
local interface_top_talkers_creation = true
if _SERVER["REQUEST_METHOD"] == "POST" then
if _POST["interface_top_talkers_creation"] ~= "1" then
interface_top_talkers_creation = false
top_talkers_utils.disableTop(interface.getId())
else
top_talkers_utils.enableTop(interface.getId())
end
else
if not top_talkers_utils.areTopEnabled(interface.getId()) then
interface_top_talkers_creation = false
end
end
print [[<tr>
<th>]] print(i18n("if_stats_config.interface_top_talkers_creation")) print[[</th>
<td>]]
print(template.gen("on_off_switch.html", {
id = "interface_top_talkers_creation",
checked = interface_top_talkers_creation,
}))
print[[
</td>
</tr>]]
-- Flow dump
if prefs.is_dump_flows_enabled then
print [[<tr>
<th>]] print(i18n("if_stats_config.dump_flows_to_database")) print[[</th>
<td>]]
print(template.gen("on_off_switch.html", {
id = "interface_flow_dump",
checked = interface_flow_dump,
}))
print[[
</td>
</tr>]]
end
-- Mirrored Traffic
if not ntop.isnEdge() and is_packet_interface then
print [[<tr>
<th>]] print(i18n("if_stats_config.is_mirrored_traffic")) print[[</th>
<td>]]
print(template.gen("on_off_switch.html", {
id = "is_mirrored_traffic",
checked = is_mirrored_traffic,
}))
print[[
<script type="text/javascript">
$("#is_mirrored_traffic").change(function(e) {
const value = $(this).is(":checked");
if (value) {
toggle_mirrored_traffic_function_on();
} else {
toggle_mirrored_traffic_function_off();
}
});
function toggle_mirrored_traffic_function_on(){
$(`#is_mirrored_traffic`).val("1");
$("#gw_macs_tr").css("display","table-row");
}
function toggle_mirrored_traffic_function_off(){
$(`#is_mirrored_traffic`).val("0");
$("#gw_macs_tr").css("display","none");
}
</script>
</td>
</tr>]]
-- Gw Macs for Address-Based Traffic Directions
local rv = ntop.getMembersCache(getGwMacsSet(ifstats.id)) or {}
local members = {}
-- impose sort order
for _, addr in pairsByValues(rv, asc) do
members[#members + 1] = addr
end
local gw_macs = table.concat(members, ",")
print([[
<tr id="gw_macs_tr" style="display: ]] .. ternary(is_mirrored_traffic, "table-row", "none") .. [[;">
<th>]] .. i18n("if_stats_config.gw_macs") .. [[</th>
<td>]])
print('<input style="width:36em;" class="form-control" name="gw_macs" placeholder="'..i18n("if_stats_config.gw_macs_example", {example="00:11:22:33:44:55,00:11:22:33:44:66"})..'" value="' .. gw_macs .. '">')
print([[
<small>
<details class='mt-2'>
<summary>
<span data-toggle="tooltip" data-placement="right" title=']].. i18n("click_to_expand") ..[['>
]]..i18n("notes")..[[ <i class='fas fa-question-circle '></i>
</span>
</summary>
<p>]]..i18n("if_stats_config.gw_macs_description")..[[</p>
</details>
</small>
</td>
</tr>]])
end
-- Flows-Only Interface
if not ntop.isnEdge() and not interface.isView() and not interface.isViewed() then
local flows_only_interface = false
local flows_only_interface_pref = string.format("ntopng.prefs.ifid_%d.flows_only_interface", interface.getId())
if _SERVER["REQUEST_METHOD"] == "POST" then
if _POST["flows_only_interface"] == "1" then
flows_only_interface = true
end
ntop.setPref(flows_only_interface_pref,
ternary(flows_only_interface == true, '1', '0'))
interface.updateDiscardProbingTraffic()
else
flows_only_interface = ternary(ntop.getPref(flows_only_interface_pref) == '1', true, false)
end
print [[<tr>
<th>]] print(i18n("if_stats_config.flows_only_interface")) print[[</th>
<td>]]
print(template.gen("on_off_switch.html", {
id = "flows_only_interface",
checked = flows_only_interface,
}))
print[[
</td>
</tr>]]
end
-- Discard Probing Traffic
if not ntop.isnEdge() and not is_packet_interface then
local discard_probing_traffic = false
local discard_probing_traffic_pref = string.format("ntopng.prefs.ifid_%d.discard_probing_traffic", interface.getId())
if _SERVER["REQUEST_METHOD"] == "POST" then
if _POST["discard_probing_traffic"] == "1" then
discard_probing_traffic = true
end
ntop.setPref(discard_probing_traffic_pref,
ternary(discard_probing_traffic == true, '1', '0'))
interface.updateDiscardProbingTraffic()
else
discard_probing_traffic = ternary(ntop.getPref(discard_probing_traffic_pref) == '1', true, false)
end
print [[<tr>
<th>]] print(i18n("if_stats_config.discard_probing_traffic")) print[[</th>
<td>]]
print(template.gen("on_off_switch.html", {
id = "discard_probing_traffic",
checked = discard_probing_traffic,
}))
print[[
</td>
</tr>]]
end
-- per-interface Network Discovery
if interface.isDiscoverableInterface() then
local discover = require "discover_utils"
local interface_network_discovery = true
if _SERVER["REQUEST_METHOD"] == "POST" then
if _POST["interface_network_discovery"] ~= "1" then
interface_network_discovery = false
end
ntop.setPref(discover.getInterfaceNetworkDiscoveryEnabledKey(interface.getId()), tostring(interface_network_discovery))
else
interface_network_discovery = ntop.getPref(discover.getInterfaceNetworkDiscoveryEnabledKey(interface.getId()))
if interface_network_discovery == "false" then
interface_network_discovery = false
end
end
print [[<tr>
<th>]] print(i18n("if_stats_config.interface_network_discovery")) print[[</th>
<td>]]
print(template.gen("on_off_switch.html", {
id = "interface_network_discovery",
checked = interface_network_discovery,
}))
print[[
</td>
</tr>]]
end
if not ifstats.isDynamic then
local cur_companion = companion_interface_utils.getCurrentCompanion(ifstats.id)
local companions = companion_interface_utils.getAvailableCompanions()
if table.len(companions) > 1 then
print [[
<tr>
<th>]] print(i18n("if_stats_config.companion_interface")) print[[</th>
<td>
<select name="companion_interface" class="form-control" style="width:36em; display:inline;">]]
for _, companion in ipairs(companions) do
local companion_id = companion["ifid"]
local companion_name = companion["ifname"]
local label = companion_name
if companion_name ~= "None" then
label = getHumanReadableInterfaceName(companion_name)
end
print[[<option value="]] print(companion_id) print[[" ]] if cur_companion == companion_id then print('selected="selected"') end print[[">]] print(label) print[[</option>]]
end
print[[
</select>
</td>
</tr>]]
end
end
if has_traffic_recording_page then
local cur_provider = recording_utils.getCurrentTrafficRecordingProvider(ifstats.id)
local providers = recording_utils.getAvailableTrafficRecordingProviders()
-- only 1 provider means there's only the default ntopng
-- so no need to show this extra menu entry
if table.len(providers) > 1 then
print [[
<tr>
<th>]] print(i18n("traffic_recording.traffic_recording_provider")) print[[</th>
<td>
<select name="traffic_recording_provider" class="form-control" style="width:36em; display:inline;">]]
for _, provider in pairs(providers) do
local label = string.format("%s", provider["name"])
if provider["conf"] then
label = string.format("%s (%s)", provider["name"], provider["conf"])
end
if provider["name"] == "ntopng" and not is_packet_interface then
-- non-packet interfaces
label = "None"
end
print[[<option value="]] print(provider["name"]) print[[" ]] if cur_provider == provider["name"] then print('selected="selected"') end print[[">]] print(label) print[[</option>]]
end
print[[
</select>
</td>
</tr>]]
end
end
if not ifstats.isDynamic and not have_nedge then
local cur_mode = ntop.getCache(disaggregation_criterion_key)
if isEmptyString(cur_mode) then
cur_mode = "none"
end
local labels = {
i18n("prefs.none"),
i18n("prefs.vlan"),
i18n("prefs.probe_ip_address"),
i18n("prefs.ingress_egress_flow_interface"),
i18n("prefs.ingress_flow_interface"),
i18n("prefs.ingress_vrf_id"),
i18n("prefs.probe_ip_and_ingress_iface_idx")
}
local values = {}
if is_packet_interface then
values = {
"none",
"vlan"
}
else
values = {
"none",
"vlan",
"probe_ip",
"iface_idx",
"ingress_iface_idx",
"ingress_vrf_id",
"probe_ip_and_ingress_iface_idx",
}
end
print [[
<tr>
<th>]] print(i18n("prefs.dynamic_interfaces_creation_title")) print[[</th>
<td>
<select name="disaggregation_criterion" class="form-control" style="width:36em; display:inline;">]]
for k, value in ipairs(values) do
local label = labels[k]
print[[<option value="]] print(value) print[[" ]] if cur_mode == value then print('selected="selected"') end print[[">]] print(label) print[[</option>]]
end
print[[
</select>
]]
print([[
<small>
<details class='mt-2'>
<summary>
<span data-toggle="tooltip" data-placement="right" title=']].. i18n("click_to_expand") ..[['>
]]..i18n("notes")..[[ <i class='fas fa-question-circle '></i>
</span>
</summary>
<p>]]..i18n("prefs.dynamic_interfaces_creation_description")..[[</p>
<p>]]..i18n("prefs.dynamic_interfaces_creation_note_0")..[[</p>
<p>]]..i18n("prefs.dynamic_interfaces_creation_note_4")..[[</p>
<p>]]..i18n("prefs.dynamic_interfaces_creation_note_1")..[[</p>
<p>]]..(not is_packet_interface and i18n("prefs.dynamic_interfaces_creation_note_2") or '') ..[[</p>
<p>]]..(not is_packet_interface and i18n("prefs.dynamic_interfaces_creation_note_3") or '') ..[[</p>
</details>
</small>
]])
print[[
</td>
</tr>]]
-- Show dynamic traffic in the master interface
local show_dyn_iface_traffic = false
local show_dyn_iface_traffic_pref = string.format("ntopng.prefs.ifid_%d.show_dynamic_interface_traffic", interface.getId())
if _SERVER["REQUEST_METHOD"] == "POST" then
if _POST["show_dyn_iface_traffic"] == "1" then
show_dyn_iface_traffic = true
end
ntop.setPref(show_dyn_iface_traffic_pref,
ternary(show_dyn_iface_traffic == true, '1', '0'))
interface.updateDynIfaceTrafficPolicy()
else
show_dyn_iface_traffic = ternary(ntop.getPref(show_dyn_iface_traffic_pref) == '1', true, false)
end
print [[<tr>
<th>
]] print(i18n("if_stats_config.show_dyn_iface_traffic")) print[[
<i class='fas fa-question-circle ' data-toggle="tooltip" data-placement="top" title=']] print(i18n("if_stats_config.show_dyn_iface_traffic_note")) print[['></i>
</th>
<td>]]
print(template.gen("on_off_switch.html", {
id = "show_dyn_iface_traffic",
checked = show_dyn_iface_traffic,
}))
print[[
</td>
</tr>]]
end
print[[
</table>
<button class="btn btn-primary" style="float:right; margin-right:1em; margin-left: auto" disabled="disabled" type="submit">]] print(i18n("save_settings")) print[[</button><br><br>
</form>
<script>
aysHandleForm("#iface_config");
</script>]]
elseif(page == "internals") then
internals_utils.printInternals(ifid, true --[[ hash tables ]], true --[[ periodic activities ]], true --[[ user scripts]], true --[[ queues --]])
print [[
</table>
]]
elseif(page == "snmp_bind") then
if ((not hasSnmpDevices(ifstats.id)) or (not is_packet_interface)) then
return
end
local snmp_host = _POST["ip"]
local snmp_interface = _POST["snmp_port_idx"] or ""
if (snmp_host ~= nil) then
-- snmp_host can be empty
snmp_utils.set_snmp_bound_interface(ifstats.id, snmp_host, snmp_interface)
else
local value = snmp_utils.get_snmp_bound_interface(ifstats.id)
if value ~= nil then
snmp_host = value.snmp_device
snmp_interface = value.snmp_port
end
end
local snmp_devices = snmp_utils.get_snmp_devices(ifstats.id)
print[[
<form id="snmp_bind_form" method="post" style="margin-bottom:3em;">
<table class="table table-bordered table-striped">]]
print[[
<tr>
<th>]] print(i18n("snmp.snmp_device")) print[[</th>
<td>
<select class="form-control" style="width:30em; display:inline;" id="snmp_bind_device" name="ip">
<option]] if isEmptyString(snmp_host) then print(" selected") end print[[ value="">Not Bound</option>
]]
for _, device in pairs(snmp_devices) do
print('<option value="'..device.ip..'"')
if (snmp_host == device.ip) then
print(' selected')
end
print('>'..device.name..' ('..device.ip..')</option>')
end
print[[
</select>
<a class="btn" id="snmp_device_link" style="padding:0.2em; margin-left:0.3em;" href="#"]]
if isEmptyString(snmp_host) then
print(" disabled")
end
print[[>]] print(i18n("snmp.view_device")) print[[</i></a>
</td>
</tr>
<tr>
<th>]] print(i18n("snmp.snmp_interface")) print[[</th>
<td>
<select class="form-control" style="width:30em; display:inline;" id="snmp_bind_interface" name="snmp_port_idx">]]
if not isEmptyString(snmp_interface) then
-- This is neeeded to initialized ays form fields
print('<option value="'..snmp_interface..'" selected></option>')
end
print[[
</select>
<img id="snmp_loading" style="margin-left:0.5em; visibility:hidden;" src="]] print(ntop.getHttpPrefix()) print[[/img/loading.gif"\>
</td>
</tr>
</table>
<input type="hidden" name="csrf" value="]] print(ntop.getRandomCSRFValue()) print[[" />
<button id="snmp_bind_submit" class="btn btn-primary" style="float:right; margin-right:1em; margin-left: auto" disabled="disabled" type="submit">]] print(i18n("save_settings")) print[[</button>
</form>
<b>]] print(i18n("snmp.note") .. ":") print[[</b><br>
<small>]] print(i18n("snmp.bound_interface_description")) print[[</small>
<script>
var snmp_bind_port_ajax = null;
var snmp_bind_first_init = true;
function snmp_set_loading_status(is_loading) {
if (is_loading) {
$("#snmp_loading").css("visibility", "");
$("#snmp_bind_submit").addClass("disabled");
} else {
$("#snmp_loading").css("visibility", "hidden");
$("#snmp_bind_submit").removeClass("disabled");
}
}
function snmp_check_snmp_list() {
var iflist = $("#snmp_bind_interface");
if ($("option", iflist).length > 0)
iflist.removeAttr("disabled");
else
iflist.attr("disabled", "disabled");
aysRecheckForm('#snmp_bind_form');
}
function snmp_recheck_selection() {
var iflist = $("#snmp_bind_interface");
var selected_device = $("#snmp_bind_device option:selected").val();
// Remove existing entries
$("option", iflist).remove();
if (snmp_bind_port_ajax != null) {
snmp_bind_port_ajax.abort();
snmp_bind_port_ajax = null;
}
snmp_check_snmp_list();
if (selected_device) {
snmp_set_loading_status(true);
$("#snmp_device_link").removeAttr("disabled");
$("#snmp_device_link").attr("href", "]] print(ntop.getHttpPrefix()) print[[/lua/pro/enterprise/snmp_device_details.lua?host=" + selected_device);
snmp_bind_port_ajax = $.ajax({
type: 'GET',
url: ']]
print (ntop.getHttpPrefix())
print [[/lua/pro/enterprise/get_snmp_device_details.lua',
data: { ifid: ]] print(ifstats.id) print[[, ip: selected_device, iftype_filter:'snmp_binding' },
success: function(rsp) {
if (rsp.interfaces) {
for (var ifidx in rsp.interfaces) {
var snmp_interface = rsp.interfaces[ifidx];
var selected = snmp_interface.bound ? " selected" : "";
iflist.append('<option value="' + ifidx + '"' + selected + '>' + snmp_interface.label + '</option>');
snmp_interface.label;
}
snmp_check_snmp_list();
}
}, complete: function() {
snmp_set_loading_status(false);
}
});
} else {
snmp_set_loading_status(false);
$("#snmp_device_link").attr("disabled", "disabled");
snmp_check_snmp_list();
}
}
aysHandleForm("#snmp_bind_form");
snmp_check_snmp_list();
$("#snmp_bind_device").change(snmp_recheck_selection);
$(function() {
// let it pass some time to ays initialization
snmp_recheck_selection();
});
</script>]]
elseif(page == "sub_interfaces") then
if(isAdministrator() and ntop.isEnterpriseM()) then
dofile(dirs.installdir .. "/pro/scripts/lua/enterprise/sub_interfaces.lua")
end
elseif(page == "syslog_producers") then
if(isAdministrator()) then
dofile(dirs.installdir .. "/scripts/lua/syslog_producers.lua")
end
elseif(page == "unassigned_pool_devices") then
dofile(dirs.installdir .. "/scripts/lua/unknown_devices.lua")
elseif(page == "dhcp") then
dofile(dirs.installdir .. "/scripts/lua/admin/dhcp.lua")
elseif page == "traffic_report" then
dofile(dirs.installdir .. "/pro/scripts/lua/enterprise/traffic_report.lua")
end
print("<script>\n")
print("var last_pkts = " .. ifstats.stats.packets .. ";\n")
print("var last_in_pkts = " .. ifstats.eth.ingress.packets .. ";\n")
print("var last_out_pkts = " .. ifstats.eth.egress.packets .. ";\n")
print("var last_drops = " .. ifstats.stats.drops .. ";\n")
print("var last_engaged_alerts = " .. ifstats.num_alerts_engaged .. ";\n")
print("var last_dropped_alerts = " .. ifstats.num_dropped_alerts .. ";\n")
print("var last_num_local_hosts_anomalies = " .. ifstats.anomalies.num_local_hosts_anomalies .. ";\n")
print("var last_num_remote_hosts_anomalies = " .. ifstats.anomalies.num_remote_hosts_anomalies .. ";\n")
if(ifstats.zmqRecvStats ~= nil) then
print("var last_zmq_time = 0;\n")
print("var last_zmq_remote_bps = ".. ifstats.remote_bps .. ";\n")
print("var last_zmq_remote_pps = ".. ifstats.remote_pps .. ";\n")
print("var last_zmq_flows = ".. ifstats.zmqRecvStats.flows .. ";\n")
print("var last_zmq_dropped_flows = ".. ifstats.zmqRecvStats.dropped_flows .. ";\n")
print("var last_zmq_events = ".. ifstats.zmqRecvStats.events .. ";\n")
print("var last_zmq_counters = ".. ifstats.zmqRecvStats.counters .. ";\n")
print("var last_zmq_msg_drops = ".. ifstats.zmqRecvStats.zmq_msg_drops .. ";\n")
print("var last_zmq_msg_rcvd = ".. ifstats.zmqRecvStats.zmq_msg_rcvd .. ";\n")
print("var last_zmq_drops_export_queue_full = "..(ifstats["zmq.drops.export_queue_full"] or 0).. ";\n")
print("var last_zmq_drops_flow_collection_drops = "..(ifstats["zmq.drops.flow_collection_drops"] or 0) .. ";\n")
print("var last_zmq_drops_flow_collection_udp_socket_drops = ".. (ifstats["zmq.drops.flow_collection_udp_socket_drops"] or 0) .. ";\n")
print("var last_zmq_avg_msg_flows = 1;\n")
print("var last_probe_zmq_exported_flows = ".. (ifstats["zmq.num_flow_exports"] or 0) .. ";\n")
end
if ifstats.stats.discarded_probing_packets then
print("var last_discarded_probing_pkts = " .. ifstats.stats.discarded_probing_packets .. ";\n")
end
print [[
function resetCounters(drops_only) {
var action = "reset_all";
if(drops_only) action = "reset_drops";
$.ajax({ type: 'post',
url: ']]
print (ntop.getHttpPrefix())
print [[/lua/reset_stats.lua',
data: {ifid: ]] print(ifstats.id) print [[, resetstats_mode: action, csrf: "]] print(ntop.getRandomCSRFValue()) print[["},
success: function(rsp) {},
complete: function() {
/* reload the page to generate a new CSRF */
window.location.href = window.location.href;
}
});
}
var resetInterfaceCounters = function(drops_only) {
if(drops_only)
$('#reset_drops_dialog').modal('show');
else
$('#reset_stats_dialog').modal('show');
}
setInterval(function() {
$.ajax({
type: 'GET',
url: ']]
print (ntop.getHttpPrefix())
print [[/lua/rest/v1/get/interface/data.lua',
data: { iffilter: "]] print(tostring(interface.name2id(ifstats.name))) print [[" },
success: function(content) {
if(content["rc_str"] != "OK") {
return;
}
const rsp = content["rsp"];
const v = NtopUtils.bytesToVolume(rsp.bytes);
$('#if_bytes').html(v);
$('#if_in_bytes').html(NtopUtils.bytesToVolume(rsp.bytes_download));
$('#if_out_bytes').html(NtopUtils.bytesToVolume(rsp.bytes_upload));
$('#if_in_pkts').html(NtopUtils.addCommas(rsp.packets_download) + " Pkts");
$('#if_out_pkts').html(NtopUtils.addCommas(rsp.packets_upload) + " Pkts");
$('#pkts_in_trend').html(NtopUtils.get_trend(rsp.bytes_download, last_in_pkts));
$('#pkts_out_trend').html(NtopUtils.get_trend(rsp.bytes_upload, last_out_pkts));
last_in_pkts = rsp.bytes_download;
last_out_pkts = rsp.bytes_upload;
if (typeof rsp.zmqRecvStats !== 'undefined') {
var diff, time_diff, flows_label;
var now = (new Date()).getTime();
if(last_zmq_time > 0) {
time_diff = now - last_zmq_time;
diff = rsp.zmqRecvStats.flows - last_zmq_flows;
if(diff > 0) {
rate = ((diff * 1000)/time_diff).toFixed(1);
flows_label = " [" + NtopUtils.fflows(rate) + "] " + NtopUtils.get_trend(1,0);
} else {
flows_label = " "+NtopUtils.get_trend(0,0);
}
} else {
flows_label = " "+NtopUtils.get_trend(0,0);
}
$('#if_zmq_remote_bps').html(NtopUtils.bitsToSize(rsp.remote_bps) + " " + NtopUtils.get_trend(rsp.remote_bps, last_zmq_remote_bps));
$('#if_zmq_remote_pps').html(NtopUtils.fpackets(rsp.remote_pps) + " " + NtopUtils.get_trend(rsp.remote_pps, last_zmq_remote_pps));
$('#if_zmq_flows').html(NtopUtils.addCommas(rsp.zmqRecvStats.flows)+flows_label);
$('#if_zmq_dropped_flows').html(NtopUtils.addCommas(rsp.zmqRecvStats.dropped_flows)+" "+NtopUtils.get_trend(rsp.zmqRecvStats.dropped_flows, last_zmq_dropped_flows));
$('#if_zmq_events').html(NtopUtils.addCommas(rsp.zmqRecvStats.events)+" "+NtopUtils.get_trend(rsp.zmqRecvStats.events, last_zmq_events));
$('#if_zmq_counters').html(NtopUtils.addCommas(rsp.zmqRecvStats.counters)+" "+NtopUtils.get_trend(rsp.zmqRecvStats.counters, last_zmq_counters));
$('#if_zmq_msg_drops').html(NtopUtils.addCommas(rsp.zmqRecvStats.zmq_msg_drops)+" "+NtopUtils.get_trend(rsp.zmqRecvStats.zmq_msg_drops, last_zmq_msg_drops));
$('#if_zmq_drops_export_queue_full').html(NtopUtils.addCommas(rsp["zmq.drops.export_queue_full"])+" "+NtopUtils.get_trend(rsp["zmq.drops.export_queue_full"], last_zmq_drops_export_queue_full));
$('#if_zmq_drops_flow_collection_drops').html(NtopUtils.addCommas(rsp["zmq.drops.flow_collection_drops"])+" "+NtopUtils.get_trend(rsp["zmq.drops.flow_collection_drops"], last_zmq_drops_flow_collection_drops));
$('#if_zmq_drops_flow_collection_udp_socket_drops').html(NtopUtils.addCommas(rsp["zmq.drops.flow_collection_udp_socket_drops"])+" "+NtopUtils.get_trend(rsp["zmq.drops.flow_collection_udp_socket_drops"], last_zmq_drops_flow_collection_udp_socket_drops));
$('#if_zmq_msg_rcvd').html(NtopUtils.addCommas(rsp.zmqRecvStats.zmq_msg_rcvd)+" "+NtopUtils.get_trend(rsp.zmqRecvStats.zmq_msg_rcvd, last_zmq_msg_rcvd));
$('#if_zmq_avg_msg_flows').html(NtopUtils.addCommas(NtopUtils.formatValue(rsp.zmqRecvStats.zmq_avg_msg_flows)));
$('#if_num_remote_zmq_flow_exports').html(NtopUtils.addCommas(rsp["zmq.num_flow_exports"])+" "+NtopUtils.get_trend(rsp["zmq.num_flow_exports"], last_probe_zmq_exported_flows));
last_remote_pps = rsp.remote_pps;
last_remote_bps = rsp.remote_bps;
last_zmq_flows = rsp.zmqRecvStats.flows;
last_zmq_dropped_flows = rsp.zmqRecvStats.dropped_flows;
last_zmq_events = rsp.zmqRecvStats.events;
last_zmq_counters = rsp.zmqRecvStats.counters;
last_zmq_msg_drops = rsp.zmqRecvStats.zmq_msg_drops;
last_zmq_drops_export_queue_full = rsp["zmq.drops.export_queue_full"];
last_zmq_drops_flow_collection_drops = rsp["zmq.drops.flow_collection_drops"];
last_zmq_drops_flow_collection_udp_socket_drops = rsp["zmq.drops.flow_collection_udp_socket_drops"];
last_zmq_msg_rcvd = rsp.zmqRecvStats.zmq_msg_rcvd;
last_zmq_avg_msg_flows = rsp.zmqRecvStats.zmq_avg_msg_flows;
last_probe_zmq_exported_flows = rsp["zmq.num_flow_exports"];
last_zmq_time = now;
}
$('#if_pkts').html(NtopUtils.addCommas(rsp.packets)+"]]
print(" Pkts\");")
if have_nedge and ifstats.type == "netfilter" and ifstats.netfilter then
local st = ifstats.netfilter
print("var last_nfq_queue_total = ".. st.nfq.queue_total .. ";\n")
print("var last_nfq_handling_failed = ".. st.failures.handle_packet .. ";\n")
print("var last_nfq_enobufs = ".. st.failures.no_buffers .. ";\n")
print[[
if(rsp.netfilter.nfq.queue_pct > 80) {
$('#nfq_queue_total').addClass("badge badge-danger");
} else {
$('#nfq_queue_total').removeClass("badge badge-danger");
}
$('#nfq_queue_total').html(NtopUtils.fint(rsp.netfilter.nfq.queue_total) + " [" + NtopUtils.fint(rsp.netfilter.nfq.queue_pct) + " %]");
$('#nfq_queue_total_trend').html(NtopUtils.get_trend(rsp.netfilter.nfq.queue_total, last_nfq_queue_total));
$('#nfq_handling_failed').html(NtopUtils.fint(rsp.netfilter.failures.handle_packet));
$('#nfq_handling_failed_trend').html(NtopUtils.get_trend(rsp.netfilter.failures.handle_packet, last_nfq_handling_failed));
$('#nfq_enobufs').html(NtopUtils.fint(rsp.netfilter.failures.no_buffers));
$('#nfq_enobufs_trend').html(NtopUtils.get_trend(rsp.netfilter.failures.no_buffers, last_nfq_enobufs));
$('#num_conntrack_entries').html(NtopUtils.fint(rsp.netfilter.nfq.num_conntrack_entries)+ " [" + NtopUtils.fint((rsp.netfilter.nfq.num_conntrack_entries*100)/rsp.num_flows) + " %]");
]]
end
if ifstats.stats.discarded_probing_packets then
print[[
$('#if_discarded_probing_bytes').html(NtopUtils.bytesToVolume(rsp.discarded_probing_bytes));
$('#if_discarded_probing_pkts').html(NtopUtils.formatPackets(rsp.discarded_probing_packets));
$('#if_discarded_probing_trend').html(NtopUtils.get_trend(rsp.discarded_probing_packets, last_discarded_probing_pkts));
last_discarded_probing_pkts = rsp.discarded_probing_packets;
]]
end
print [[
var pctg = 0;
var drops = "";
var last_pkt_retransmissions = ]] print(tostring(ifstats.tcpPacketStats.retransmissions)) print [[;
var last_pkt_ooo = ]] print(tostring(ifstats.tcpPacketStats.out_of_order)) print [[;
var last_pkt_lost = ]] print(tostring(ifstats.tcpPacketStats.lost)) print [[;
$('#pkt_retransmissions').html(NtopUtils.fint(rsp.tcpPacketStats.retransmissions)+" Pkts");
$('#pkt_retransmissions_trend').html(NtopUtils.get_trend(rsp.tcpPacketStats.retransmissions, last_pkt_retransmissions));
$('#pkt_ooo').html(NtopUtils.fint(rsp.tcpPacketStats.out_of_order)+" Pkts");
$('#pkt_ooo_trend').html(NtopUtils.get_trend(rsp.tcpPacketStats.out_of_order, last_pkt_ooo));
$('#pkt_lost').html(NtopUtils.fint(rsp.tcpPacketStats.lost)+" Pkts");
$('#pkt_lost_trend').html(NtopUtils.get_trend(rsp.tcpPacketStats.lost, last_pkt_lost));
last_pkt_retransmissions = rsp.tcpPacketStats.retransmissions;
last_pkt_ooo = rsp.tcpPacketStats.out_of_order;
last_pkt_lost = rsp.tcpPacketStats.lost;
$('#pkts_trend').html(NtopUtils.get_trend(rsp.packets, last_pkts));
$('#drops_trend').html(NtopUtils.get_trend(rsp.drops, last_drops));
last_pkts = rsp.packets;
last_drops = rsp.drops;
$('#engaged_alerts_trend').html(NtopUtils.get_trend(rsp.engaged_alerts, last_engaged_alerts));
last_engaged_alerts = rsp.engaged_alerts;
$('#dropped_alerts_trend').html(NtopUtils.get_trend(rsp.dropped_alerts, last_dropped_alerts));
last_dropped_alerts = rsp.dropped_alerts;
$('#dropped_alerts').html(last_dropped_alerts);
$('#local_hosts_anomalies').html(NtopUtils.fint(rsp.num_local_hosts_anomalies));
$('#local_hosts_anomalies_trend').html(NtopUtils.get_trend(rsp.num_local_hosts_anomalies, last_num_local_hosts_anomalies));
last_num_local_hosts_anomalies = rsp.num_local_hosts_anomalies;
$('#remote_hosts_anomalies').html(NtopUtils.fint(rsp.num_remote_hosts_anomalies));
$('#remote_hosts_anomalies_trend').html(NtopUtils.get_trend(rsp.num_remote_hosts_anomalies, last_num_remote_hosts_anomalies));
last_num_remote_hosts_anomalies = rsp.num_remote_hosts_anomalies;
if((rsp.packets + rsp.drops) > 0) {
pctg = ((rsp.drops*100)/(rsp.packets+rsp.drops)).toFixed(2);
}
if(rsp.drops > 0) {
drops = '<span class="badge badge-danger">';
}
drops = drops + NtopUtils.addCommas(rsp.drops)+" Pkts";
if(pctg > 0) { drops += " [ "+pctg+" % ]"; }
if(rsp.drops > 0) { drops += '</span>'; }
$('#if_drops').html(drops);
$('#exported_flows').html(NtopUtils.fint(rsp.flow_export_count));
$('#exported_flows_rate').html(NtopUtils.fflows(rsp.flow_export_rate));
if(rsp.flow_export_drops > 0) {
$('#exported_flows_drops')
.addClass("badge badge-danger")
.html(NtopUtils.fint(rsp.flow_export_drops));
if(rsp.flow_export_count > 0) {
$('#exported_flows_drops_pct')
.addClass("badge badge-danger")
.html("[" + NtopUtils.fpercent(rsp.flow_export_drops / (rsp.flow_export_count + rsp.flow_export_drops + 1) * 100) + "]");
} else {
$('#exported_flows_drops_pct').addClass("badge badge-danger").html("[100%]");
}
} else {
$('#exported_flows_drops').removeClass().html("0");
$('#exported_flows_drops_pct').removeClass().html("[0%]");
}
]]
if interface.isSyslogInterface() then
print [[
$('#syslog_tot_events').html(rsp.syslog.tot_events);
]]
end
print [[
}
});
}, ]] print(getInterfaceRefreshRate(ifstats.id).."") print[[ * 1000)
</script>
]]
print [[
<script type="text/javascript" src="]] print(ntop.getHttpPrefix()) print [[/js/jquery.tablesorter.js?]] print(ntop.getStaticFileEpoch()) print[["></script>
<script>
$(document).ready(function()
{
$("#icmp_table_4").tablesorter();
$("#icmp_table_6").tablesorter();
$("#arp_table").tablesorter();
$("#if_stats_ndpi").tablesorter();
$("#if_stats_ndpi_categories").tablesorter();
}
);
</script>
]]
dofile(dirs.installdir .. "/scripts/lua/inc/footer.lua")