-- -- (C) 2014-15 - ntop.org -- require "lua_trace" function getInterfaceName(interface_id) local ifnames = interface.getIfNames() interface_id = tonumber(interface_id) for _,if_name in pairs(ifnames) do interface.select(if_name) ifstats = interface.getStats() if(ifstats.id == interface_id) then return(ifstats.name) end end return("") end -- Note that ifname can be set by Lua.cpp so don't touch it if already defined if((ifname == nil) and (_GET ~= nil)) then ifname = _GET["ifname"] if(ifname ~= nil) then if(ifname.."" == tostring(tonumber(ifname)).."") then -- ifname does not contain the interface name but rather the interface id ifname = getInterfaceName(ifname) if(ifname == "") then ifname = nil end end end if(debug_session) then traceError(TRACE_DEBUG,TRACE_CONSOLE, "Session => Session:".._SESSION["session"]) end if((ifname == nil) and (_SESSION ~= nil)) then if(debug_session) then traceError(TRACE_DEBUG,TRACE_CONSOLE, "Session => set ifname by _SESSION value") end ifname = _SESSION["ifname"] if(debug_session) then traceError(TRACE_DEBUG,TRACE_CONSOLE, "Session => ifname:"..ifname) end else if(debug_session) then traceError(TRACE_DEBUG,TRACE_CONSOLE, "Session => set ifname by _GET value") end end end --print("(((("..ifname.."))))") l4_keys = { { "TCP", "tcp" }, { "UDP", "udp" }, { "ICMP", "icmp" }, { "Other IP", "other ip" } } function __FILE__() return debug.getinfo(2,'S').source end function __LINE__() return debug.getinfo(2, 'l').currentline end function sendHTTPHeaderIfName(mime, ifname, maxage) info = ntop.getInfo() print('HTTP/1.1 200 OK\r\n') print('Cache-Control: max-age=0, no-cache, no-store\r\n') print('Server: ntopng '..info["version"]..' ['.. info["platform"]..']\r\n') print('Pragma: no-cache\r\n') print('X-Frame-Options: DENY\r\n') print('X-Content-Type-Options: nosniff\r\n') if(_SESSION ~= nil) then print('Set-Cookie: session='.._SESSION["session"]..'; max-age=' .. maxage .. '; path=/; HttpOnly\r\n') end if(ifname ~= nil) then print('Set-Cookie: ifname=' .. ifname .. '; path=/\r\n') end print('Content-Type: '.. mime ..'\r\n') print('Last-Modified: '..os.date("!%a, %m %B %Y %X %Z").."\r\n") print('\r\n') end function sendHTTPHeaderLogout(mime) sendHTTPHeaderIfName(mime, nil, 0) end function sendHTTPHeader(mime) sendHTTPHeaderIfName(mime, nil, 3600) end function printGETParameters(get) for key, value in pairs(get) do io.write(key.."="..value.."\n") end end function isEmptyString(str) -- io.write(str..'\n') if((str == nil) or (str == "")) then return true else return false end end function findString(str, tofind) local upper_lower = true if(str == nil) then return(nil) end if(tofind == nil) then return(nil) end str1 = string.gsub(str, "-", "_") tofind1 = string.gsub(tofind, "-", "_") rsp = string.find(str1, tofind1, 1) if(upper_lower) then if(rsp == nil) then -- Lowercase str1 = string.lower(str1) tofind1 = string.lower(tofind1) rsp = string.find(str1, tofind1, 1) end if(rsp == nil) then -- Uppercase str1 = string.upper(str1) tofind1 = string.upper(tofind1) rsp = string.find(str1, tofind1, 1) end end --print(str1 .. "/" .. tofind1.."\n") --print(rsp) --print("\n") return(rsp) end function findStringArray(str, tofind) if(str == nil) then return(nil) end if(tofind == nil) then return(nil) end local rsp = false for k,v in pairs(tofind) do str1 = string.gsub(str, "-", "_") tofind1 = string.gsub(v, "-", "_") if(str1 == tofind1) then rsp = true end end return(rsp) end function string.contains(String,Start) return(string.find(String,Start,1) ~= nil) end function string.starts(String,Start) return string.sub(String,1,string.len(Start))==Start end function string.ends(String,End) return End=='' or string.sub(String,-string.len(End))==End end function printASN(asn, asname) if(asn > 0) then return(""..asname.." ") else return(asname) end end function shortenString(name) max_len = 24 if(string.len(name) < max_len) then return(name) else return(string.sub(name, 1, max_len).."...") end end function shortHostName(name) local chunks = {name:match("(%d+)%.(%d+)%.(%d+)%.(%d+)")} if(#chunks == 4) then return(name) else max_len = 24 chunks = {name:match("%w+:%w+:%w+:%w+:%w+:%w+")} --io.write(#chunks.."\n") if(#chunks == 1) then return(name) end if(string.len(name) < max_len) then return(name) else tot = 0 n = 0 ret = "" for token in string.gmatch(name, "([%w-]+).") do if(tot < max_len) then if(n > 0) then ret = ret .. "." end ret = ret .. token tot = tot+string.len(token) n = n + 1 end end return(ret .. "...") end end return(name) end function _handleArray(name, sev) local id for id, _ in ipairs(name) do local l = name[id][1] local key = name[id][2] if(string.upper(key) == string.upper(sev)) then return(l) end end return(firstToUpper(sev)) end epp_rrd_names = { { "Positive Replies Number", "num_replies_ok.rrd" }, { "Error Replies Number", "num_replies_error.rrd" }, { "Query Number", "num_queries.rrd" }, { "domain-create", "num_cmd_1.rrd" }, { "domain-update", "num_cmd_2.rrd" }, { "domain-delete", "num_cmd_3.rrd" }, { "domain-restore", "num_cmd_4.rrd" }, { "domain-transfer", "num_cmd_5.rrd" }, { "domain-transfer-trade", "num_cmd_6.rrd" }, { "domain-transfer-request", "num_cmd_7.rrd" }, { "domain-transfer-trade-request", "num_cmd_8.rrd" }, { "domain-transfer-cancel", "num_cmd_9.rrd" }, { "domain-transfer-approve", "num_cmd_10.rrd" }, { "domain-transfer-reject", "num_cmd_11.rrd" }, { "contact-create", "num_cmd_12.rrd" }, { "contact-update", "num_cmd_13.rrd" }, { "contact-delete", "num_cmd_14.rrd" }, { "domain-update-hosts", "num_cmd_15.rrd" }, { "domain-update-statuses", "num_cmd_16.rrd" }, { "domain-update-contacts", "num_cmd_17.rrd" }, { "domain-trade", "num_cmd_18.rrd" }, { "domain-update-simple", "num_cmd_19.rrd" }, { "domain-info", "num_cmd_20.rrd" }, { "contact-info", "num_cmd_21.rrd" }, { "domain-check", "num_cmd_22.rrd" }, { "contact-check", "num_cmd_23.rrd" }, { "poll-req", "num_cmd_24.rrd" }, { "domain-transfer-trade-cancel", "num_cmd_25.rrd" }, { "domain-transfer-trade-approve", "num_cmd_26.rrd" }, { "domain-transfer-trade-reject", "num_cmd_27.rrd" }, { "domain-transfer-query", "num_cmd_28.rrd" }, { "login", "num_cmd_29.rrd" }, { "login-chg-pwd", "num_cmd_30.rrd" }, { "logout", "num_cmd_31.rrd" }, { "poll-ack", "num_cmd_32.rrd" }, { "hello", "num_cmd_33.rrd" }, { "unknown-command", "num_cmd_34.rrd" } } function l4Label(proto) return(_handleArray(l4_keys, proto)) end function mapEppRRDName(name) return(_handleArray(epp_rrd_names, name)) end -- Alerts (see ntop_typedefs.h) alert_level_keys = { { "Info", 0 }, { "Warning", 1 }, { "Error", 2 } } alert_type_keys = { { " TCP SYN Flood", 0 }, { " Flows Flood", 1 }, { " Threshold Cross", 2 }, { " Blacklist Host", 3 }, { " Periodic Activity", 4 }, { " Quota Exceeded", 5 }, { " Malware Detected", 6 } } function alertSeverityLabel(v) return(_handleArray(alert_level_keys, tonumber(v))) end function alertTypeLabel(v) return(_handleArray(alert_type_keys, tonumber(v))) end function firstToUpper(str) str = tostring(str) return (str:gsub("^%l", string.upper)) end function pairsByKeys(t, f) local a = {} for n in pairs(t) do table.insert(a, n) end table.sort(a, f) local i = 0 -- iterator variable local iter = function () -- iterator function i = i + 1 if a[i] == nil then return nil else return a[i], t[a[i]] end end return iter end function pairsByValues(t, f) local a = {} for n in pairs(t) do table.insert(a, n) end table.sort(a, function(x, y) return f(t[x], t[y]) end) local i = 0 -- iterator variable local iter = function () -- iterator function i = i + 1 if a[i] == nil then return nil else return a[i], t[a[i]] end end return iter end function asc(a,b) return (a < b) end function rev(a,b) return (a > b) end --for _key, _value in pairsByKeys(vals, rev) do -- print(_key .. "=" .. _value .. "\n") --end function round(num, idp) return tonumber(string.format("%." .. (idp or 0) .. "f", num)) end -- Convert bytes to human readable format function bytesToSize(bytes) if(bytes == nil) then return("0") else precision = 2 kilobyte = 1024; megabyte = kilobyte * 1024; gigabyte = megabyte * 1024; terabyte = gigabyte * 1024; if((bytes >= 0) and (bytes < kilobyte)) then return round(bytes, precision) .. " B"; elseif((bytes >= kilobyte) and (bytes < megabyte)) then return round(bytes / kilobyte, precision) .. ' KB'; elseif((bytes >= megabyte) and (bytes < gigabyte)) then return round(bytes / megabyte, precision) .. ' MB'; elseif((bytes >= gigabyte) and (bytes < terabyte)) then return round(bytes / gigabyte, precision) .. ' GB'; elseif(bytes >= terabyte) then return round(bytes / terabyte, precision) .. ' TB'; else return round(bytes, precision) .. ' B'; end end end -- Convert bits to human readable format function bitsToSize(bits) precision = 2 kilobit = 1024; megabit = kilobit * 1024; gigabit = megabit * 1024; terabit = gigabit * 1024; if((bits >= kilobit) and (bits < megabit)) then return round(bits / kilobit, precision) .. ' Kbit/s'; elseif((bits >= megabit) and (bits < gigabit)) then return round(bits / megabit, precision) .. ' Mbit/s'; elseif((bits >= gigabit) and (bits < terabit)) then return round(bits / gigabit, precision) .. ' Gbit/s'; elseif(bits >= terabit) then return round(bits / terabit, precision) .. ' Tbit/s'; else return round(bits, precision) .. ' bps'; end end -- Convert packets to pps readable format function pktsToSize(pkts) precision = 2 if (pkts >= 1000000) then return round(pkts/1000000, precision)..' Mpps'; elseif(pkts >= 1000) then return round(pkts/ 1000, precision)..' Kpps'; else return round(pkts , precision)..' pps'; end end function formatValue(amount) local formatted = amount if(formatted == nil) then return(0) end while true do formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2') if(k==0) then break end end return formatted end function formatPackets(amount) return formatValue(amount).." Pkts" end function capitalize(str) return (str:gsub("^%l", string.upper)) end function split(pString, pPattern) local Table = {} -- NOTE: use {n = 0} in Lua-5.0 local fpat = "(.-)" .. pPattern local last_end = 1 local s, e, cap = pString:find(fpat, 1) while s do if s ~= 1 or cap ~= "" then table.insert(Table,cap) end last_end = e+1 s, e, cap = pString:find(fpat, last_end) end if last_end <= #pString then cap = pString:sub(last_end) table.insert(Table, cap) end return Table end string.split = function(s, p) local temp = {} local index = 0 local last_index = string.len(s) while true do local i, e = string.find(s, p, index) if i and e then local next_index = e + 1 local word_bound = i - 1 table.insert(temp, string.sub(s, index, word_bound)) index = next_index else if index > 0 and index <= last_index then table.insert(temp, string.sub(s, index, last_index)) elseif index == 0 then temp = nil end break end end return temp end function formatEpoch(epoch) return(os.date("%d/%m/%Y %X", epoch)) end function secondsToTime(seconds) if(seconds == nil) then return "" end if(seconds < 1) then return("< 1 sec") end days = math.floor(seconds / 86400) hours = math.floor((seconds / 3600) - (days * 24)) minutes = math.floor((seconds / 60) - (days * 1440) - (hours * 60)) sec = seconds % 60 msg = "" if(days > 0) then years = math.floor(days/365) if(years > 0) then days = days % 365 msg = years .. " year" if(years > 1) then msg = msg .. "s" end msg = msg .. ", " end if(days > 0) then msg = msg .. days .. " day" if(days > 1) then msg = msg .. "s" end msg = msg .. ", " end end if(hours > 0) then msg = msg .. string.format("%d ", hours) if(hours > 1) then msg = msg .. "h" else msg = msg .. "h" end --if(hours > 1) then msg = msg .. "s" end msg = msg .. ", " end if(minutes > 0) then msg = msg .. string.format("%d min", minutes) end if(sec > 0) then if((string.len(msg) > 0) and (minutes > 0)) then msg = msg .. ", " end msg = msg .. string.format("%d sec", sec); end return msg end function starts(String,Start) return string.sub(String,1,string.len(Start))==Start end function ends(String,End) return End=='' or string.sub(String,-string.len(End))==End end -- ################################################################# function getCategoryIcon(what, cat) if((cat == "") or (cat == nil)) then return("") elseif(cat == "safe") then return("") elseif(cat == "malware") then return("") else return(cat) end end function abbreviateString(str, len) if(str == nil) then return("") else if(string.len(str) < len) then return(str) else return(string.sub(str, 1, len).."...") end end end function bit(p) return 2 ^ (p - 1) -- 1-based indexing end -- Typical call: if hasbit(x, bit(3)) then ... function hasbit(x, p) return x % (p + p) >= p end function setbit(x, p) return hasbit(x, p) and x or x + p end function clearbit(x, p) return hasbit(x, p) and x - p or x end function isBroadMulticast(ip) if(ip == "0.0.0.0") then return true end -- print(ip) t = string.split(ip, "%.") -- print(table.concat(t, "\n")) if(t == nil) then return false -- Might be an IPv6 address else if(tonumber(t[1]) >= 224) then return true end end return false end -- exclude_BroadMultIPv6 function exclude_BroadMultIPv6(ip) -- check NoIP if(ip == "0.0.0.0") then return true end -- check IPv6 t = string.split(ip, "%.") if(t == nil) then return true else -- check Multicast / Broadcast if(tonumber(t[1]) >= 224) then return true end end return false end function addGauge(name, url, maxValue, width, height) if(url ~= nil) then print('') end print('\n') -- print('
\n') if(url ~= nil) then print('
') end print [[ \n") end -- Compute the difference in seconds between local time and UTC. function get_timezone() local now = os.time() return os.difftime(now, os.time(os.date("!*t", now))) end function isLocal(host_ip) host = interface.getHostInfo(host_ip) if((host == nil) or (host['localhost'] ~= true)) then return(false) else return(true) end end -- Return the first 'howmany' hosts function getTopInterfaceHosts(howmany, localHostsOnly) hosts_stats = interface.getHostsInfo() ret = {} sortTable = {} n = 0 for k,v in pairs(hosts_stats) do if((not localHostsOnly) or ((v["localhost"] == true) and (v["ip"] ~= nil))) then sortTable[v["bytes.sent"]+v["bytes.rcvd"]+n] = k n = n +0.01 end end n = 0 for _v,k in pairsByKeys(sortTable, rev) do if(n < howmany) then ret[k] = hosts_stats[k] n = n+1 else break end end return(ret) end function http_escape(s) s = string.gsub(s, "([&=+%c])", function (c) return string.format("%%%02X", string.byte(c)) end) s = string.gsub(s, " ", "+") return s end function getInterfaceId(interface_name) ifnames = interface.getIfNames() for _,if_name in pairs(ifnames) do interface.select(if_name) ifstats = interface.getStats() if(ifstats.name == interface_name) then return(ifstats.id) end end return(-1) end -- Windows fixes for interfaces with "uncommon chars" function purifyInterfaceName(interface_name) interface_name = string.gsub(interface_name, "@", "_") interface_name = string.gsub(interface_name, ":", "_") return(interface_name) end -- Fix path format Unix <-> Windows function fixPath(path) if(ntop.isWindows() and (string.len(path) > 2)) then path = string.gsub(path, "/", "\\") -- Avoid changing c:\.... into c_\.... path = string.sub(path, 1, 2) .. string.gsub(string.sub(path, 3), ":", "_") -- io.write("->"..path.."\n") end return(path) end -- See datatype AggregationType in ntop_typedefs.h function aggregation2String(value) if(value == 0) then return("Client Name") elseif(value == 1) then return("Server Name") elseif(value == 2) then return("Domain Name") elseif(value == 3) then return("Operating System") elseif(value == 4) then return("Registrar Name") else return(value) end end function getOSIcon(name) icon = "" if(findString(name, "Linux") or findString(name, "Ubuntu")) then icon = ' ' elseif(findString(name, "Android")) then icon = ' ' elseif(findString(name, "Windows") or findString(name, "Win32") or findString(name, "MSIE")) then icon = ' ' elseif(findString(name, "iPhone") or findString(name, "iPad") or findString(name, "OS X") ) then icon = ' ' end return(icon) end function getApplicationLabel(name) icon = "" if(name == nil) then name = "" end if(findString(name, "Skype")) then icon = '' elseif(findString(name, "Unknown")) then icon = '' elseif(findString(name, "Twitter")) then icon = '' elseif(findString(name, "DropBox")) then icon = '' elseif(findString(name, "Spotify")) then icon = '' elseif(findString(name, "Apple")) then icon = '' elseif(findString(name, "Google") or findString(name, "Chrome")) then icon = '' elseif(findString(name, "FaceBook")) then icon = '' elseif(findString(name, "Youtube")) then icon = '' elseif(findString(name, "thunderbird")) then icon = '' end name = name:gsub("^%l", string.upper) return(icon.." "..name) end function mapOS2Icon(name) if(name == nil) then return("") else return(getOSIcon(name) .. name) end end function getItemsNumber(n) tot = 0 for k,v in pairs(n) do --io.write(k.."\n") tot = tot + 1 end --io.write(tot.."\n") return(tot) end function getHostCommaSeparatedList(p_hosts) hosts = {} hosts_size = 0 for i,host in pairs(split(p_hosts, ",")) do hosts[i] = host hosts_size = hosts_size + 1 end return hosts,hosts_size end -- ############################################## -- Used to avoid resolving host names too many times resolved_host_labels_cache = {} function getHostAltName(host_ip) local alt_name = resolved_host_labels_cache[host_ip] if(alt_name ~= nil) then return(alt_name) end alt_name = ntop.getHashCache("ntopng.host_labels", host_ip) if((alt_name == nil) or (alt_name == "")) then alt_name = host_ip end resolved_host_labels_cache[host_ip] = alt_name return(alt_name) end function setHostAltName(host_ip, alt_name) ntop.setHashCache("ntopng.host_labels", host_ip, alt_name) end -- Flow Utils -- function flowinfo2hostname(flow_info, host_type, show_vlan) local name local orig_name name = flow_info[host_type..".host"] if((name == "") or (name == nil)) then name = flow_info[host_type..".ip"] end orig_name = name name = getHostAltName(name) if(name == orig_name) then rname = ntop.getResolvedAddress(name) if((rname ~= nil) and (rname ~= "")) then name = rname end end -- io.write(host_type.. " / " .. flow_info[host_type..".host"].." / "..name.."\n") if(show_vlan and (flow_info["vlan"] > 0)) then name = name .. '@' .. flow_info["vlan"] end return name end -- Url Util -- -- -- Split the host key (ip@vlan) creating a new lua table. -- Example: -- info = hostkey2hostinfo(key) -- ip = info["host"] -- vlan = info["vlan"] -- function hostkey2hostinfo(key) local host = {} local info = split(key,"@") if(info[1] ~= nil) then host["host"] = info[1] end if(info[2] ~= nil) then host["vlan"] = tonumber(info[2]) else host["vlan"] = 0 end return host end -- -- Analyze the host_info table and return the host key. -- Example: -- host_info = interface.getHostInfo("127.0.0.1",0) -- key = hostinfo2hostkey(host_info) -- function hostinfo2hostkey(host_info,host_type,show_vlan) local rsp = "" if(host_type == "cli") then if(host_info["cli.ip"] ~= nil) then rsp = rsp..host_info["cli.ip"] end elseif(host_type == "srv") then if(host_info["srv.ip"] ~= nil) then rsp = rsp..host_info["srv.ip"] end else if(host_info["host"] ~= nil) then rsp = rsp..host_info["host"] elseif(host_info["name"] ~= nil) then rsp = rsp..host_info["name"] elseif(host_info["ip"] ~= nil) then rsp = rsp..host_info["ip"] elseif(host_info["mac"] ~= nil) then rsp = rsp..host_info["mac"] end end if(((host_info["vlan"] ~= nil) and (host_info["vlan"] ~= 0)) or ((show_vlan ~= nil) and show_vlan)) then rsp = rsp..'@'..tostring(host_info["vlan"]) end if(debug_host) then traceError(TRACE_DEBUG,TRACE_CONSOLE,"HOST2URL => ".. rsp .. "\n") end return rsp end -- -- Analyze the get_info and return a new table containing the url information about an host. -- Example: url2host(_GET) -- function url2hostinfo(get_info) local host = {} -- Catch when the host key is using as host url parameter if((get_info["host"] ~= nil) and (string.find(get_info["host"],"@"))) then get_info = hostkey2hostinfo(get_info["host"]) end if(get_info["host"] ~= nil) then host["host"] = get_info["host"] if(debug_host) then traceError(TRACE_DEBUG,TRACE_CONSOLE,"URL2HOST => Host:"..get_info["host"].."\n") end end if(get_info["vlan"] ~= nil) then host["vlan"] = tonumber(get_info["vlan"]) if(debug_host) then traceError(TRACE_DEBUG,TRACE_CONSOLE,"URL2HOST => Vlan:"..get_info["vlan"].."\n") end else host["vlan"] = 0 end return host end -- -- Catch the main information about an host from the host_info table and return the corresponding url. -- Example: -- hostinfo2url(host_key), return an url based on the host_key -- hostinfo2url(host[key]), return an url based on the host value -- hostinfo2url(flow[key],"cli"), return an url based on the client host information in the flow table -- hostinfo2url(flow[key],"srv"), return an url based on the server host information in the flow table -- function hostinfo2url(host_info,host_type) local rsp = '' -- local version = 0 local version = 1 if(host_type == "cli") then if(host_info["cli.ip"] ~= nil) then rsp = rsp..'host='..host_info["cli.ip"] end elseif(host_type == "srv") then if(host_info["srv.ip"] ~= nil) then rsp = rsp..'host='..host_info["srv.ip"] end else if((type(host_info) ~= "table")) then host_info = hostkey2hostinfo(host_info) end if(host_info["host"] ~= nil) then rsp = rsp..'host='..host_info["host"] elseif(host_info["ip"] ~= nil) then rsp = rsp..'host='..host_info["ip"] elseif(host_info["name"] ~= nil) then rsp = rsp..'host='..host_info["name"] elseif(host_info["mac"] ~= nil) then rsp = rsp..'host='..host_info["mac"] end end if((host_info["vlan"] ~= nil) and (host_info["vlan"] ~= 0)) then if(version == 0) then rsp = rsp..'&vlan='..tostring(host_info["vlan"]) elseif(version == 1) then rsp = rsp..'@'..tostring(host_info["vlan"]) end end if(debug_host) then traceError(TRACE_DEBUG,TRACE_CONSOLE,"HOST2URL => ".. rsp .. "\n") end return rsp end -- -- Catch the main information about an host from the host_info table and return the corresponding json. -- Example: -- hostinfo2json(host[key]), return a json string based on the host value -- hostinfo2json(flow[key],"cli"), return a json string based on the client host information in the flow table -- hostinfo2json(flow[key],"srv"), return a json string based on the server host information in the flow table -- function hostinfo2json(host_info,host_type) local rsp = '' if(host_type == "cli") then if(host_info["cli.ip"] ~= nil) then rsp = rsp..'host: "'..host_info["cli.ip"]..'"' end elseif(host_type == "srv") then if(host_info["srv.ip"] ~= nil) then rsp = rsp..'host: "'..host_info["srv.ip"]..'"' end else if((type(host_info) ~= "table") and (string.find(host_info,"@"))) then host_info = hostkey2hostinfo(host_info) end if(host_info["host"] ~= nil) then rsp = rsp..'host: "'..host_info["host"]..'"' elseif(host_info["ip"] ~= nil) then rsp = rsp..'host: "'..host_info["ip"]..'"' elseif(host_info["name"] ~= nil) then rsp = rsp..'host: "'..host_info["name"] ..'"' elseif(host_info["mac"] ~= nil) then rsp = rsp..'host: "'..host_info["mac"] ..'"' end end if((host_info["vlan"] ~= nil) and (host_info["vlan"] ~= 0)) then rsp = rsp..', vlan: "'..tostring(host_info["vlan"]) .. '"' end if(debug_host) then traceError(TRACE_DEBUG,TRACE_CONSOLE,"HOST2JSON => ".. rsp .. "\n") end return rsp end -- -- Catch the main information about an host from the host_info table and return the corresponding jqueryid. -- Example: host 192.168.1.254, vlan0 ==> 1921681254_0 function hostinfo2jqueryid(host_info,host_type) local rsp = '' if(host_type == "cli") then if(host_info["cli.ip"] ~= nil) then rsp = rsp..''..host_info["cli.ip"] end elseif(host_type == "srv") then if(host_info["srv.ip"] ~= nil) then rsp = rsp..''..host_info["srv.ip"] end else if((type(host_info) ~= "table") and (string.find(host_info,"@"))) then host_info = hostkey2hostinfo(host_info) end if(host_info["host"] ~= nil) then rsp = rsp..''..host_info["host"] elseif(host_info["ip"] ~= nil) then rsp = rsp..''..host_info["ip"] elseif(host_info["name"] ~= nil) then rsp = rsp..''..host_info["name"] elseif(host_info["mac"] ~= nil) then rsp = rsp..''..host_info["mac"] end end if((host_info["vlan"] ~= nil) and (host_info["vlan"] ~= 0)) then rsp = rsp..'_'..tostring(host_info["vlan"]) end rsp = string.gsub(rsp, "%.", "__") rsp = string.gsub(rsp, "/", "___") rsp = string.gsub(rsp, ":", "____") if(debug_host) then traceError(TRACE_DEBUG,TRACE_CONSOLE,"HOST2KEY => ".. rsp .. "\n") end return rsp end -- version is major.minor.veryminor function version2int(v) if(v == nil) then return(0) end e = string.split(v, "%."); if(e ~= nil) then major = e[1] minor = e[2] veryminor = e[3] if(major == nil or tonumber(major) == nil or type(major) ~= "string") then major = 0 end if(minor == nil or tonumber(minor) == nil or type(minor) ~= "string") then minor = 0 end if(veryminor == nil or tonumber(veryminor) == nil or type(veryminor) ~= "string") then veryminor = 0 end version = tonumber(major)*1000 + tonumber(minor)*100 + tonumber(veryminor) return(version) else return(0) end end function ntop_version_check() _rsp = ntop.getCache("ntopng.version") if((_rsp == nil) or (_rsp == "")) then _rsp = ntop.httpGet("http://www.ntop.org/ntopng.version", "", "", 10) if((_rsp == nil) or (_rsp["CONTENT"] == nil)) then rsp = "0.0.0" else rsp = _rsp["CONTENT"] end ntop.setCache("ntopng.version", rsp, 86400) else rsp = _rsp end if(rsp ~= nil) then info = ntop.getInfo() stable_version = version2int(rsp) version_elems = split(info["version"], " "); this_version = version2int(version_elems[1]) if(stable_version > this_version) then print("

