ntopng/scripts/lua/google_assistant_utils.lua
2019-03-26 17:47:02 +01:00

252 lines
8.1 KiB
Lua

--
-- (C) 2013-19 - ntop.org
--
local dirs = ntop.getDirs()
package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path
require "lua_utils"
ignore_post_payload_parse = 1
local json = require("dkjson")
local matrix = interface.getArpStatsMatrixInfo()
sendHTTPContentTypeHeader('application/json')
--sendHTTPContentTypeHeader('text/html')
--g: the type og graph ( 1 -sigma graph, 2 -heb graph )
--t: the type of data visualized (1-broadcast,2-replies,3-requests)
--local g,t = _GET["g"], _GET["t"]
--print(g..t)
--MISSING VALIDATION!
--========UTILS=======(but not currently used)==============================
--[[
--chack if inside "t" there is a mac named "name", if true return the index, nil otherwise
local function containName(t,name)
for i,v in pairs(t) do
if v.labels == name then return i end
end
return nil
end
--split the string "s" with the "sep" separator
local function split(s,sep)
local sep, fields = sep, {}
local pattern = string.format("([^%s]+)", sep)
s:gsub(pattern, function(c) fields[#fields+1] = c end)
return fields
end
function tableLength(t)
local count = 0
for _ in pairs(t) do count = count + 1 end
return count
end
--]]
--=======================================================================
--[[ JSON SCHEMA for sigma.js graph
{
"nodes": [
{
"id": "chr1",
"x": 0,
"y": 0,
"label": "Bob",
"size": 8.75
},
{
"id": "chr10",
"label": "Alice",
"x": 3,
"y": 1,
"size": 14.75
}
],
"edges": [{
"id": "1",
"source": "chr1",
"target": "chr10"
}]
]]--
--TODO: normalize pkt size (eg: size = (pkt_snt+rcv / tot_pkt_seen) * max_node_size ) ? )
--but maybe is not necessary, sigma.js already make an average
--the value of a t_nodes element is the size (not normalized) of the node (size = #request_pkt_sent )
--if "broadcast" is false all the broadcast requests will be ignored
--AT THE MOMENT THE CREATED GRAPH REPRESENT ONLY THE ARP REQUESTS (not replies)
local function createNodesAndEdges(matrix, broadcast)
local t_nodes = {}
local x,y = 10,10
local num, e_id = 0, 0
local t = { nodes = {}, edges = {} }
local source, target
for _, m_elem in ipairs(matrix) do
for src_mac, s_elem in pairs(m_elem)do
for dst_mac, stats in pairs(s_elem) do
--add dst_mac node and edges if broadcast is true or the pkt isn't broadcast
if broadcast or (dst_mac ~= "FF:FF:FF:FF:FF:FF") then
if t_nodes[src_mac] then
t_nodes[src_mac] = t_nodes[src_mac] + stats["src2dst.requests"]
else
t_nodes[src_mac] = stats["src2dst.requests"]
end
if t_nodes[dst_mac] then
t_nodes[dst_mac] = t_nodes[dst_mac] + stats["dst2src.requests"]
else
t_nodes[dst_mac] = stats["dst2src.requests"]
end
if stats["src2dst.requests"] > 0 then
table.insert( t.edges,
{ id = e_id,
source = src_mac,
target = dst_mac,
size = stats["src2dst.requests"],
label = stats["src2dst.requests"].." req snt"
}
)
end
e_id = e_id + 1
if stats["dst2src.requests"] > 0 then
table.insert( t.edges,
{ id = e_id,
source = dst_mac,
target = src_mac,
size = stats["dst2src.requests"],
label = stats["dst2src.requests"].." req snt"
}
)
end
e_id = e_id + 1
end--end if
end
end
end
for i,v in pairs(t_nodes) do
x = math.floor(math.random(0,500))
y = math.floor(math.random(0,350))
table.insert( t.nodes, { id = i, label = i, x = x , y = y, size = v })
end
return t
end
----WIP--------WIP--------WIP--------WIP--------WIP--------WIP--------WIP--------WIP--------
--------------------------------------------------------------------------------------------
----------------------------Hierarchical Edge Bundling--------------------------------------
--------------------------------------------------------------------------------------------
--PROBLEMA: le "foglie", cioè l'ultima parola dopo il punto. devono essere uniche
-- ma se A invia una req a B e poi B invia una req ad A, ciò viene meno
--IDEA: creo una finta gerarchia in base alle comunicazioni:
--se A invia a B, allora il nome di B diventa "A.B". e così per ogni comunicazione
--TODO: unire i 3 cici dove possibile
local function createHierarchyAndImport(matrix,broadcast)
local t_names = {}
local tbl = {}
local pkt_num = 0
--creo i nodi del grafo
for _, m_elem in ipairs(matrix) do
for src_mac, s_elem in pairs(m_elem)do
for dst_mac, stats in pairs(s_elem) do
--i due punti separatori dei byte del mac danno noia allo script js, metto il trattino
src_mac = string.gsub(src_mac, ":", "-")
dst_mac = string.gsub(dst_mac, ":", "-")
t_names[src_mac] = {name = src_mac, imports = {} }
if dst_mac ~= "FF-FF-FF-FF-FF-FF" then
t_names[dst_mac] = {name = dst_mac, imports = {} }
end
end
end
end
--ho la mappa dei mac dentro t_names, ora compongo la gerarchia fittizia
for _, m_elem in ipairs(matrix) do
for src_mac, s_elem in pairs(m_elem)do
for dst_mac, stats in pairs(s_elem) do
src_mac = string.gsub(src_mac, ":", "-")
dst_mac = string.gsub(dst_mac, ":", "-")
pkt_num = stats["src2dst.requests"]
if pkt_num > 0 then
if dst_mac ~= "FF-FF-FF-FF-FF-FF" then
t_names[dst_mac].name = src_mac.."."..t_names[dst_mac].name
end
end
pkt_num = stats["dst2src.requests"]
if pkt_num > 0 then
t_names[src_mac].name = dst_mac.."."..t_names[src_mac].name
end
end
end
end
--ho i nomi "lunghi", aggiungo gli import
for _, m_elem in ipairs(matrix) do
for src_mac, s_elem in pairs(m_elem)do
for dst_mac, stats in pairs(s_elem) do
src_mac = string.gsub(src_mac, ":", "-")
dst_mac = string.gsub(dst_mac, ":", "-")
pkt_num = stats["src2dst.requests"]
if pkt_num > 0 then
if dst_mac ~= "FF-FF-FF-FF-FF-FF" and (t_names[dst_mac].name ~= t_names[src_mac].name) then
table.insert( t_names[src_mac].imports, t_names[dst_mac].name )
end
end
pkt_num = stats["dst2src.requests"]
if pkt_num > 0 then
if t_names[dst_mac].name ~= t_names[src_mac].name then
table.insert( t_names[dst_mac].imports, t_names[src_mac].name )
end
end
end
end
end
--genero la tabella pronta per divenire il file json
for i,v in pairs(t_names) do
--tprint(v)
--"size" non viene preso in considerazione per lo spessore dell'arco
table.insert(tbl, { name = v.name, size = math.floor(math.random(100,10000)), imports = v.imports } )
end
return tbl
end
--print( json.encode( createNodesAndEdges(matrix, false), {indent = true} ) )
print( json.encode( createHierarchyAndImport(matrix, false), {indent = true} ) )
--print( json.encode( matrix, {indent = true} ) )