From 9786581526c25d79fcbf1cb234b40bfd1307dcd2 Mon Sep 17 00:00:00 2001 From: emanuele-f Date: Wed, 16 Oct 2019 13:57:22 +0200 Subject: [PATCH] flow.getInfo now returns minimal information --- doc/src/api/lua_c/flow/flow.lua | 51 ++++++---- doc/src/api/user_scripts/flow_hooks.rst | 5 +- doc/src/api/user_scripts/index.rst | 6 +- include/Flow.h | 4 +- scripts/callbacks/interface/flow.lua | 4 +- .../flow/{udp.lua => udp_unidirectional.lua} | 27 ++---- scripts/lua/modules/flow_utils.lua | 4 +- src/Flow.cpp | 38 ++++++++ src/LuaEngine.cpp | 97 ++++++++----------- 9 files changed, 129 insertions(+), 107 deletions(-) rename scripts/callbacks/interface/flow/{udp.lua => udp_unidirectional.lua} (59%) diff --git a/doc/src/api/lua_c/flow/flow.lua b/doc/src/api/lua_c/flow/flow.lua index d32815d7fa..c1e1cba985 100644 --- a/doc/src/api/lua_c/flow/flow.lua +++ b/doc/src/api/lua_c/flow/flow.lua @@ -1,29 +1,44 @@ ---! @brief Check if the flow is blacklisted ---! @return true if blacklisted, false otherwise -function flow.isBlacklistedFlow() - --! @brief Get the status bitmap of the flow --! @return the flow status bitmap function flow.getStatus() --! @brief Sets a bit into the flow status --! @param status_bit the status bit to set, see flow_consts.lua ---! @notes This is used to indicate that the Flow has a possible problem. -function flow.addStatus(status_bit) +--! @note This is used to indicate that the Flow has a possible problem. +function flow.setStatus(status_bit) ---! @brief Trigger an alert on the current flow ---! @param alerted_status the flow status which is causing the alert generation ---! @param alert_type the alert_id of the alert to generate (see alert_consts.alert_types) ---! @param alert_severity the severity_id of the alert to generate (see alert_consts.alert_types) ---! @notes alert_json an optional string message or json to store into the alert -function flow.triggerAlert(alerted_status, alert_type, alert_severity, alert_json = nil) +--! @brief Sets a bit into the flow status and possibly trigger an alert +--! @param status_bit the flow status bit to set +--! @param alert_json an optional string message or json to store into the alert +--! @note An alert will be triggered only for the status with the highest priority +function flow.triggerStatus(status_bit, alert_json = nil) ---! @brief Get the Layer-4 and the Layer-7 protocols +--! @brief Check if the flow is blacklisted +--! @return true if blacklisted, false otherwise +function flow.isBlacklistedFlow() + +--! @brief Get basic flow information. --! @return table:
---! proto.ndpi_id: the L7 nDPI protocol ID
---! proto.ndpi_breed: the nDPI protocol breed (e.g. Acceptable)
+--! cli.ip: the client IP address
+--! srv.ip: the server IP address
+--! cli.port: the client port
+--! srv.port: the server port
--! proto.l4: the L4 protocol name (e.g. TCP)
---! proto.ndpi_cat: the nDPI category name (e.g. Web)
---! proto.ndpi_cat_id: the nDPI category ID
--! proto.ndpi: the nDPI L7 protocol name (e.g. HTTP)
-function flow.getProtocols() +--! proto.ndpi_cat: the nDPI category name (e.g. Web)
+--! cli2srv.bytes: client-to-server bytes
+--! srv2cli.bytes: server-to-client bytes
+--! cli2srv.packets: client-to-server packets
+--! srv2cli.packets: server-to-client packets +function flow.getInfo() + +--! @brief Get full information about the flow. +--! @return a table with flow information, see Flow::lua +--! @note This call is expensive and should be avoided. See flow.getInfo() +function flow.getFullInfo() + +--! @brief Check if flow hosts are unicast or broadcast/multicast. +--! @return table:
+--! cli.broadmulticast: true if the client is broadcast/multicast
+--! srv.broadmulticast: true if the server is broadcast/multicast +function flow.getUnicastInfo() diff --git a/doc/src/api/user_scripts/flow_hooks.rst b/doc/src/api/user_scripts/flow_hooks.rst index 0539907b30..aa02314108 100644 --- a/doc/src/api/user_scripts/flow_hooks.rst +++ b/doc/src/api/user_scripts/flow_hooks.rst @@ -4,9 +4,6 @@ Flow Scripts Flow scripts are executed on each network flow. The user can inspect the flow protocol, peers involved in the communication, and other specific information. -Generating alerts from the user scripts is currently not supported (see -https://github.com/ntop/ntopng/issues/2842). - Hooks ----- @@ -73,7 +70,7 @@ The `flow` object keeps a context of the currently processed flow. The `flow.getClientGeolocation` and `flow.getServerGeolocation` functions extract the peers country information. The country code is then processed to determine if any of the peers is located in China (country code `CN`). -An easier way to access all the flow information would be to call `flow.getInfo()`, but this should not be used in +An easier way to access all the flow information would be to call `flow.getFullInfo()`, but this should not be used in production as it's a very expensive call. See the `Flow API`_ for a documentation of the available functions. diff --git a/doc/src/api/user_scripts/index.rst b/doc/src/api/user_scripts/index.rst index f4f016f29a..542327c34c 100644 --- a/doc/src/api/user_scripts/index.rst +++ b/doc/src/api/user_scripts/index.rst @@ -33,10 +33,8 @@ placed under the `/usr/share/ntopng/user_scripts/flows` directory: return(script) -The example above uses `flow.getInfo()` to extract all the information for the -current flow. While this is very pratical, it is an expensive operation so scripts -operating in large networks should instead call specific methods which are documented -below. +The example above uses `flow.getInfo()` to extract minimal information for the +current flow and prints it into the console. .. toctree:: diff --git a/include/Flow.h b/include/Flow.h index d32764d23f..3e704a3ab8 100644 --- a/include/Flow.h +++ b/include/Flow.h @@ -440,7 +440,9 @@ class Flow : public GenericHashEntry { u_int16_t vlan_id, u_int16_t protocol); void lua(lua_State* vm, AddressTree * ptree, DetailsLevel details_level, bool asListElement); - + void lua_get_min_info(lua_State* vm); + + void lua_get_unicast_info(lua_State* vm) const; void lua_get_status(lua_State* vm) const; void lua_get_protocols(lua_State* vm) const; void lua_get_bytes(lua_State* vm) const; diff --git a/scripts/callbacks/interface/flow.lua b/scripts/callbacks/interface/flow.lua index ed1ac69705..0b1d4a1c6f 100644 --- a/scripts/callbacks/interface/flow.lua +++ b/scripts/callbacks/interface/flow.lua @@ -120,7 +120,7 @@ local function call_modules(l4_proto, mod_fn) end -- TODO too expensive, remove - local info = flow.getInfo() + local info = flow.getFullInfo() local params = { -- Flow specific information @@ -161,7 +161,7 @@ function flow.triggerStatus(status_id, status_json) end -- Set the status bit in the flow status bitmap - flow.addStatus(status_id) + flow.setStatus(status_id) end -- ################################################################# diff --git a/scripts/callbacks/interface/flow/udp.lua b/scripts/callbacks/interface/flow/udp_unidirectional.lua similarity index 59% rename from scripts/callbacks/interface/flow/udp.lua rename to scripts/callbacks/interface/flow/udp_unidirectional.lua index 389db809a3..f73e473fd9 100644 --- a/scripts/callbacks/interface/flow/udp.lua +++ b/scripts/callbacks/interface/flow/udp_unidirectional.lua @@ -12,7 +12,8 @@ local user_scripts = require("user_scripts") -- ################################################################# local script = { - key = "udp", + key = "udp_unidirectional", + l4_proto = "udp", -- NOTE: hooks defined below hooks = {}, @@ -27,29 +28,19 @@ local script = { -- ################################################################# -- NOTE: what if at some point the flow receives a packet? We need to cancel the status bit -function script.hooks.flowEnd(params) - local packets = flow.getPackets() +function script.hooks.all(params) + local info = flow.getInfo() - if(packets["packets.rcvd"] == 0) then - local proto = flow.getProtocols() + if(info["packets.rcvd"] == 0) then + local info = flow.getUnicastInfo() - if(proto["proto.l4"] == "UDP") then - local server = flow.getServerIp() - - -- Now check if the recipient isn't a broadcast/multicast address - if(not(server["srv.broadmulticast"])) then - flow.triggerStatus(flow_consts.status_types.status_udp_unidirectional.status_id) - end + -- Now check if the recipient isn't a broadcast/multicast address + if(not(info["srv.broadmulticast"])) then + flow.setStatus(flow_consts.status_types.status_udp_unidirectional.status_id) end end end -- ################################################################# -function script.hooks.periodicUpdate(params) - script.hooks.flowEnd(params) -end - --- ################################################################# - return script diff --git a/scripts/lua/modules/flow_utils.lua b/scripts/lua/modules/flow_utils.lua index f1e9942bd6..897d682010 100644 --- a/scripts/lua/modules/flow_utils.lua +++ b/scripts/lua/modules/flow_utils.lua @@ -1809,8 +1809,10 @@ end -- ####################### -- A one line flow description +-- This uses the information from flow.getInfo() function shortFlowLabel(flow) - return(string.format("[%s] %s:%d -> %s:%s [%s]", flow["proto.l4"], + return(string.format("[%s] %s:%d -> %s:%s [%s]", + flow["proto.l4"], flow["cli.ip"], flow["cli.port"], flow["srv.ip"], flow["srv.port"], flow["proto.ndpi"] diff --git a/src/Flow.cpp b/src/Flow.cpp index 22e7c1fb58..e17253d084 100644 --- a/src/Flow.cpp +++ b/src/Flow.cpp @@ -4427,6 +4427,44 @@ void Flow::lua_get_info(lua_State *vm, bool client) const { /* ***************************************************** */ +/* Get minimal flow information. + * NOTE: this is intended to be called only from flow user scripts + * via flow.getInfo(). mask_host/allowed networks are not honored. + */ +void Flow::lua_get_min_info(lua_State *vm) { + const IpAddress *cli_ip = get_cli_ip_addr(); + const IpAddress *srv_ip = get_srv_ip_addr(); + char buf[32]; + + lua_newtable(vm); + + if(cli_ip) lua_push_str_table_entry(vm, "cli.ip", cli_ip->print(buf, sizeof(buf))); + if(srv_ip) lua_push_str_table_entry(vm, "srv.ip", srv_ip->print(buf, sizeof(buf))); + lua_push_int32_table_entry(vm, "cli.port", get_cli_port()); + lua_push_int32_table_entry(vm, "srv.port", get_srv_port()); + lua_push_str_table_entry(vm, "proto.l4", get_protocol_name()); + lua_push_str_table_entry(vm, "proto.ndpi", get_detected_protocol_name(buf, sizeof(buf))); + lua_push_str_table_entry(vm, "proto.ndpi_cat", get_protocol_category_name()); + lua_push_uint64_table_entry(vm, "cli2srv.bytes", stats.cli2srv_bytes); + lua_push_uint64_table_entry(vm, "srv2cli.bytes", stats.srv2cli_bytes); + lua_push_uint64_table_entry(vm, "cli2srv.packets", stats.srv2cli_packets); + lua_push_uint64_table_entry(vm, "srv2cli.packets", stats.srv2cli_packets); +} + +/* ***************************************************** */ + +void Flow::lua_get_unicast_info(lua_State* vm) const { + const IpAddress *cli_ip = get_cli_ip_addr(); + const IpAddress *srv_ip = get_srv_ip_addr(); + + lua_newtable(vm); + + if(cli_ip) lua_push_bool_table_entry(vm, "cli.broadmulticast", cli_ip->isBroadMulticastAddress()); + if(srv_ip) lua_push_bool_table_entry(vm, "srv.broadmulticast", srv_ip->isBroadMulticastAddress()); +} + +/* ***************************************************** */ + void Flow::lua_get_ssl_info(lua_State *vm) const { if(isSSL()) { lua_push_int32_table_entry(vm, "protos.ssl_version", protos.ssl.ssl_version); diff --git a/src/LuaEngine.cpp b/src/LuaEngine.cpp index 369758a48e..0a0f480f21 100644 --- a/src/LuaEngine.cpp +++ b/src/LuaEngine.cpp @@ -8405,7 +8405,20 @@ static Flow* ntop_flow_get_context_flow(lua_State* vm) { /* ****************************************** */ +// ***API*** static int ntop_flow_get_info(lua_State* vm) { + Flow *f = ntop_flow_get_context_flow(vm); + + if(!f) return(CONST_LUA_ERROR); + + f->lua_get_min_info(vm); + + return(CONST_LUA_OK); +} + +/* ****************************************** */ + +static int ntop_flow_get_full_info(lua_State* vm) { AddressTree *ptree = get_allowed_nets(vm); Flow *f = ntop_flow_get_context_flow(vm); @@ -8418,6 +8431,19 @@ static int ntop_flow_get_info(lua_State* vm) { /* ****************************************** */ +// ***API*** +static int ntop_flow_get_unicast_info(lua_State* vm) { + Flow *f = ntop_flow_get_context_flow(vm); + + if(!f) return(CONST_LUA_ERROR); + + f->lua_get_unicast_info(vm); + + return(CONST_LUA_OK); +} + +/* ****************************************** */ + static int ntop_flow_is_local(lua_State* vm) { Flow *f = ntop_flow_get_context_flow(vm); bool is_local = false; @@ -8590,7 +8616,7 @@ static int ntop_flow_get_status(lua_State* vm) { /* ****************************************** */ // ***API*** -static int ntop_flow_add_status(lua_State* vm) { +static int ntop_flow_set_status(lua_State* vm) { FlowStatus new_status; Flow *f = ntop_flow_get_context_flow(vm); @@ -8607,7 +8633,6 @@ static int ntop_flow_add_status(lua_State* vm) { /* ****************************************** */ -// ***API*** static int ntop_flow_trigger_alert(lua_State* vm) { Flow *f = ntop_flow_get_context_flow(vm); FlowStatus status; @@ -8650,7 +8675,6 @@ static int ntop_flow_is_blacklisted(lua_State* vm) { /* ****************************************** */ -// ***API*** static int ntop_flow_get_protocols(lua_State* vm) { Flow *f = ntop_flow_get_context_flow(vm); @@ -8747,54 +8771,6 @@ static int ntop_flow_get_time(lua_State* vm) { /* ****************************************** */ -static int ntop_flow_get_ip(lua_State* vm, bool client) { - Flow *f = ntop_flow_get_context_flow(vm); - - lua_newtable(vm); - - if(f) f->lua_get_ip(vm, client); - - return CONST_LUA_OK; -} - -/* ****************************************** */ - -static int ntop_flow_get_cli_ip(lua_State* vm) { - return ntop_flow_get_ip(vm, true /* Client */); -} - -/* ****************************************** */ - -static int ntop_flow_get_srv_ip(lua_State* vm) { - return ntop_flow_get_ip(vm, false /* Server */); -} - -/* ****************************************** */ - -static int ntop_flow_get_info(lua_State* vm, bool client) { - Flow *f = ntop_flow_get_context_flow(vm); - - lua_newtable(vm); - - if(f) f->lua_get_info(vm, client); - - return CONST_LUA_OK; -} - -/* ****************************************** */ - -static int ntop_flow_get_cli_info(lua_State* vm) { - return ntop_flow_get_info(vm, true /* Client */); -} - -/* ****************************************** */ - -static int ntop_flow_get_srv_info(lua_State* vm) { - return ntop_flow_get_info(vm, false /* Server */); -} - -/* ****************************************** */ - static int ntop_flow_get_ssl_info(lua_State* vm) { Flow *f = ntop_flow_get_context_flow(vm); @@ -10254,7 +10230,18 @@ static const luaL_Reg ntop_network_reg[] = { /* **************************************************************** */ static const luaL_Reg ntop_flow_reg[] = { + /* Documented */ + { "getStatus", ntop_flow_get_status }, + { "isBlacklisted", ntop_flow_is_blacklisted }, + { "setStatus", ntop_flow_set_status }, { "getInfo", ntop_flow_get_info }, + { "getFullInfo", ntop_flow_get_full_info }, + { "getUnicastInfo", ntop_flow_get_unicast_info }, + + /* Internal */ + { "triggerAlert", ntop_flow_trigger_alert }, + + /* TODO document */ { "isLocal", ntop_flow_is_local }, { "setScore", ntop_flow_set_score }, { "getClientScore", ntop_flow_get_client_score }, @@ -10267,10 +10254,6 @@ static const luaL_Reg ntop_flow_reg[] = { { "serializeServerByMac", ntop_flow_serialize_server_by_mac }, { "storeAlert", ntop_flow_store_alert }, - { "isBlacklisted", ntop_flow_is_blacklisted }, - { "getStatus", ntop_flow_get_status }, - { "addStatus", ntop_flow_add_status }, - { "triggerAlert", ntop_flow_trigger_alert }, { "getProtocols", ntop_flow_get_protocols }, { "getBytes", ntop_flow_get_bytes }, { "getClient2ServerTraffic", ntop_flow_get_cli2srv_traffic }, @@ -10279,10 +10262,6 @@ static const luaL_Reg ntop_flow_reg[] = { { "getServer2ClientIAT", ntop_flow_get_srv2cli_iat }, { "getPackets", ntop_flow_get_packets }, { "getTime", ntop_flow_get_time }, - { "getClientIp", ntop_flow_get_cli_ip }, - { "getServerIp", ntop_flow_get_srv_ip }, - { "getClientInfo", ntop_flow_get_cli_info }, - { "getServerInfo", ntop_flow_get_srv_info }, { "getSSLInfo", ntop_flow_get_ssl_info }, { "getSSHInfo", ntop_flow_get_ssh_info }, { "getHTTPInfo", ntop_flow_get_http_info },