A new "..info["product"].." (v." .. rsp .. ") is available for download: please upgrade.

") end end end -- Print contents of `tbl`, with indentation. -- `indent` sets the initial level of indentation. function tprint (tbl, indent) if not indent then indent = 0 end if(tbl ~= nil) then for k, v in pairs(tbl) do formatting = string.rep(" ", indent) .. k .. ": " if type(v) == "table" then io.write(formatting) tprint(v, indent+1) elseif type(v) == 'boolean' then io.write(formatting .. tostring(v)) else io.write(formatting .. v) end end io.write("\n") end end function table.empty(table) if(table == nil) then return true end if next(table) == nil then return true end return false end function table.len(table) local count = 0 if(table == nil) then return(0) end for k,v in pairs(table) do count = count + 1 end return count end -- ############################################ -- Redis Utils -- ############################################ -- Inpur: General prefix (i.e ntopng.pref) -- Output: User based prefix, if it exists -- -- Examples: -- With user: ntopng.pref.user_name -- Without: ntopng.pref function getRedisPrefix(str) if not (isEmptyString(_SESSION["user"] )) then -- Login enabled return (str .. '.' .. _SESSION["user"]) else -- Login disabled return (str) end end function getPathFromKey(key) local path = string.gsub(key, "%.", "/") path = string.gsub(path, ":", "_") return fixPath(path) end ----- End of Redis Utils ------ -- ############################################ -- Runtime preference function prefsInputField(label, comment, key, value) if(_GET[key] ~= nil) then k = "ntopng.prefs."..key v_s = _GET[key] v = tonumber(v_s) if(v ~= nil and (v > 0) and (v < 86400)) then -- print(k.."="..v) ntop.setCache(k, tostring(v)) value = v elseif (v_s ~= nil) then ntop.setCache(k, v_s) value = v_s end end print(''..label..'

