--
-- (C) 2013-20 - ntop.org
--
local dirs = ntop.getDirs()
package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path
local shaper_utils
require "lua_utils"
require "alert_utils"
local format_utils = require "format_utils"
local have_nedge = ntop.isnEdge()
local NfConfig = nil
local flow_consts = require "flow_consts"
require "flow_utils"
if ntop.isPro() then
package.path = dirs.installdir .. "/scripts/lua/pro/modules/?.lua;" .. package.path
shaper_utils = require("shaper_utils")
if ntop.isnEdge() then
package.path = dirs.installdir .. "/scripts/lua/pro/nedge/modules/?.lua;" .. package.path
NfConfig = require("nf_config")
end
end
require "historical_utils"
require "flow_utils"
require "voip_utils"
local template = require "template_utils"
local categories_utils = require "categories_utils"
local protos_utils = require("protos_utils")
local discover = require("discover_utils")
local json = require ("dkjson")
local page_utils = require("page_utils")
local user_scripts = require("user_scripts")
local tls_cipher_suites = {
TLS_NULL_WITH_NULL_NULL=0x000000,
TLS_RSA_WITH_NULL_MD5=0x000001,
TLS_RSA_WITH_NULL_SHA=0x000002,
TLS_RSA_EXPORT_WITH_RC4_40_MD5=0x000003,
TLS_RSA_WITH_RC4_128_MD5=0x000004,
TLS_RSA_WITH_RC4_128_SHA=0x000005,
TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5=0x000006,
TLS_RSA_WITH_IDEA_CBC_SHA=0x000007,
TLS_RSA_EXPORT_WITH_DES40_CBC_SHA=0x000008,
TLS_RSA_WITH_DES_CBC_SHA=0x000009,
TLS_RSA_WITH_3DES_EDE_CBC_SHA=0x00000a,
TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA=0x00000b,
TLS_DH_DSS_WITH_DES_CBC_SHA=0x00000c,
TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA=0x00000d,
TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA=0x00000e,
TLS_DH_RSA_WITH_DES_CBC_SHA=0x00000f,
TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA=0x000010,
TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA=0x000011,
TLS_DHE_DSS_WITH_DES_CBC_SHA=0x000012,
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA=0x000013,
TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA=0x000014,
TLS_DHE_RSA_WITH_DES_CBC_SHA=0x000015,
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA=0x000016,
TLS_DH_anon_EXPORT_WITH_RC4_40_MD5=0x000017,
TLS_DH_anon_WITH_RC4_128_MD5=0x000018,
TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA=0x000019,
TLS_DH_anon_WITH_DES_CBC_SHA=0x00001a,
TLS_DH_anon_WITH_3DES_EDE_CBC_SHA=0x00001b,
SSL_FORTEZZA_KEA_WITH_NULL_SHA=0x00001c,
SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA=0x00001d,
SSL_FORTEZZA_KEA_WITH_RC4_128_SHA=0x00001e,
TLS_KRB5_WITH_DES_CBC_SHA=0x00001E,
TLS_KRB5_WITH_3DES_EDE_CBC_SHA=0x00001F,
TLS_KRB5_WITH_RC4_128_SHA=0x000020,
TLS_KRB5_WITH_IDEA_CBC_SHA=0x000021,
TLS_KRB5_WITH_DES_CBC_MD5=0x000022,
TLS_KRB5_WITH_3DES_EDE_CBC_MD5=0x000023,
TLS_KRB5_WITH_RC4_128_MD5=0x000024,
TLS_KRB5_WITH_IDEA_CBC_MD5=0x000025,
TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA=0x000026,
TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA=0x000027,
TLS_KRB5_EXPORT_WITH_RC4_40_SHA=0x000028,
TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5=0x000029,
TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5=0x00002A,
TLS_KRB5_EXPORT_WITH_RC4_40_MD5=0x00002B,
TLS_PSK_WITH_NULL_SHA=0x00002C,
TLS_DHE_PSK_WITH_NULL_SHA=0x00002D,
TLS_RSA_PSK_WITH_NULL_SHA=0x00002E,
TLS_RSA_WITH_AES_128_CBC_SHA=0x00002f,
TLS_DH_DSS_WITH_AES_128_CBC_SHA=0x000030,
TLS_DH_RSA_WITH_AES_128_CBC_SHA=0x000031,
TLS_DHE_DSS_WITH_AES_128_CBC_SHA=0x000032,
TLS_DHE_RSA_WITH_AES_128_CBC_SHA=0x000033,
TLS_DH_anon_WITH_AES_128_CBC_SHA=0x000034,
TLS_RSA_WITH_AES_256_CBC_SHA=0x000035,
TLS_DH_DSS_WITH_AES_256_CBC_SHA=0x000036,
TLS_DH_RSA_WITH_AES_256_CBC_SHA=0x000037,
TLS_DHE_DSS_WITH_AES_256_CBC_SHA=0x000038,
TLS_DHE_RSA_WITH_AES_256_CBC_SHA=0x000039,
TLS_DH_anon_WITH_AES_256_CBC_SHA=0x00003A,
TLS_RSA_WITH_NULL_SHA256=0x00003B,
TLS_RSA_WITH_AES_128_CBC_SHA256=0x00003C,
TLS_RSA_WITH_AES_256_CBC_SHA256=0x00003D,
TLS_DH_DSS_WITH_AES_128_CBC_SHA256=0x00003E,
TLS_DH_RSA_WITH_AES_128_CBC_SHA256=0x00003F,
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256=0x000040,
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA=0x000041,
TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA=0x000042,
TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA=0x000043,
TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA=0x000044,
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA=0x000045,
TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA=0x000046,
TLS_ECDH_ECDSA_WITH_NULL_SHA=0x000047,
TLS_ECDH_ECDSA_WITH_RC4_128_SHA=0x000048,
TLS_ECDH_ECDSA_WITH_DES_CBC_SHA=0x000049,
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA=0x00004A,
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA=0x00004B,
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA=0x00004C,
TLS_RSA_EXPORT1024_WITH_RC4_56_MD5=0x000060,
TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5=0x000061,
TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA=0x000062,
TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA=0x000063,
TLS_RSA_EXPORT1024_WITH_RC4_56_SHA=0x000064,
TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA=0x000065,
TLS_DHE_DSS_WITH_RC4_128_SHA=0x000066,
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256=0x000067,
TLS_DH_DSS_WITH_AES_256_CBC_SHA256=0x000068,
TLS_DH_RSA_WITH_AES_256_CBC_SHA256=0x000069,
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256=0x00006A,
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256=0x00006B,
TLS_DH_anon_WITH_AES_128_CBC_SHA256=0x00006C,
TLS_DH_anon_WITH_AES_256_CBC_SHA256=0x00006D,
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA=0x000084,
TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA=0x000085,
TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA=0x000086,
TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA=0x000087,
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA=0x000088,
TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA=0x000089,
TLS_PSK_WITH_RC4_128_SHA=0x00008A,
TLS_PSK_WITH_3DES_EDE_CBC_SHA=0x00008B,
TLS_PSK_WITH_AES_128_CBC_SHA=0x00008C,
TLS_PSK_WITH_AES_256_CBC_SHA=0x00008D,
TLS_DHE_PSK_WITH_RC4_128_SHA=0x00008E,
TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA=0x00008F,
TLS_DHE_PSK_WITH_AES_128_CBC_SHA=0x000090,
TLS_DHE_PSK_WITH_AES_256_CBC_SHA=0x000091,
TLS_RSA_PSK_WITH_RC4_128_SHA=0x000092,
TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA=0x000093,
TLS_RSA_PSK_WITH_AES_128_CBC_SHA=0x000094,
TLS_RSA_PSK_WITH_AES_256_CBC_SHA=0x000095,
TLS_RSA_WITH_SEED_CBC_SHA=0x000096,
TLS_DH_DSS_WITH_SEED_CBC_SHA=0x000097,
TLS_DH_RSA_WITH_SEED_CBC_SHA=0x000098,
TLS_DHE_DSS_WITH_SEED_CBC_SHA=0x000099,
TLS_DHE_RSA_WITH_SEED_CBC_SHA=0x00009A,
TLS_DH_anon_WITH_SEED_CBC_SHA=0x00009B,
TLS_RSA_WITH_AES_128_GCM_SHA256=0x00009C,
TLS_RSA_WITH_AES_256_GCM_SHA384=0x00009D,
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256=0x00009E,
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384=0x00009F,
TLS_DH_RSA_WITH_AES_128_GCM_SHA256=0x0000A0,
TLS_DH_RSA_WITH_AES_256_GCM_SHA384=0x0000A1,
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256=0x0000A2,
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384=0x0000A3,
TLS_DH_DSS_WITH_AES_128_GCM_SHA256=0x0000A4,
TLS_DH_DSS_WITH_AES_256_GCM_SHA384=0x0000A5,
TLS_DH_anon_WITH_AES_128_GCM_SHA256=0x0000A6,
TLS_DH_anon_WITH_AES_256_GCM_SHA384=0x0000A7,
TLS_PSK_WITH_AES_128_GCM_SHA256=0x0000A8,
TLS_PSK_WITH_AES_256_GCM_SHA384=0x0000A9,
TLS_DHE_PSK_WITH_AES_128_GCM_SHA256=0x0000AA,
TLS_DHE_PSK_WITH_AES_256_GCM_SHA384=0x0000AB,
TLS_RSA_PSK_WITH_AES_128_GCM_SHA256=0x0000AC,
TLS_RSA_PSK_WITH_AES_256_GCM_SHA384=0x0000AD,
TLS_PSK_WITH_AES_128_CBC_SHA256=0x0000AE,
TLS_PSK_WITH_AES_256_CBC_SHA384=0x0000AF,
TLS_PSK_WITH_NULL_SHA256=0x0000B0,
TLS_PSK_WITH_NULL_SHA384=0x0000B1,
TLS_DHE_PSK_WITH_AES_128_CBC_SHA256=0x0000B2,
TLS_DHE_PSK_WITH_AES_256_CBC_SHA384=0x0000B3,
TLS_DHE_PSK_WITH_NULL_SHA256=0x0000B4,
TLS_DHE_PSK_WITH_NULL_SHA384=0x0000B5,
TLS_RSA_PSK_WITH_AES_128_CBC_SHA256=0x0000B6,
TLS_RSA_PSK_WITH_AES_256_CBC_SHA384=0x0000B7,
TLS_RSA_PSK_WITH_NULL_SHA256=0x0000B8,
TLS_RSA_PSK_WITH_NULL_SHA384=0x0000B9,
TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256=0x0000BA,
TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256=0x0000BB,
TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256=0x0000BC,
TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256=0x0000BD,
TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256=0x0000BE,
TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256=0x0000BF,
TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256=0x0000C0,
TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256=0x0000C1,
TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256=0x0000C2,
TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256=0x0000C3,
TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256=0x0000C4,
TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256=0x0000C5,
TLS_EMPTY_RENEGOTIATION_INFO_SCSV=0x0000FF,
TLS_ECDH_ECDSA_WITH_NULL_SHA=0x00c001,
TLS_ECDH_ECDSA_WITH_RC4_128_SHA=0x00c002,
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA=0x00c003,
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA=0x00c004,
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA=0x00c005,
TLS_ECDHE_ECDSA_WITH_NULL_SHA=0x00c006,
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA=0x00c007,
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA=0x00c008,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA=0x00c009,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA=0x00c00a,
TLS_ECDH_RSA_WITH_NULL_SHA=0x00c00b,
TLS_ECDH_RSA_WITH_RC4_128_SHA=0x00c00c,
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA=0x00c00d,
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA=0x00c00e,
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA=0x00c00f,
TLS_ECDHE_RSA_WITH_NULL_SHA=0x00c010,
TLS_ECDHE_RSA_WITH_RC4_128_SHA=0x00c011,
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA=0x00c012,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA=0x00c013,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA=0x00c014,
TLS_ECDH_anon_WITH_NULL_SHA=0x00c015,
TLS_ECDH_anon_WITH_RC4_128_SHA=0x00c016,
TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA=0x00c017,
TLS_ECDH_anon_WITH_AES_128_CBC_SHA=0x00c018,
TLS_ECDH_anon_WITH_AES_256_CBC_SHA=0x00c019,
TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA=0x00C01A,
TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA=0x00C01B,
TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA=0x00C01C,
TLS_SRP_SHA_WITH_AES_128_CBC_SHA=0x00C01D,
TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA=0x00C01E,
TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA=0x00C01F,
TLS_SRP_SHA_WITH_AES_256_CBC_SHA=0x00C020,
TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA=0x00C021,
TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA=0x00C022,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256=0x00C023,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384=0x00C024,
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256=0x00C025,
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384=0x00C026,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=0x00C027,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384=0x00C028,
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256=0x00C029,
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384=0x00C02A,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256=0x00C02B,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384=0x00C02C,
TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256=0x00C02D,
TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384=0x00C02E,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256=0x00C02F,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384=0x00C030,
TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256=0x00C031,
TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384=0x00C032,
TLS_ECDHE_PSK_WITH_RC4_128_SHA=0x00C033,
TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA=0x00C034,
TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA=0x00C035,
TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA=0x00C036,
TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256=0x00C037,
TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384=0x00C038,
TLS_ECDHE_PSK_WITH_NULL_SHA=0x00C039,
TLS_ECDHE_PSK_WITH_NULL_SHA256=0x00C03A,
TLS_ECDHE_PSK_WITH_NULL_SHA384=0x00C03B,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256=0x00CC13,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256=0x00CC14,
TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256=0x00CC15,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256=0x00CCA8,
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256=0x00CCA9,
TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256=0x00CCAA,
TLS_PSK_WITH_CHACHA20_POLY1305_SHA256=0x00CCAB,
TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256=0x00CCAC,
TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256=0x00CCAD,
TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256=0x00CCAE,
TLS_RSA_WITH_ESTREAM_SALSA20_SHA1=0x00E410,
TLS_RSA_WITH_SALSA20_SHA1=0x00E411,
TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1=0x00E412,
TLS_ECDHE_RSA_WITH_SALSA20_SHA1=0x00E413,
TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1=0x00E414,
TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1=0x00E415,
TLS_PSK_WITH_ESTREAM_SALSA20_SHA1=0x00E416,
TLS_PSK_WITH_SALSA20_SHA1=0x00E417,
TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1=0x00E418,
TLS_ECDHE_PSK_WITH_SALSA20_SHA1=0x00E419,
TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1=0x00E41A,
TLS_RSA_PSK_WITH_SALSA20_SHA1=0x00E41B,
TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1=0x00E41C,
TLS_DHE_PSK_WITH_SALSA20_SHA1=0x00E41D,
TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1=0x00E41E,
TLS_DHE_RSA_WITH_SALSA20_SHA1=0x00E41F,
SSL_RSA_FIPS_WITH_DES_CBC_SHA=0x00fefe,
SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA=0x00feff,
SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA=0x00ffe0,
SSL_RSA_FIPS_WITH_DES_CBC_SHA=0x00ffe1,
SSL2_RC4_128_WITH_MD5=0x010080,
SSL2_RC4_128_EXPORT40_WITH_MD5=0x020080,
SSL2_RC2_128_CBC_WITH_MD5=0x030080,
SSL2_RC2_128_CBC_EXPORT40_WITH_MD5=0x040080,
SSL2_IDEA_128_CBC_WITH_MD5=0x050080,
SSL2_DES_64_CBC_WITH_MD5=0x060040,
SSL2_DES_192_EDE3_CBC_WITH_MD5=0x0700c0,
SSL2_RC4_64_WITH_MD5=0x080080,
}
function tlsVersion2Str(v)
-- TODO: Use ndpi_ssl_version2str()
if(v == 768) then
return("SSL v3")
elseif(v == 769) then
return("TLS v1");
elseif(v == 770) then
return("TLS v1.1");
elseif(v == 771) then
return("TLS v1.2");
elseif(v == 772) then
return("TLS v1.3");
elseif(v == 64282) then
return("TLS v1.3 (Fizz)");
elseif(v == 65279) then
return("DTLS v1.0");
elseif(v == 65277) then
return("DTLS v1.2");
else
return("TLS "..flow["protos.tls_version"])
end
end
local function cipher2str(c)
if(c == nil) then return end
for s,v in pairs(tls_cipher_suites) do
if(v == c) then
return(''..s..'')
end
end
return(c)
end
local function ja3url(what, safety)
if(what == nil) then
print(" ")
else
ret = ''..what..' '
if((safety ~= nil) and (safety ~= "safe")) then
ret = ret .. ' [ '..capitalize(safety)..' Cipher ]'
end
print(ret)
end
end
sendHTTPContentTypeHeader('text/html')
warn_shown = 0
local alert_banners = {}
if isAdministrator() then
if _POST["custom_hosts"] and _POST["l7proto"] then
local proto_id = tonumber(_POST["l7proto"])
local proto_name = interface.getnDPIProtoName(proto_id)
if protos_utils.addAppRule(proto_name, {match="host", value=_POST["custom_hosts"]}) then
local info = ntop.getInfo()
alert_banners[#alert_banners + 1] = {
type = "success",
text = i18n("custom_categories.protos_reboot_necessary", {product=info.product})
}
else
alert_banners[#alert_banners + 1] = {
type="danger",
text=i18n("flow_details.could_not_add_host_to_category",
{host=_POST["custom_hosts"], category=proto_name})
}
end
elseif _POST["custom_hosts"] and _POST["category"] then
local lists_utils = require("lists_utils")
local category_id = tonumber(split(_POST["category"], "cat_")[2])
if categories_utils.addCustomCategoryHost(category_id, _POST["custom_hosts"]) then
lists_utils.reloadLists()
alert_banners[#alert_banners + 1] = {
type="success",
text=i18n("flow_details.host_successfully_added_to_category",
{host=_POST["custom_hosts"], category=interface.getnDPICategoryName(category_id),
url = ntop.getHttpPrefix() .. "/lua/admin/edit_categories.lua?l7proto=" .. category_id})
}
else
alert_banners[#alert_banners + 1] = {
type="danger",
text=i18n("flow_details.could_not_add_host_to_category",
{host=_POST["custom_hosts"], category=interface.getnDPICategoryName(category_id)})
}
end
end
end
local function printAddCustomHostRule(full_url)
if not isAdministrator() then
return
end
local categories = interface.getnDPICategories()
local protocols = interface.getnDPIProtocols()
local short_url = categories_utils.getSuggestedHostName(full_url)
-- Fill the category dropdown
local cat_select_dropdown = '"
-- Fill the application dropdown
local app_select_dropdown = '"
-- Put a note if the URL is already assigned to another customized category
local existing_note = ""
local matched_category = ntop.matchCustomCategory(full_url)
existing_note = "
" ..
i18n("flow_details.existing_rules_note",
{name=i18n("custom_categories.apps_and_categories"), url=ntop.getHttpPrefix().."/lua/admin/edit_categories.lua"})
if matched_category ~= nil then
existing_note = existing_note .. "
" .. i18n("details.note") .. ": " ..
i18n("custom_categories.similar_host_found", {host=full_url, category=interface.getnDPICategoryName(matched_category)}) ..
"
"
end
local rule_type_selection = ""
if protos_utils.hasProtosFile() then
rule_type_selection = i18n("flow_details.rule_type")..":"..[[
]]
end
print(
template.gen("modal_confirm_dialog.html", {
dialog={
id = "add_to_customized_categories",
action = "addToCustomizedCategories()",
custom_alert_class = "",
custom_dialog_class = "dialog-body-full-height",
title = i18n("custom_categories.custom_host_category"),
message = rule_type_selection .. i18n("custom_categories.select_url_category") .. "
" ..
cat_select_dropdown .. app_select_dropdown .. "
" .. i18n("custom_categories.the_following_url_will_be_added") ..
'
' .. existing_note,
confirm = i18n("custom_categories.add"),
cancel = i18n("cancel"),
}
})
)
print(' ')
print[[]]
end
local function displayContainer(cont, label)
print(label)
if not isEmptyString(cont["id"]) then
-- short 12-chars UUID as in docker
print("
| ") print(i18n("details.vlan_id")) print(" | " .. flow["vlan"].. " | |||
|---|---|---|---|---|
| "..i18n("flow_details.flow_peers_client_server").." | "..getFlowLabel(flow, true, not ifstats.isViewed --[[ don't add hyperlinks, viewed interface don't have hosts --]], nil, nil, true --[[ add flags ]]).." | |||
| "..i18n("protocol").." / "..i18n("application").." | ") if((ifstats.inline and flow["verdict.pass"]) or (flow.vrfId ~= nil)) then print("") else print(" | ")
end
if(flow["verdict.pass"] == false) then print(" | ')
if(flow.vrfId ~= nil) then
print("VRF Id "..flow.vrfId.." | ") end print("|
| "..i18n("flow_details.flow_shapers").." | ") c = flowinfo2hostname(flow,"cli") s = flowinfo2hostname(flow,"srv") if flow["cli.pool_id"] ~= nil then c = c .. " (".. host_pools_utils.poolIdToUsername(flow["cli.pool_id"]) ..")" end if flow["srv.pool_id"] ~= nil then s = s .. " (".. host_pools_utils.poolIdToUsername(flow["srv.pool_id"]) ..")" end local shaper = shaper_utils.nedge_shaper_id_to_shaper(flow["shaper.cli2srv_egress"]) print(""..c.." | ".. shaper.icon .. " " .. shaper.text .." | "..s.." | ".. shaper.icon .. " " .. shaper.text.." | ") print("") if flow["cli.pool_id"] ~= nil and flow["srv.pool_id"] ~= nil then print("
| "..i18n("flow_details.flow_quota").." | ") print(""..c.." | ") print("") printFlowQuota(ifstats.id, flow, true --[[ client ]]) print(" | "..s.." | ") print("") printFlowQuota(ifstats.id, flow, false --[[ server ]]) print(" | ") print("") end -- ENABLE MARKER DEBUG if ntop.isnEdge() and false then print("
| "..i18n("flow_details.flow_marker").." | ") print("".. NfConfig.formatMarker(flow["marker"]) .." | ") print("|||
| "..i18n("device_protocols.device_protocol_policy").." | ") if cli_show then print(""..i18n("device_protocols.devtype_as_proto_client", {devtype=discover.devtype2string(flow["cli.devtype"]), proto=interface.getnDPIProtoName(forbidden_proto)}).." | ") print("") print(i18n(ternary(forbidden_peer ~= "cli", "allowed", "forbidden"))) print(" | ||
| "..i18n("device_protocols.devtype_as_proto_server", {devtype=discover.devtype2string(flow["srv.devtype"]), proto=interface.getnDPIProtoName(forbidden_proto)}).." | ") print("") print(i18n(ternary(forbidden_peer ~= "srv", "allowed", "forbidden"))) print(" | |||
| "..i18n("details.first_last_seen").." | "
.. formatEpoch(flow["seen.first"]) .. " [" .. secondsToTime(os.time()-flow["seen.first"]) .. " "..i18n("details.ago").."]" .. " | \n")
print("" .. formatEpoch(flow["seen.last"]) .. " [" .. secondsToTime(os.time()-flow["seen.last"]) .. " "..i18n("details.ago").."]" .. " | ||
| "..i18n("details.total_traffic").." | "..i18n("total")..": " .. bytesToSize(flow["bytes"]) .. " | ") if((ifstats.type ~= "zmq") and ((flow["proto.l4"] == "TCP") or (flow["proto.l4"] == "UDP")) and (flow["goodput_bytes"] > 0)) then print(""..i18n("details.goodput")..": " .. bytesToSize(flow["goodput_bytes"]) .. " (") pctg = round(((flow["goodput_bytes"]*100)/flow["bytes"]), 2) if(pctg < 50) then pctg = ""..pctg.."" elseif(pctg < 60) then pctg = ""..pctg.."" end print(pctg.."") print(" %) | \n") end print(" | |
| " .. i18n("client") .. " " .. i18n("server") .. ": " .. formatPackets(flow["cli2srv.packets"]) .. " / ".. bytesToSize(flow["cli2srv.bytes"]) .. " | " .. i18n("client") .. " " .. i18n("server") .. ": " .. formatPackets(flow["srv2cli.packets"]) .. " / ".. bytesToSize(flow["srv2cli.bytes"]) .. " | |||
| ")
cli2srv = round((flow["cli2srv.bytes"] * 100) / flow["bytes"], 0)
local cli_name = shortHostName(flowinfo2hostname(flow, "cli"))
local srv_name = shortHostName(flowinfo2hostname(flow, "srv"))
if(flow["cli.port"] > 0) then
cli_name = cli_name .. ":" .. flow["cli.port"]
srv_name = srv_name .. ":" .. flow["srv.port"]
end
print(' ')
print(" | ||||
| "..i18n("flow_details.rtt_breakdown").." | ")
print(' ')
print(' ')
print(" | |||
| "..i18n("flow_details.rtt_distance").." | ") local c_vacuum_km_s = 299792 local c_vacuum_mi_s = 186000 local fiber_vf = .67 local delta_t = rtt/1000 local dd_fiber_km = delta_t * c_vacuum_km_s * fiber_vf local dd_fiber_mi = delta_t * c_vacuum_mi_s * fiber_vf print(formatValue(toint(dd_fiber_km)).." Km | "..formatValue(toint(dd_fiber_mi)).." Miles") print(" | ||
| "..i18n("flow_details.application_latency").." | "..msToTime(flow["tcp.appl_latency"]).." | |||
| "..i18n("flow_details.packet_inter_arrival_time").." | "..i18n("client").." "..i18n("server")..": ") print(msToTime(flow["interarrival.cli2srv"]["min"]).." / "..msToTime(flow["interarrival.cli2srv"]["avg"]).." / "..msToTime(flow["interarrival.cli2srv"]["max"])) print(" | \n") if(flow["srv2cli.packets"] < 2) then print("") else print(" | "..i18n("client").." "..i18n("server")..": ") print(msToTime(flow["interarrival.srv2cli"]["min"]).." / "..msToTime(flow["interarrival.srv2cli"]["avg"]).." / "..msToTime(flow["interarrival.srv2cli"]["max"])) end print(" | |
| "..i18n("flow_details.looks_like_idle_flow_message").." | ||||
| "..i18n("flow_details.ip_packet_analysis").." | ") print(""..i18n("client").." "..i18n("server").." / "..i18n("client").." "..i18n("server").." | |||
| "..i18n("details.fragments").." | ".. formatPackets(flow["cli2srv.fragments"]) .." / ".. formatPackets(flow["srv2cli.fragments"]) .." | |||
| "..i18n("flow_details.tcp_packet_analysis").." | ") print(""..i18n("client").." "..i18n("server").." / "..i18n("client").." "..i18n("server").." | |||
| "..i18n("details.retransmissions").." | ".. formatPackets(flow["cli2srv.retransmissions"]) .." / ".. formatPackets(flow["srv2cli.retransmissions"]) .." | |||
| "..i18n("details.out_of_order").." | ".. formatPackets(flow["cli2srv.out_of_order"]) .." / ".. formatPackets(flow["srv2cli.out_of_order"]) .." | |||
| "..i18n("details.lost").." | ".. formatPackets(flow["cli2srv.lost"]) .." / ".. formatPackets(flow["srv2cli.lost"]) .." | |||
| "..i18n("details.keep_alive").." | ".. formatPackets(flow["cli2srv.keep_alive"]) .." / ".. formatPackets(flow["srv2cli.keep_alive"]) .." | |||
| "..i18n("flow_details.tls_certificate").." | ")
print(i18n("flow_details.client_requested")..": ") print(""..flow["protos.tls.client_requested_server_name"].." ") if(flow["category"] ~= nil) then print(" "..getCategoryIcon(flow["protos.tls.client_requested_server_name"], flow["category"])) end historicalProtoHostHref(ifid, nil, nil, nil, flow["protos.tls.client_requested_server_name"]) printAddCustomHostRule(flow["protos.tls.client_requested_server_name"]) print(" | ")
print("")
if(flow["protos.tls.server_names"] ~= nil) then
local servers = string.split(flow["protos.tls.server_names"], ",") or {flow["protos.tls.server_names"]}
print(i18n("flow_details.tls_server_names")..": ") for i, server in ipairs(servers) do if i > 1 then print(" ") end if starts(server, '*') then print(server) else print(""..server.." ") end end if(ntop.bitmapIsSet(flow["status_map"], flow_consts.status_types.status_tls_certificate_mismatch.status_id)) then print("\n "..i18n("flow_details.certificates_not_match").."") end end print(" | ")
print("||
| '..i18n("flow_details.tls_certificate_validity").." | ") if((flow["protos.tls.notBefore"] > now) or (flow["protos.tls.notAfter"] < now)) then print(" ") end print(formatEpoch(flow["protos.tls.notBefore"])) print(" - ") print(formatEpoch(flow["protos.tls.notAfter"])) print(" | |||
| JA3 | ') if(flow["protos.tls.ja3.client_malicious"]) then print(' ') end ja3url(flow["protos.tls.ja3.client_hash"], nil) print(" | ") if(flow["protos.tls.ja3.server_malicious"]) then print(' ') end ja3url(flow["protos.tls.ja3.server_hash"], flow["protos.tls.ja3.server_unsafe_cipher"]) --print(cipher2str(flow["protos.tls.ja3.server_cipher"])) print(" | ||
| TLS ALPN | '..flow["protos.tls.client_alpn"]..' | |||
| '.. i18n("flow_details.client_tls_supported_versions") ..' | '..flow["protos.tls.client_tls_supported_versions"]..' | |||
| ".. ''.. i18n("flow_details.max_estimated_tcp_throughput").." | "..i18n("client").." "..i18n("server")..": ") print(bitsToSize(flow["tcp.max_thpt.cli2srv"])) print(" | "..i18n("client").." "..i18n("server")..": ") print(bitsToSize(flow["tcp.max_thpt.srv2cli"])) print(" | ||
| "..i18n("flow_details.throughput_trend").." | "..flow["cli.ip"].." "..flow["srv.ip"]..": ") print(flow["cli2srv.trend"]) print(" | "..flow["cli.ip"].." "..flow["srv.ip"]..": ") print(flow["srv2cli.trend"]) print(" | ||
| "..i18n("tcp_flags").." | "..i18n("client").." "..i18n("server")..": ") printTCPFlags(flow["cli2srv.tcp_flags"]) print(" | "..i18n("client").." "..i18n("server")..": ") printTCPFlags(flow["srv2cli.tcp_flags"]) print(" | ||
| ") local flow_msg = "" if flow["tcp_reset"] then local resetter = "" if(hasbit(flow["cli2srv.tcp_flags"],0x04)) then resetter = "client" else resetter = "server" end flow_msg = flow_msg..i18n("flow_details.flow_reset_by_resetter_msg",{resetter = resetter}) elseif flow["tcp_closed"] then flow_msg = flow_msg..i18n("flow_details.flow_completed_msg") elseif flow["tcp_connecting"] then flow_msg = flow_msg..i18n("flow_details.flow_connecting_msg") elseif flow["tcp_established"] then flow_msg = flow_msg..i18n("flow_details.flow_active_msg") else flow_msg = flow_msg.." "..i18n("flow_details.flow_peer_roles_inaccurate_msg") end print(flow_msg) print(" | ||||
| "..i18n("flow_details.icmp_info").." | "..icmp_label) if icmp["unreach"] then local unreachable_flow = interface.findFlowByTuple(flow["cli.ip"], flow["srv.ip"], flow["vlan"], icmp["unreach"]["dst_port"], icmp["unreach"]["src_port"], icmp["unreach"]["protocol"]) print(" ["..i18n("flow")..": ") if unreachable_flow then print(" Info") print(" "..getFlowLabel(unreachable_flow, true, true)) else -- The flow hasn't been found so very likely it is no longer active or it hasn't been seen. -- Still print the flow using data found in the original datagram found in the icmp packet print(getFlowLabel({ ["cli.ip"] = icmp["unreach"]["src_ip"], ["srv.ip"] = icmp["unreach"]["dst_ip"], ["cli.port"] = icmp["unreach"]["src_port"], ["srv.port"] = icmp["unreach"]["dst_port"]}, false, true)) end print("]") end print(" | |||
| "..i18n("flow_details.flow_alerted").." | ") print(message) print(" | |||
| "..status_icon..i18n("flow_details.additional_flow_status").." | ")
for _, t in pairsByKeys(flow_consts.status_types) do
local id = t.status_id
if ntop.bitmapIsSet(additional_status, id) then
local status_info = status_infos[id]
local detail = ""
if status_info then
detail = string.format(" [%s: %d]", i18n("score"), status_info.score)
detail = detail .. getConfigsetAlertLink({alert_generation = {confset_id = confset_id, subdir = "flow", script_key = status_info.user_script}})
end
print(flow_consts.getStatusDescription(id, flow2statusinfo(flow))..detail.." ") end end print(" | |||
| "..i18n("flow_details.flow_score").." | "..flow["score"].." | |||
| "..i18n("flow_details.actual_peak_throughput").." | ") if (throughput_type == "bps") then print("" .. bitsToSize(8*flow["throughput_bps"]) .. " ") elseif (throughput_type == "pps") then print("" .. pktsToSize(flow["throughput_bps"]) .. " ") end if (throughput_type == "bps") then print(" / " .. bitsToSize(8*flow["top_throughput_bps"]) .. " ") elseif (throughput_type == "pps") then print(" / " .. pktsToSize(flow["top_throughput_bps"]) .. " ") end print(" | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0") print(" | ||
| ') local width = 1024 local height = 200 local url = ntop.getHttpPrefix().."/lua/get_flow_process_tree.lua?flow_key="..flow_key.."&flow_hash_id="..flow_hash_id epbf_utils.draw_flow_processes_graph(width, height, url) print(' | ||||
| "..i18n("flow_details.client_process_information").." | ||||
| "..i18n("flow_details.client_container_information").." | ||||
| "..i18n("flow_details.server_process_information").." | ||||
| "..i18n("flow_details.server_container_information").." | ||||
| "..i18n("flow_details.dns_query").." | ") if(string.ends(flow["protos.dns.last_query"], "arpa")) then print(shortHostName(flow["protos.dns.last_query"])) else print(""..shortHostName(flow["protos.dns.last_query"]).." ") end if(flow["category"] ~= nil) then print(" "..getCategoryIcon(flow["protos.dns.last_query"], flow["category"])) end printAddCustomHostRule(flow["protos.dns.last_query"]) print(" | |||
| HASSH | ") print(""..i18n("client")..": "..(flow["protos.ssh.hassh.client_hash"] or '').." | ") print(""..i18n("server")..": "..(flow["protos.ssh.hassh.server_hash"] or '').." | ") print("") end if(not isEmptyString(flow["protos.ssh.client_signature"])) then print("||
| "..i18n("flow_details.ssh_signature").." | "..i18n("client")..": "..(flow["protos.ssh.client_signature"] or '').." | "..i18n("server")..": "..(flow["protos.ssh.server_signature"] or '').." | ||
| "..i18n("flow_details.bittorrent_hash").." | ".. flow["bittorrent_hash"].." | |||
| "..i18n("http").." | ") if(not isEmptyString(flow["protos.http.last_method"])) then print(""..i18n("flow_details.http_method").." | "..(flow["protos.http.last_method"] or '').." | ") print("||
| "..i18n("flow_details.server_name").." | ") local s = flowinfo2hostname(flow,"srv") if(not isEmptyString(flow["host_server_name"])) then s = flow["host_server_name"] end print(""..s.." ") if(flow["category"] ~= nil) then print(" "..getCategoryIcon(flow["host_server_name"], flow["category"])) end printAddCustomHostRule(s) print(" | |||
| "..i18n("flow_details.url").." | ") print(""..shortenString(flow["protos.http.last_url"] or '', 64).." ") print(" | |||
| "..i18n("flow_details.response_code").." | "..(flow["protos.http.last_return_code"] or '').." | |||
| "..i18n("flow_details.server_name").." | "..flow["host_server_name"].." ") if not isEmptyString(flow["protos.http.server_name"]) then printAddCustomHostRule(flow["protos.http.server_name"]) end print(" | |||
| "..i18n("flow_details.profile_name").." | "..flow["profile"].." | |||
| "..i18n("flow_details.additional_flow_elements").." | ||||
| " .. getFlowKey(key) .. " | " .. handleCustomFlowField(key, value, snmpdevice) .. " | |||