mirror of
https://github.com/ntop/ntopng.git
synced 2026-05-08 14:50:54 +00:00
408 lines
10 KiB
Lua
408 lines
10 KiB
Lua
--
|
|
-- (C) 2016 - ntop.org
|
|
--
|
|
|
|
-- Enable tracings here
|
|
local trace_hk = false
|
|
|
|
local profile_activity_match
|
|
local default_activity_parameters = {filter.SMA}
|
|
local media_activity_defaults = {filter.SMA, --[[min bytes]] 500, --[[min samples]]1, --[[bound time]]500, --[[sustain time]]4000}
|
|
local web_activity_defaults = {filter.Web}
|
|
|
|
if(trace_hk) then print("Initialized script useractivity.lua\n") end
|
|
|
|
-- ########################################################
|
|
|
|
local media_activity_mime_types = {
|
|
"audio/",
|
|
"video/",
|
|
"application/x-shockwave-flash"
|
|
}
|
|
|
|
local web_activity_mime_types = {
|
|
"text/",
|
|
"application/javascript",
|
|
"application/x-javascript",
|
|
"application/ecmascript"
|
|
}
|
|
|
|
-- ########################################################
|
|
|
|
function getFlowKey(f)
|
|
return(f["cli.ip"]..":"..f["cli.port"].." <-> " ..f["srv.ip"]..":"..f["srv.port"])
|
|
end
|
|
|
|
function string:split(sep)
|
|
local sep, fields = sep or ":", {}
|
|
local pattern = string.format("([^%s]+)", sep)
|
|
self:gsub(pattern, function(c) fields[#fields+1] = c end)
|
|
return fields
|
|
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 string.search(String,Search,Start)
|
|
return string.find(String, Search, Start or 1, false)
|
|
end
|
|
|
|
function splitProto(proto)
|
|
return unpack(proto:split("."))
|
|
end
|
|
|
|
-- ########################################################
|
|
|
|
-- These are matched top-down, so order is important
|
|
local profile_activity_match = {
|
|
-- Media profile
|
|
{
|
|
["profile"] = profile.Media,
|
|
["defaults"] = {filter.All, false},
|
|
["protos"] = {
|
|
"MGCP",
|
|
"RTCP",
|
|
"RTSP",
|
|
"SIP",
|
|
"H323",
|
|
"Megaco",
|
|
"CiscoSkinny"
|
|
}
|
|
},{
|
|
["profile"] = profile.Media,
|
|
["defaults"] = media_activity_defaults,
|
|
["protos"] = {
|
|
"RTMP",
|
|
"RTP",
|
|
"PPLive",
|
|
"PPStream",
|
|
"Tvants",
|
|
"TVUplayer",
|
|
"Zattoo",
|
|
"IceCast",
|
|
"ShoutCast",
|
|
"Sopcast",
|
|
"QQLive",
|
|
"QuickPlay",
|
|
"Vevo",
|
|
"IAX",
|
|
"Webex",
|
|
"WhatsAppVoice",
|
|
"KakaoTalk_Voice",
|
|
"TruPhone",
|
|
"SPOTIFY",
|
|
"Pandora",
|
|
"Deezer",
|
|
"Twitch",
|
|
"NetFlix",
|
|
"LastFM"
|
|
}
|
|
},
|
|
|
|
-- VPN profile
|
|
{
|
|
["profile"] = profile.VPN,
|
|
["defaults"] = {filter.SMA},
|
|
["protos"] = {
|
|
["OpenVPN"] = {filter.SMA, 150, 3, 3000, 2000},
|
|
"CiscoVPN",
|
|
"PPTP",
|
|
"HotspotShield"
|
|
}
|
|
},
|
|
|
|
-- MailSync profile
|
|
{
|
|
["profile"] = profile.MailSync,
|
|
["defaults"] = {filter.CommandSequence, false, 200, 3000},
|
|
["protos"] = {
|
|
["Hotmail"] = {filter.CommandSequence, true, 15000, 3000, 7},
|
|
"IMAP",
|
|
"IMAPS"
|
|
}
|
|
},{
|
|
["profile"] = profile.MailSync,
|
|
["defaults"] = {filter.All, true},
|
|
["protos"] = {
|
|
"POP3",
|
|
"POPS"
|
|
}
|
|
},
|
|
|
|
-- MailSend profile
|
|
{
|
|
["profile"] = profile.MailSend,
|
|
["defaults"] = {filter.All, true},
|
|
["protos"] = {
|
|
"SMTP",
|
|
"SMTPS"
|
|
}
|
|
},
|
|
|
|
-- FileTransfer profile
|
|
{
|
|
["profile"] = profile.FileTransfer,
|
|
["defaults"] = {filter.SMA},
|
|
["protos"] = {
|
|
["FTP_CONTROL"] = {filter.All, false},
|
|
["HTTP_Application_ActiveSync"] = {filter.All, false},
|
|
"FTP_DATA",
|
|
"Direct_Download_Link",
|
|
"AFP",
|
|
"Dropbox", -- TODO implement proper background detection
|
|
"NFS",
|
|
"SMB",
|
|
"UbuntuONE",
|
|
"MS_OneDrive",
|
|
"RSYNC",
|
|
"TFTP"
|
|
}
|
|
},
|
|
|
|
-- FileSharing profile
|
|
{
|
|
["profile"] = profile.FileSharing,
|
|
["defaults"] = {filter.SMA, 300, 3, 4000, 3000},
|
|
["protos"] = {
|
|
"BitTorrent",
|
|
"Gnutella",
|
|
"AppleJuice",
|
|
"DirectConnect",
|
|
"eDonkey",
|
|
"FastTrack",
|
|
"Filetopia",
|
|
"iMESH",
|
|
"OpenFT",
|
|
"Pando_Media_Booster",
|
|
"Soulseek",
|
|
"Stealthnet",
|
|
"Thunder"
|
|
}
|
|
},
|
|
|
|
-- Chat profile
|
|
{
|
|
["profile"] = profile.Chat,
|
|
["defaults"] = {filter.All, true},
|
|
["protos"] = {
|
|
"GoogleHangout",
|
|
"IRC",
|
|
"Unencryped_Jabber",
|
|
"Meebo",
|
|
"MSN",
|
|
"Oscar",
|
|
"QQ",
|
|
"Skype",
|
|
"TeamSpeak",
|
|
"Telegram",
|
|
"Viber",
|
|
"Slack",
|
|
"Weibo"
|
|
}
|
|
},
|
|
|
|
-- Game profile
|
|
{
|
|
["profile"] = profile.Game,
|
|
["defaults"] = {filter.All, true},
|
|
["protos"] = {
|
|
"Dofus",
|
|
"BattleField",
|
|
"Armagetron",
|
|
"Florensia",
|
|
"Guildwars",
|
|
"HalfLife2",
|
|
"MapleStory",
|
|
"Quake",
|
|
"Starcraft",
|
|
"Warcraft3",
|
|
"WorldOfKungFu",
|
|
"WorldOfWarcraft",
|
|
"Xbox"
|
|
}
|
|
},
|
|
|
|
-- RemoteControl profile
|
|
{
|
|
["profile"] = profile.RemoteControl,
|
|
["defaults"] = {filter.SMA, 20},
|
|
["protos"] = {
|
|
"PcAnywhere",
|
|
"RDP",
|
|
"SSH",
|
|
"TeamViewer",
|
|
"Telnet",
|
|
"VNC",
|
|
"XDMCP"
|
|
}
|
|
},
|
|
|
|
-- SocialNetwork profile
|
|
{
|
|
["profile"] = profile.SocialNetwork,
|
|
["defaults"] = {filter.Interflow},
|
|
["protos"] = {
|
|
["Twitter"] = {filter.Interflow, 3, 200},
|
|
["Facebook"] = {filter.Interflow, 3, 600, -1, true}
|
|
}
|
|
},
|
|
|
|
-- Web profile
|
|
{
|
|
["profile"] = profile.Web,
|
|
["defaults"] = web_activity_defaults,
|
|
["protos"] = {
|
|
"HTTP",
|
|
"HTTPS",
|
|
"YouTube"
|
|
}
|
|
},
|
|
|
|
-- Other profile
|
|
{
|
|
["profile"] = profile.Other,
|
|
-- Note: filter.Web will possibly update the flow to Web profile
|
|
["defaults"] = {filter.Web},
|
|
["protos"] = {
|
|
"SSL",
|
|
"SSL_No_Cert"
|
|
}
|
|
}
|
|
}
|
|
|
|
-- ########################################################
|
|
--
|
|
-- < Lua Virtual Machine - main >
|
|
--
|
|
-- The callbacks listed below are executed in the main ntopng thread, so
|
|
-- you can call most of the Flow functions without any synchronization troubles.
|
|
--
|
|
-- ########################################################
|
|
|
|
--
|
|
-- This callback is called once, when a new flow is created
|
|
--
|
|
function flowCreate()
|
|
if(trace_hk) then print("flowCreate()\n") end
|
|
end
|
|
|
|
--
|
|
-- This callback is called once, when a new flow is deleted
|
|
--
|
|
function flowDelete()
|
|
if(trace_hk) then print("flowDelete()\n") end
|
|
end
|
|
|
|
--
|
|
-- This callback is called any time some flow status, affecting activity
|
|
-- detection logic, changes. This happens, for example, when flow protocol
|
|
-- is detected.
|
|
--
|
|
function flowProtocolDetected()
|
|
local proto = flow.getNdpiProto()
|
|
local master, sub = splitProto(proto)
|
|
local srv = flow.getServerName()
|
|
|
|
if master ~= "DNS" then
|
|
local matched = nil
|
|
|
|
-- Particular protocols detection
|
|
if sub == "YouTube" and srv:ends("googlevideo.com") then
|
|
matched = {["profile"]=profile.Media, ["config"]={filter.All, true}}
|
|
elseif master == "HTTP" then
|
|
local contentType = flow.getHTTPContentType()
|
|
if contentType then
|
|
if flow.getProfileId() ~= profile.Media then
|
|
-- Try to detect a media type
|
|
for i=1, #media_activity_mime_types do
|
|
if contentType:starts(media_activity_mime_types[i]) then
|
|
matched = {["profile"]=profile.Media, ["config"]=media_activity_defaults}
|
|
break
|
|
end
|
|
end
|
|
|
|
-- Try to detect a web type
|
|
if not matched and flow.getActivityFilterId() ~= filter.All then
|
|
for i=1, #web_activity_mime_types do
|
|
if contentType:starts(web_activity_mime_types[i]) then
|
|
-- Be always active
|
|
matched = {["profile"]=profile.Web, ["config"]={filter.All, true}}
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Plain detection
|
|
if not matched then
|
|
for i=1, #profile_activity_match do
|
|
local pamatch = profile_activity_match[i]
|
|
local profile = pamatch["profile"]
|
|
local protos = pamatch["protos"]
|
|
|
|
for k,v in pairs(protos) do
|
|
local matchproto
|
|
local config = nil
|
|
|
|
if type(v) == "table" then
|
|
matchproto = k
|
|
config = v
|
|
else
|
|
matchproto = v
|
|
end
|
|
|
|
if matchproto == master or matchproto == sub then
|
|
matched = {["profile"]=profile, ["proto"]=matchproto, ["config"]=config, ["defaults"]=pamatch["defaults"]}
|
|
-- prefer subprotocols match within the same profile
|
|
if matchproto == sub then
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if matched then break end
|
|
end
|
|
end
|
|
|
|
-- Update Flow status
|
|
if matched then
|
|
local params = matched.config or matched.defaults
|
|
flow.setActivityFilter(matched.profile, unpack(params))
|
|
else
|
|
flow.setActivityFilter(profile.Other, unpack(default_activity_parameters))
|
|
end
|
|
|
|
if(trace_hk) then
|
|
f = flow.dump()
|
|
print("flowProtocolDetected(".. getFlowKey(f)..") = "..f["proto.ndpi"].."\n")
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ########################################################
|
|
--
|
|
-- < Lua Virtual Machine - periodic >
|
|
--
|
|
-- The callbacks listed below are executed periodically, NOT in the main
|
|
-- thread. This means that particular care must be taken before accessing
|
|
-- Flow state or other main thread related structure.
|
|
-- This is the right place to perform more intensive tasks.
|
|
--
|
|
-- ########################################################
|
|
|
|
--
|
|
-- This callback is called periodically for all active flows
|
|
-- Add here housekeeping of periodic activities you want to
|
|
-- perform in a flow
|
|
--
|
|
function flowUpdate()
|
|
if(trace_hk) then print("flowUpdate()\n") end
|
|
end
|