'..comment..'') print [[

]] end function toggleTableButton(label, comment, on_label, on_value, on_color , off_label, off_value, off_color, submit_field, redis_key, disabled) if(_GET[submit_field] ~= nil) then ntop.setCache(redis_key, _GET[submit_field]) value = _GET[submit_field] else value = ntop.getCache(redis_key) end if (disabled == true) then disabled = 'disabled = ""' else disabled = "" end -- Read it anyway to if(value == off_value) then rev_value = on_value on_active = "btn-default" off_active = "btn-"..off_color.." active" else rev_value = off_value on_active = "btn-"..on_color.." active" off_active = "btn-default" end if(label ~= "") then print(''..label..'

'..comment..'\n') end print('

\n
') print('\n') print('\n') print('') print('
\n') print('
\n') if(label ~= "") then print('') end return(value) end function isPausedInterface(current_ifname) state = ntop.getCache("ntopng.prefs."..current_ifname.."_not_idle") if(state == "0") then return true else return false end end function getThroughputType() throughput_type = ntop.getCache("ntopng.prefs.thpt_content") if(throughput_type == "") then throughput_type = "bps" end return throughput_type end function isLoopback(name) if((name == "lo") or (name == "lo0")) then return(true) else return(false) end end function processColor(proc) if(proc == nil) then return("") elseif(proc["average_cpu_load"] < 33) then return(""..proc["name"].."") elseif(proc["average_cpu_load"] < 66) then return(""..proc["name"].."") else return(""..proc["name"].."") end end -- Table preferences function getDefaultTableSort(table_type) table_key = getRedisPrefix("ntopng.prefs.table") if(table_type ~= nil) then value = ntop.getHashCache(table_key, "sort_"..table_type) end if((value == nil) or (value == "")) then value = 'column_' end return(value) end function getDefaultTableSortOrder(table_type) table_key = getRedisPrefix("ntopng.prefs.table") if(table_type ~= nil) then value = ntop.getHashCache(table_key, "sort_order_"..table_type) end if((value == nil) or (value == "")) then value = 'desc' end return(value) end function getDefaultTableSize() table_key = getRedisPrefix("ntopng.prefs.table") value = ntop.getHashCache(table_key, "rows_number") if((value == nil) or (value == "")) then value = 10 end return(tonumber(value)) end function tablePreferences(key, value) table_key = getRedisPrefix("ntopng.prefs.table") if((value == nil) or (value == "")) then -- Get preferences return ntop.getHashCache(table_key, key) else -- Set preferences ntop.setHashCache(table_key, key, value) return(value) end end function getHumanReadableInterfaceName(interface_id) key = 'ntopng.prefs.'..interface_id..'.name' custom_name = ntop.getCache(key) if((custom_name ~= nil) and (custom_name ~= "")) then return(custom_name) else interface.select(interface_id) ifstats = interface.getStats() -- print(interface_id.."="..ifstats.name) if((interface_id ~= ifstats.description) and (ifstats.description ~= "PF_RING")) then return(ifstats.description) else return(ifstats.name) end end end function escapeHTML(s) s = string.gsub(s, "([&=+%c])", function (c) return string.format("%%%02X", string.byte(c)) end) s = string.gsub(s, " ", "+") return s end function unescapeHTML (s) s = string.gsub(s, "+", " ") s = string.gsub(s, "%%(%x%x)", function (h) return string.char(tonumber(h, 16)) end) return s end -- ############################################## function harvestUnusedDir(path, min_epoch) local files = ntop.readdir(path) -- print("Reading "..path.."
\n") for k,v in pairs(files) do if(v ~= nil) then local p = fixPath(path .. "/" .. v) if(ntop.isdir(p)) then harvestUnusedDir(p, min_epoch) else local when = ntop.fileLastChange(path) if((when ~= -1) and (when < min_epoch)) then os.remove(p) end end end end end -- ############################################## function harvestJSONTopTalkers(days) local when = os.time() - 86400 * days ifnames = interface.getIfNames() for _,ifname in pairs(ifnames) do interface.select(ifname) local ifstats = interface.getStats() local dirs = ntop.getDirs() local basedir = fixPath(dirs.workingdir .. "/" .. ifstats.id) harvestUnusedDir(fixPath(basedir .. "/top_talkers"), when) harvestUnusedDir(fixPath(basedir .. "/flows"), when) end end -- ############################################## function isAdministrator() local user_group = ntop.getUserGroup() if(user_group == "administrator") then return(true) else return(false) end end -- ############################################## function haveAdminPrivileges() if(isAdministrator) then return(true) else ntop.dumpFile(dirs.installdir .. "/httpdocs/inc/header.inc") dofile(dirs.installdir .. "/scripts/lua/inc/menu.lua") print("
Access forbidden
") return(false) end end -- ############################################## function getKeysSortedByValue(tbl, sortFunction) local keys = {} for key in pairs(tbl) do table.insert(keys, key) end table.sort(keys, function(a, b) return sortFunction(tbl[a], tbl[b]) end) return keys end function getKeys(t, col) local keys = {} for k,v in pairs(t) do keys[tonumber(v[col])] = k end return keys end -- ############################################## function formatBreed(breed) if(breed == "Safe") then return("") elseif(breed == "Acceptable") then return("") elseif(breed == "Fun") then return("") elseif(breed == "Unsafe") then return("") elseif(breed == "Dangerous") then return("") else return("") end end function getFlag(country) if((country == nil) or (country == "")) then return("") else return(" ") end end -- GENERIC UTILS -- ternary function ternary(cond, T, F) if cond then return T else return F end end -- split function split(s, delimiter) result = {}; for match in (s..delimiter):gmatch("(.-)"..delimiter) do table.insert(result, match); end return result; end -- startswith function startswith(s, char) return string.sub(s, 1, string.len(s)) == char end -- strsplit function strsplit(inputstr, sep) if (inputstr == nil or inputstr == "") then return {} end if sep == nil then sep = "%s" end local t={} ; i=1 for str in string.gmatch(inputstr, "([^"..sep.."]+)") do t[i] = str i = i + 1 end return t end -- isempty function isempty(array) local count = 0 for _,__ in pairs(array) do count = count + 1 end return (count == 0) end -- isin function isin(s, array) if (s == nil or s == "" or array == nil or isempty(array)) then return false end for _, v in pairs(array) do if (s == v) then return true end end return false end -- maxRateToString function maxRateToString(max_rate) if((max_rate == nil) or (max_rate == "")) then max_rate = -1 end max_rate = tonumber(max_rate) if(max_rate == -1) then return("No Limit") else if(max_rate == 0) then return("Drop All Traffic") else if(max_rate < 1024) then return(max_rate.." Kbps") else local mr mr = round(max_rate / 1024, 2) return(mr.." Mbps") end end end end -- makeTopStatsScriptsArray function makeTopStatsScriptsArray() path = dirs.installdir .. "/scripts/lua/modules/top_scripts" path = fixPath(path) local files = ntop.readdir(path) topArray = {} for k,v in pairs(files) do if(v ~= nil) then value = {} fn,ext = v:match("([^.]+).([^.]+)") mod = require("top_scripts."..fn) if(type(mod) ~= type(true)) then value["name"] = mod.name value["script"] = mod.infoScript value["key"] = mod.infoScriptKey value["levels"] = mod.numLevels topArray[fn] = value end end end return(topArray) end local mac_cache = { } -- get_mac_classification function get_mac_classification(m) local path = fixPath(dirs.installdir.."/httpdocs/other/EtherOUI.txt") local file_mac if(string.len(m) > 8) then m = string.sub(m, 1, 8) end if(mac_cache[m] ~= nil) then -- io.write("Cached "..m.."\n") return(mac_cache[m]) end file_mac = io.open(path) if (file_mac == nil) then return m end local mac_line = file_mac:read("*l") while (mac_line ~= nil) do if (not startswith(mac_line, "#") and mac_line ~= "") then b = string.sub(mac_line, 1, 8) if (m == b) then t = split(mac_line, "\t") file_mac.close() rsp = split(t[2], " ")[1] mac_cache[m] = rsp return rsp end end mac_line = file_mac:read("*l") end file_mac.close() return m end local magic_macs = { ["FF:FF:FF:FF:FF:FF"] = "Broadcast", ["01:00:0C:CC:CC:CC"] = "CDP", ["01:00:0C:CC:CC:CD"] = "CiscoSTP", ["01:80:C2:00:00:00"] = "STP", ["01:80:C2:00:00:00"] = "LLDP", ["01:80:C2:00:00:03"] = "LLDP", ["01:80:C2:00:00:0E"] = "LLDP", ["01:80:C2:00:00:08"] = "STP", ["01:1B:19:00:00:00"] = "PTP", ["01:80:C2:00:00:0E"] = "PTP" } local magic_short_macs = { ["01:00:5E"] = "IPv4mcast", ["33:33:"] = "IPv6mcast" } -- get_symbolic_mac function get_symbolic_mac(mac_address) if(magic_macs[mac_address] ~= nil) then return(magic_macs[mac_address]) else local m = string.sub(mac_address, 1, 8) local t = string.sub(mac_address, 10, 17) if(magic_short_macs[m] ~= nil) then return(magic_short_macs[m].."_"..t.." ("..mac_address..")") else local s = get_mac_classification(m) if(m == s) then return(get_mac_classification(m)..":"..t) else return(get_mac_classification(m).."_"..t.." ("..mac_address..")") end end end end -- rrd_exists function rrd_exists(host_ip, rrdname) dirs = ntop.getDirs() rrdpath = dirs.workingdir .. "/" .. ifId .. "/rrd/" .. getPathFromKey(host_ip) .. "/" .. rrdname return ntop.exists(rrdpath) end -- getservbyport function getservbyport(port_num, proto) if(proto == nil) then proto = "TCP" end port_num = tonumber(port_num) proto = string.lower(proto) -- io.write(port_num.."@"..proto.."\n") return(ntop.getservbyport(port_num, proto)) end