--
-- (C) 2013-16 - ntop.org
--
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
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
require "common"
local json = require "dkjson"
end
require "lua_utils"
require "prefs_utils"
require "graph_utils"
require "alert_utils"
require "db_utils"
if ntop.isPro() then
shaper_utils = require("shaper_utils")
end
sendHTTPHeader('text/html; charset=iso-8859-1')
page = _GET["page"]
if_name = _GET["if_name"]
ifid = (_GET["id"] or _GET["ifId"])
ifname_clean = "iface_"..tostring(ifid)
msg = ""
function inline_input_form(name, placeholder, tooltip, value, can_edit, input_opts, input_clss)
print [[
\n")
end
if(_GET["switch_interface"] ~= nil) then
-- First switch interfaces so the new cookie will have effect
ifname = interface.setActiveInterfaceId(tonumber(ifid))
--print("@"..ifname.."="..id.."@")
if((ifname ~= nil) and (_SESSION["session"] ~= nil)) then
key = getRedisPrefix("ntopng.prefs") .. ".ifname"
ntop.setCache(key, ifname)
msg = "
The selected interface " .. getHumanReadableInterfaceName(ifid)
msg = msg .. " [id: ".. ifid .."] is now active
"
if(_SESSION["session"] == nil) then
msg = msg .."
Empty session
"
end
end
end
-- 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)
-- if not interface id is specified we look for the interface name
elseif if_name ~= nil and if_name ~= "" then
ifid = tostring(interface.name2id(if_name))
-- finally, we fall back to the default selected interface name
else
-- fall-back to the default interface
if_name = ifname
ifid = interface.name2id(ifname)
end
interface.select(if_name)
-- local pcap dump is disabled if the nbox integration is enabled or
-- if the user is not an administrator or if the interface:
-- is a view
-- is not a packet interface (i.e., it is zmq)
is_packetdump_enabled = isLocalPacketdumpEnabled()
is_packet_interface = interface.isPacketInterface()
ifstats = interface.getStats()
if (isAdministrator()) then
if(_GET["custom_name"] ~=nil) then
if(_GET["csrf"] ~= nil) then
-- TODO move keys to new schema: replace ifstats.name with ifid
ntop.setCache('ntopng.prefs.'..ifstats.name..'.name',_GET["custom_name"])
end
end
if(_GET["scaling_factor"] ~= nil) then
if(_GET["csrf"] ~= nil) then
local sf = tonumber(_GET["scaling_factor"])
if(sf == nil) then sf = 1 end
ntop.setCache(getRedisIfacePrefix(ifid)..'.scaling_factor',tostring(sf))
interface.loadScalingFactorPrefs()
end
end
if is_packetdump_enabled then
if(_GET["dump_all_traffic"] ~= nil and _GET["csrf"] ~= nil) then
page = "packetdump"
ntop.setCache('ntopng.prefs.'..ifstats.name..'.dump_all_traffic',_GET["dump_all_traffic"])
end
if(_GET["dump_traffic_to_tap"] ~= nil and _GET["csrf"] ~= nil) then
page = "packetdump"
ntop.setCache('ntopng.prefs.'..ifstats.name..'.dump_tap',_GET["dump_traffic_to_tap"])
end
if(_GET["dump_traffic_to_disk"] ~= nil and _GET["csrf"] ~= nil) then
page = "packetdump"
ntop.setCache('ntopng.prefs.'..ifstats.name..'.dump_disk',_GET["dump_traffic_to_disk"])
end
if(_GET["dump_unknown_to_disk"] ~= nil and _GET["csrf"] ~= nil) then
page = "packetdump"
ntop.setCache('ntopng.prefs.'..ifstats.name..'.dump_unknown_disk',_GET["dump_unknown_to_disk"])
end
if(_GET["dump_security_to_disk"] ~= nil and _GET["csrf"] ~= nil) then
page = "packetdump"
ntop.setCache('ntopng.prefs.'..ifstats.name..'.dump_security_disk',_GET["dump_security_to_disk"])
end
if(_GET["sampling_rate"] ~= nil and _GET["csrf"] ~= nil) then
if(tonumber(_GET["sampling_rate"]) ~= nil) then
page = "packetdump"
val = ternary(_GET["sampling_rate"] ~= "0", _GET["sampling_rate"], "1")
ntop.setCache('ntopng.prefs.'..ifstats.name..'.dump_sampling_rate', val)
end
end
if(_GET["max_pkts_file"] ~= nil and _GET["csrf"] ~= nil) then
if(tonumber(_GET["max_pkts_file"]) ~= nil) then
page = "packetdump"
ntop.setCache('ntopng.prefs.'..ifstats.name..'.dump_max_pkts_file',_GET["max_pkts_file"])
end
end
if(_GET["max_sec_file"] ~= nil and _GET["csrf"] ~= nil) then
if(tonumber(_GET["max_sec_file"]) ~= nil) then
page = "packetdump"
ntop.setCache('ntopng.prefs.'..ifstats.name..'.dump_max_sec_file',_GET["max_sec_file"])
end
end
if(_GET["max_files"] ~= nil and _GET["csrf"] ~= nil) then
if(tonumber(_GET["max_files"]) ~= nil) then
page = "packetdump"
local max_files_size = tonumber(_GET["max_files"])
max_files_size = max_files_size * 1000000
ntop.setCache('ntopng.prefs.'..ifstats.name..'.dump_max_files', tostring(max_files_size))
end
end
interface.loadDumpPrefs()
end
end
ntop.dumpFile(dirs.installdir .. "/httpdocs/inc/header.inc")
print("")
active_page = "if_stats"
dofile(dirs.installdir .. "/scripts/lua/inc/menu.lua")
print(msg)
rrdname = fixPath(dirs.workingdir .. "/" .. ifstats.id .. "/rrd/bytes.rrd")
url = ntop.getHttpPrefix()..'/lua/if_stats.lua?id=' .. ifid
-- Added global javascript variable, in order to disable the refresh of pie chart in case
-- of historical interface
print('\n\n')
print [[
]]
if((page == "overview") or (page == nil)) then
print("
\n")
print("
Id
" .. ifstats.id .. " ")
print("
\n")
if interface.isPcapDumpInterface() == false then
print("
State
")
state = toggleTableButton("", "", "Active", "1","primary", "Paused", "0","primary", "toggle_local", "ntopng.prefs."..if_name.."_not_idle")
if(state == "0") then
on_state = true
else
on_state = false
end
interface.setInterfaceIdleState(on_state)
print("
\n")
end
if(ifstats["remote.name"] ~= nil) then
print("
\n")
end
local is_physical_iface = (interface.isPacketInterface()) and (interface.isPcapDumpInterface() == false)
if((ifstats["bridge.device_a"] == nil) or (ifstats["bridge.device_b"] == nil)) then
print('
Name
' .. ifstats.name..'
\n')
if is_physical_iface then
if(ifstats.name ~= nil) then
print('
Custom Name
')
label = getInterfaceNameAlias(ifstats.name)
inline_input_form("custom_name", "Custom Name",
"Specify an alias for the interface",
label, isAdministrator(), 'autocorrect="off" spellcheck="false" pattern="^[_\\-a-zA-Z0-9 ]*$"')
print("
\n")
end
local speed_key = 'ntopng.prefs.'..ifname..'.speed'
local speed = ntop.getCache(speed_key)
if speed == nil or speed == "" or tonumber(speed) == nil then
speed = ifstats.speed
end
print("
Speed
" .. maxRateToString(speed*1000) .. "
")
if interface.isPacketInterface() then
print("
Scaling Factor
")
local label = ntop.getCache(getRedisIfacePrefix(ifid)..".scaling_factor")
if((label == nil) or (label == "")) then label = "1" end
inline_input_form("scaling_factor", "Scaling Factor",
"This should match your capture interface sampling rate",
label, isAdministrator(), 'type="number" min="1" step="1"', 'no-spinner')
end
print("
")
if(ifstats.stats.drops > 0) then print('') 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('') end
print(" ")
if (isAdministrator()) then
print("
\n")
end
print("
\n")
if(prefs.is_dump_flows_enabled) then
local dump_to = "MySQL"
if prefs.is_dump_flows_to_es_enabled == true then
dump_to = "ElasticSearch"
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 export_drops > 0 and export_count > 0 then
export_drops_pct = export_drops / export_count * 100
end
print("
In ethernet networks, each packet has an overhead of 24 bytes [preamble (7 bytes), start of frame (1 byte), CRC (4 bytes), and IFG (12 bytes)]. Such overhead needs to be accounted to the interface traffic, but it is not added to the traffic being exchanged between IP addresses. This is because such data contributes to interface load, but it cannot be accounted in the traffic being exchanged by hosts, and thus expect little discrepancies between host and interface traffic values.
\n")
for pname,pbytes in pairs(ifstats.profiles) do
local trimmed = trimSpace(pname)
local rrdname = fixPath(dirs.workingdir .. "/" .. ifid .. "/profilestats/" .. getPathFromKey(trimmed) .. "/bytes.rrd")
local statschart_icon = ''
if ntop.exists(rrdname) then
statschart_icon = ''
end
print("
")
if(interface.getInterfaceDumpTapName() ~= "") then
print [[
')
else
print("Disabled. Please restart ntopng with --enable-taps")
end
print("
\n")
print("
Sampling Rate
\n")
print [[
]]
if(dump_security_checked ~= "") then
print[[
NOTE: Sampling rate is applied only when dumping packets caused by a security alert
(e.g. a volumetric DDoS attack) and not to those hosts/flows that have been marked explicitly for dump.
]]
else
print('Disabled. Enable packet dump on security alert.')
end
print[[
Maximum number of packets to store on a pcap file before creating a new file.
]]
print("
Max Duration of File
\n")
print [[
Maximum pcap file duration before creating a new file. NOTE: a dump file is closed when it reaches first the maximum size or duration specified.
]]
print("
Max Size of Dump Files
\n")
print [[
Maximum size of created pcap files. NOTE: total file size is checked daily and old dump files are automatically overwritten after reaching the threshold.
]]
print("
")
end
elseif(page == "alerts") then
drawAlertSourceSettings(ifname_clean,
i18n("show_alerts.iface_delete_config_btn"), i18n("show_alerts.iface_delete_config_confirm"),
"if_stats.lua", {ifid=ifid},
if_name)
elseif(page == "config") then
local re_arm_minutes = nil
local if_name = ifstats.name
if(isAdministrator()) then
trigger_alerts = _GET["trigger_alerts"]
if(trigger_alerts ~= nil) then
if(trigger_alerts == "true") then
ntop.delHashCache(get_alerts_suppressed_hash_name(ifname), ifname_clean)
else
ntop.setHashCache(get_alerts_suppressed_hash_name(ifname), ifname_clean, trigger_alerts)
end
end
end
re_arm_minutes = ntop.getHashCache(get_re_arm_alerts_hash_name(), get_re_arm_alerts_hash_key(ifId, ifname_clean))
if re_arm_minutes == "" then re_arm_minutes=default_re_arm_minutes end
print("
\n")
suppressAlerts = ntop.getHashCache(get_alerts_suppressed_hash_name(ifname), ifname_clean)
if((suppressAlerts == "") or (suppressAlerts == nil) or (suppressAlerts == "true")) then
alerts_checked = 'checked="checked"'
alerts_value = "false" -- Opposite
else
alerts_checked = ""
alerts_value = "true" -- Opposite
end
print [[
Interface Alerts
')
print('
')
print [[
]]
print[[
]]
print("
")
elseif(page == "filtering") then
if not isAdministrator() then
error()
end
-- ====================================
function get_shapers_from_parameters(callback)
local done = {}
for option,value in pairs(_GET) do
local sp = split(option, "ishaper_")
local k = nil
if #sp == 2 then
k = sp[2]
else
sp = split(option, "eshaper_")
if #sp == 2 then
k = sp[2]
end
end
if k ~= nil then
if not done[k] then
done[k] = true;
callback(k, _GET["ishaper_"..k], _GET["eshaper_"..k])
end
end
end
end
if (_GET["view_network"] ~= nil) then
-- this is used by host_details.lua. Checks if the network exists, otherwise creates it
if isin(_GET["view_network"], shaper_utils.getNetworksList(ifid)) then
-- network exists, redirect
jsUrlChange("if_stats.lua?id="..ifid.."&page=filtering&network=".._GET["view_network"].."#protocols")
else
-- network does not exist, trigger add action
jsUrlChange("if_stats.lua?id="..ifid.."&page=filtering&network=".._GET["view_network"].."#networks")
print('')
_GET["view_network"] = nil
end
end
if((_GET["csrf"] ~= nil) and (_GET["edit_networks"] ~= nil)) then
local proto_shapers_cloned = false
get_shapers_from_parameters(function(network_key, ingress_shaper, egress_shaper)
-- reconstruct from url encoded
-- TODO ipv6 local address format?
network_key = network_key:gsub("(%d+)_(%d+)_(%d+)_(%d+)", "%1.%2.%3.%4")
network_key = network_key:gsub("_2F", "/")
network_key = network_key:gsub("_40", "@")
if(_GET["clone"] ~= nil) then
local clone_from = shaper_utils.addVlan0(_GET["clone"])
-- clone everything from the network
for _,proto_config in pairs(shaper_utils.getNetworkProtoShapers(ifid, clone_from, false)) do
shaper_utils.setProtocolShapers(ifid, network_key, proto_config.protoId, proto_config.ingress, proto_config.egress, false)
proto_shapers_cloned = true
end
else
-- Do not create any additional protocol rule
shaper_utils.setProtocolShapers(ifid, network_key, shaper_utils.NETWORK_SHAPER_DEFAULT_PROTO_KEY, ingress_shaper, egress_shaper, false)
end
interface.reloadL7Rules(network_key)
end)
jsUrlChange("if_stats.lua?id="..ifid.."&page=filtering")
end
if((_GET["csrf"] ~= nil) and (_GET["delete_network"] ~= nil) and (_GET["delete_network"] ~= shaper_utils.ANY_NETWORK)) then
local target_net = _GET["delete_network"]
shaper_utils.deleteNetwork(ifid, target_net)
-- reload all the rules, and update hosts affected by removal
interface.reloadL7Rules(target_net)
jsUrlChange("if_stats.lua?id="..ifid.."&page=filtering")
end
net = _GET["network"] or _GET["proto_network"] or _GET["view_network"]
if(net ~= nil) then
net = shaper_utils.addVlan0(net)
end
-- NB: this contains at least the 'default' network
-- NB: this must be placed after 'delete_network' in order to fetch latest networks list
nets = shaper_utils.getNetworksList(ifid)
--tprint(nets)
if(net == nil) then
-- If there is not &network= parameter then use the first network available
for _,k in ipairs(nets) do
net = k
break
end
end
selected_network = net
if(selected_network == nil) then
selected_network = shaper_utils.ANY_NETWORK
end
if((_GET["csrf"] ~= nil) and (_GET["add_shapers"] ~= nil)) then
local num_added = 0
local last_added = nil
for shaper,mrate in pairs(_GET) do
local sp = split(shaper, "shaper_")
if #sp == 2 then
local shaper_id = tonumber(sp[2])
local max_rate = tonumber(mrate)
--~ tprint(shaper_id.." "..max_rate)
if(max_rate > 1048576) then max_rate = -1 end
if(max_rate < -1) then max_rate = -1 end
shaper_utils.setShaperMaxRate(ifid, shaper_id, max_rate)
num_added = num_added + 1
last_added = shaper_id
end
end
if num_added == 1 then
print("")
end
interface.reloadShapers()
jsUrlChange("if_stats.lua?id="..ifid.."&page=filtering#shapers")
end
if((_GET["csrf"] ~= nil) and (_GET["delete_shaper"] ~= nil)) then
local shaper_id = _GET["delete_shaper"]
shaper_utils.deleteShaper(ifid, shaper_id)
jsUrlChange("if_stats.lua?id="..ifid.."&page=filtering#shapers")
end
if((_GET["csrf"] ~= nil) and (_GET["proto_network"] ~= nil)) then
local target_net = _GET["proto_network"]
if (_GET["del_l7_proto"] ~= nil) then
local protocol_id = _GET["del_l7_proto"]
shaper_utils.deleteProtocol(ifid, target_net, protocol_id)
else
-- set protocols policy for the network
get_shapers_from_parameters(function(proto_id, ingress_shaper, egress_shaper)
shaper_utils.setProtocolShapers(ifid, target_net, proto_id, ingress_shaper, egress_shaper, false)
end)
end
-- Note: this could optimized to only reload this specific network
interface.reloadL7Rules(target_net)
jsUrlChange("if_stats.lua?id="..ifid.."&page=filtering&network="..target_net.."#protocols")
end
print [[
]]
-- ******************************************
local shapers = shaper_utils.getSortedShapers(ifid)
function print_shapers(shapers, curshaper_id, terminator)
terminator = terminator or "\n"
if(curshaper_id == "") then curshaper_id = "0" else curshaper_id = tostring(curshaper_id) end
for _,shaper in ipairs(shapers) do
print(""..terminator)
end
end
-- ******************************************
locals = ntop.getLocalNetworks()
locals_empty = (next(locals) == nil)
-- ==== Create networks tab ====
print [[
Create
Network:
]]
print[[
]]
if not locals_empty then
print('')
print('
')
end
print[[
VLAN
Initial Policy:
from
NOTES:
These networks are used to define traffic policies
]]
-- ==== Manage protocols tab ====
print [[
Manage
]] print(i18n("shaping.network_group")..":") print[[ ")
this_net = shaper_utils.trimVlan0(selected_network)
if selected_network ~= shaper_utils.ANY_NETWORK then
print[[]]
print(jsFormCSRF("deletePolicyForm"))
end
print[[
NOTES:
Dropping some core protocols can have side effects on other protocols. For instance if you block DNS, symbolic host names are no longer resolved, and thus only communication with numeric IPs work.