ntopng/src/LuaEngineNtop.cpp
2026-03-16 22:22:59 +00:00

9387 lines
337 KiB
C++

/*
*
* (C) 2013-26 - ntop.org
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "ntop_includes.h"
extern "C" {
#include "rrd.h"
};
enum list_file_type {
list_type_hosts = 0,
list_type_ip_csv = 1,
list_type_ip_occurrencies = 2,
list_type_ip = 3,
list_type_max
};
static int live_extraction_num = 0;
static Mutex live_extraction_num_lock;
/* ******************************* */
/**
* @brief Check the expected type of lua function.
* @details Find in the lua stack the function and check the function parameters
* types.
*
* @param vm The lua state.
* @param func The function name.
* @param pos Index of lua stack.
* @param expected_type Index of expected type.
* @return @ref CONST_LUA_ERROR if the expected type is equal to function type,
* @ref CONST_LUA_PARAM_ERROR otherwise.
*/
int ntop_lua_check(lua_State* vm, const char* func, int pos,
int expected_type) {
if (lua_type(vm, pos) != expected_type) {
lua_Debug ar;
ntop->getTrace()->traceEvent(TRACE_ERROR,
"%s : expected %s[@pos %d], got %s", func,
lua_typename(vm, expected_type), pos,
lua_typename(vm, lua_type(vm, pos)));
if (lua_getstack(vm, 1, &ar)) {
// Fill 'ar' with Source (S) and current Line (l)
lua_getinfo(vm, "Sl", &ar);
const char* err_msg = lua_tostring(vm, -1);
// Create a formatted string: "filename:line: error message"
ntop->getTrace()->traceEvent(TRACE_ERROR, "%s:%d %s", ar.short_src,
ar.currentline, err_msg ? err_msg : "");
}
return (CONST_LUA_PARAM_ERROR);
}
return (CONST_LUA_OK);
}
/* ****************************************** */
void get_host_vlan_info(char* lua_ip, char** host_ip, u_int16_t* vlan_id,
char* buf, u_int buf_len) {
char *where, *vlan = NULL;
snprintf(buf, buf_len, "%s", lua_ip);
if (((*host_ip) = strtok_r(buf, "@", &where)) != NULL)
vlan = strtok_r(NULL, "@", &where);
if (*host_ip == NULL) *host_ip = lua_ip;
if (vlan)
(*vlan_id) = (u_int16_t)atoi(vlan);
else
(*vlan_id) = 0;
}
/* ****************************************** */
/* @brief Reads a text file and writes its content to the HTTP response, performing string substitutions. Lua: ntop.dumpFile(path) → nil */
static int ntop_dump_file(lua_State* vm) {
char* fname;
FILE* fd;
struct mg_connection* conn;
conn = getLuaVMUserdata(vm, conn);
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((fname = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((fd = fopen(fname, "r")) != NULL) {
char tmp[1024];
ntop->getTrace()->traceEvent(TRACE_INFO, "[HTTP] Serving file %s", fname);
while ((fgets(tmp,
sizeof(tmp) -
256 /* To make sure we have room for replacements */,
fd)) != NULL) {
for (int i = 0; string_to_replace[i].key != NULL; i++)
Utils::replacestr(tmp, string_to_replace[i].key,
string_to_replace[i].val);
mg_printf(conn, "%s", tmp);
}
fclose(fd);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else {
ntop->getTrace()->traceEvent(TRACE_INFO, "Unable to read file %s", fname);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
}
/* ****************************************** */
/* @brief Reads a binary file and writes it verbatim to the HTTP response. Lua: ntop.dumpBinaryFile(path) → nil */
static int ntop_dump_binary_file(lua_State* vm) {
char* fname;
FILE* fd;
struct mg_connection* conn;
conn = getLuaVMUserdata(vm, conn);
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((fname = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ntop->fixPath(fname);
if ((fd = fopen(fname, "rb")) != NULL) {
char tmp[1024];
size_t n;
while ((n = fread(tmp, 1, sizeof(tmp), fd)) > 0) {
if (mg_write(conn, tmp, n) < (int)n) break;
}
fclose(fd);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else {
ntop->getTrace()->traceEvent(TRACE_INFO, "Unable to read file %s", fname);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
}
/* ****************************************** */
/* @brief Returns the vendor/manufacturer name for a MAC address OUI. Lua: ntop.getMacManufacturer(mac) → string */
static int ntop_get_mac_manufacturer(lua_State* vm) {
const char* mac = NULL;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
mac = (char*)lua_tostring(vm, 1);
ntop->getMacManufacturer(mac, vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns combined host information table for an IP address. Lua: ntop.getHostInformation(ip) → table */
static int ntop_get_host_information(lua_State* vm) {
struct in_addr management_addr;
management_addr.s_addr = Utils::getHostManagementIPv4Address();
lua_newtable(vm);
lua_push_str_table_entry(vm, "ip", inet_ntoa(management_addr));
lua_push_str_table_entry(vm, "instance_name",
ntop->getPrefs()->get_instance_name());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#ifdef HAVE_NEDGE
/* @brief Internal helper that sets HTTP or HTTPS bind address (called by set_http/https_bind_addr). Lua: (internal helper) → nil */
static int ntop_set_bind_addr(lua_State* vm, bool http) {
char *addr, *addr2 = (char*)CONST_LOOPBACK_ADDRESS;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
addr = (char*)lua_tostring(vm, 1);
if (lua_type(vm, 2) == LUA_TSTRING) addr2 = (char*)lua_tostring(vm, 2);
if (http)
ntop->getPrefs()->bind_http_to_address(addr, addr2);
else /* https */
ntop->getPrefs()->bind_https_to_address(addr, addr2);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* @brief Sets the HTTP bind address (nEdge only). Lua: ntop.setHTTPBindAddr(addr) → nil */
static int ntop_set_http_bind_addr(lua_State* vm) {
return ntop_set_bind_addr(vm, true /* http */);
}
/* @brief Sets the HTTPS bind address (nEdge only). Lua: ntop.setHTTPSBindAddr(addr) → nil */
static int ntop_set_https_bind_addr(lua_State* vm) {
return ntop_set_bind_addr(vm, false /* https */);
}
#endif
/* ****************************************** */
/* @brief Initiates ntopng shutdown (nEdge/Appliance only). Lua: ntop.shutdown() → nil */
static int ntop_shutdown(lua_State* vm) {
char* action;
extern AfterShutdownAction afterShutdownAction;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (lua_type(vm, 1) == LUA_TSTRING) {
action = (char*)lua_tostring(vm, 1);
if (!strcmp(action, "poweroff"))
afterShutdownAction = after_shutdown_poweroff;
else if (!strcmp(action, "reboot"))
afterShutdownAction = after_shutdown_reboot;
else if (!strcmp(action, "restart_self"))
afterShutdownAction = after_shutdown_restart_self;
}
ntop->getGlobals()->requestShutdown();
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if ntopng is currently in shutdown sequence. Lua: ntop.isShuttingDown() → boolean */
static int ntop_is_shuttingdown(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->getGlobals()->isShutdownRequested());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns a table of all available network interfaces. Lua: ntop.listInterfaces() → table */
static int ntop_list_interfaces(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_newtable(vm);
Utils::listInterfaces(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Compares two IP address strings; returns -1, 0, or 1. Lua: ntop.ipCmp(ip1, ip2) → integer */
static int ntop_ip_cmp(lua_State* vm) {
IpAddress a, b;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
a.set((char*)lua_tostring(vm, 1));
b.set((char*)lua_tostring(vm, 2));
lua_pushinteger(vm, a.compare(&b));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Applies a traffic mask to a domain name for nDPI classification. Lua: ntop.setDomainMask(domain, mask) → integer */
static int ntop_setDomainMask(lua_State* vm) {
const char* domain;
int rc;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
domain = lua_tostring(vm, 1);
rc = ntop->nDPISetDomainMask(domain, 0 /* mask all */);
return (ntop_lua_return_value(vm, __FUNCTION__, rc));
}
/* ****************************************** */
/* @brief Adds a trusted TLS certificate issuer Distinguished Name. Lua: ntop.addTrustedIssuerDN(dn) → integer */
static int ntop_addTrustedIssuerDN(lua_State* vm) {
const char* dn;
int rc;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
dn = lua_tostring(vm, 1);
rc = ntop->getSystemInterface()->addTrustedIssuerDN(dn);
return (ntop_lua_return_value(vm, __FUNCTION__, rc));
}
/* ****************************************** */
/* @brief Sets the device type classification for a MAC address. Lua: ntop.setMacDeviceType(mac, type) → nil */
static int ntop_set_mac_device_type(lua_State* vm) {
char* mac = NULL;
DeviceType dtype = device_unknown;
bool overwriteType;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
mac = (char*)lua_tostring(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
dtype = (DeviceType)lua_tonumber(vm, 2);
if (dtype >= device_max_type) dtype = device_unknown;
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
overwriteType = (bool)lua_toboolean(vm, 3);
for (int i = 0; i < ntop->get_num_interfaces(); i++) {
NetworkInterface* curr_iface = ntop->getInterface(i);
if (curr_iface && mac)
curr_iface->setMacDeviceType(mac, dtype, overwriteType);
}
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Triggers a reload of host pool configuration from Redis. Lua: ntop.reloadHostPools() → nil */
static int ntop_reload_host_pools(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->reloadHostPools();
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#ifdef HAVE_NEDGE
/* @brief Enables or disables routing mode (nEdge only). Lua: ntop.setRoutingMode(enabled) → nil */
static int ntop_set_routing_mode(lua_State* vm) {
bool routing_enabled;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
routing_enabled = lua_toboolean(vm, 1);
ntop->getPrefs()->set_routing_mode(routing_enabled);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
/* ****************************************** */
#ifdef HAVE_NEDGE
/* @brief Returns true if nEdge is in routing mode (nEdge only). Lua: ntop.isRoutingMode() → boolean */
static int ntop_is_routing_mode(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->getPrefs()->is_routing_mode());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
/* ****************************************** */
/* @brief Returns true if the given path is an existing directory. Lua: ntop.isdir(path) → boolean */
static int ntop_is_dir(lua_State* vm) {
char* path;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
path = (char*)lua_tostring(vm, 1);
lua_pushboolean(vm, Utils::dir_exists(path));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the given path is a non-empty file. Lua: ntop.notEmptyFile(path) → boolean */
static int ntop_is_not_empty_file(lua_State* vm) {
char* path;
struct stat buf;
int rc;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
path = (char*)lua_tostring(vm, 1);
rc = (stat(path, &buf) != 0) ? 0 : 1;
if (rc && (buf.st_size == 0)) rc = 0;
lua_pushboolean(vm, rc);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Executes a query on the alert database and streams JSON results to the HTTP response. Lua: ntop.alert_store_query(query[,ifid,limit]) → nil */
static int ntop_alert_store_query(lua_State* vm) {
NetworkInterface* iface = NULL;
char* query;
bool limit_rows = false;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (lua_type(vm, 1) != LUA_TSTRING || !(query = (char*)lua_tostring(vm, 1))) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
if (lua_type(vm, 2) == LUA_TSTRING) {
const char* ifname = lua_tostring(vm, 1);
iface = ntop->getNetworkInterface(ifname, vm);
} else if (lua_type(vm, 2) == LUA_TNUMBER) {
int ifid = lua_tointeger(vm, 2);
iface = ntop->getNetworkInterface(vm, ifid);
} else {
iface = getCurrentInterface(vm);
}
/* Optional: limit rows */
if (lua_type(vm, 3) == LUA_TBOOLEAN)
limit_rows = lua_toboolean(vm, 3) ? true : false;
if (iface == NULL) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
if (ntop->getPrefs()->are_alerts_disabled()) {
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
if (!iface->alert_store_query(vm, query, limit_rows)) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
int ntop_release_triggered_alert(lua_State* vm, OtherAlertableEntity* alertable,
u_int idx) {
NtopngLuaContext* c = getLuaVMContext(vm);
char* key;
ScriptPeriodicity periodicity;
time_t when;
if (!c->iface || !alertable)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((key = (char*)lua_tostring(vm, idx++)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((periodicity = (ScriptPeriodicity)lua_tointeger(vm, idx++)) >=
MAX_NUM_PERIODIC_SCRIPTS)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
when = (time_t)lua_tonumber(vm, idx++);
/* The released alert will be pushed to LUA */
alertable->releaseAlert(vm, std::string(key), periodicity, when);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
int ntop_store_triggered_alert(lua_State* vm, OtherAlertableEntity* alertable,
u_int idx) {
NtopngLuaContext* c = getLuaVMContext(vm);
char *key, *alert_subtype, *alert_json, *ip = NULL, *name = NULL;
u_int16_t port = 0;
ScriptPeriodicity periodicity;
u_int32_t score;
AlertType alert_type;
// Host *host;
/* bool triggered; */
if (!alertable || !c->iface)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((key = (char*)lua_tostring(vm, idx++)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((periodicity = (ScriptPeriodicity)lua_tointeger(vm, idx++)) >=
MAX_NUM_PERIODIC_SCRIPTS)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
score = lua_tointeger(vm, idx++);
if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
alert_type = (AlertType)lua_tonumber(vm, idx++);
if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((alert_subtype = (char*)lua_tostring(vm, idx++)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, idx, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((alert_json = (char*)lua_tostring(vm, idx++)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ip = (char*)lua_tostring(vm, idx++);
name = (char*)lua_tostring(vm, idx++);
port = (u_int16_t)lua_tonumber(vm, idx++);
/* triggered = */ alertable->triggerAlert(
vm, std::string(key), periodicity, time(NULL), score, alert_type,
alert_subtype, alert_json, ip, name, port);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the given file or directory exists. Lua: ntop.exists(path) → boolean */
static int ntop_get_file_dir_exists(lua_State* vm) {
char* path;
struct stat buf;
int rc;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
path = (char*)lua_tostring(vm, 1);
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s(%s) called", __FUNCTION__,
path ? path : "???");
rc = (stat(path, &buf) != 0) ? 0 : 1;
// ntop->getTrace()->traceEvent(TRACE_ERROR, "%s: %d", path, rc);
lua_pushboolean(vm, rc);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the last modification time of a file as a Unix epoch. Lua: ntop.fileLastChange(path) → integer */
static int ntop_get_file_last_change(lua_State* vm) {
char* path;
struct stat buf;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
path = (char*)lua_tostring(vm, 1);
if (stat(path, &buf) == 0)
lua_pushinteger(vm, (lua_Integer)buf.st_mtime);
else
lua_pushinteger(vm, -1); /* not found */
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if MaxMind GeoIP databases are loaded. Lua: ntop.hasGeoIP() → boolean */
static int ntop_has_geoip(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(
vm,
ntop->getGeolocation() && ntop->getGeolocation()->isAvailable() ? 1 : 0);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns Elasticsearch connection details or nil if not configured. Lua: ntop.elasticsearchConnection() → table|nil */
static int ntop_elasticsearch_connection(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop->getPrefs()->do_dump_flows_on_es()) {
lua_newtable(vm);
lua_push_str_table_entry(vm, "user", ntop->getPrefs()->get_es_user());
lua_push_str_table_entry(vm, "password", ntop->getPrefs()->get_es_pwd());
lua_push_str_table_entry(vm, "url", ntop->getPrefs()->get_es_url());
lua_push_str_table_entry(vm, "host", ntop->getPrefs()->get_es_host());
} else
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the configured ntopng instance name. Lua: ntop.getInstanceName() → string */
static int ntop_get_instance_name(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushstring(vm, ntop->getPrefs()->get_instance_name());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if ntopng is running on Windows. Lua: ntop.isWindows() → boolean */
static int ntop_is_windows(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm,
#ifdef WIN32
1
#else
0
#endif
);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if ntopng is running on FreeBSD. Lua: ntop.isFreeBSD() → boolean */
static int ntop_is_freebsd(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm,
#ifdef __FreeBSD__
1
#else
0
#endif
);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if ntopng is running on Linux. Lua: ntop.isLinux() → boolean */
static int ntop_is_linux(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm,
#ifdef __linux__
1
#else
0
#endif
);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Begins a hot-reload of nDPI custom categories (call before loading categories). Lua: ntop.initnDPIReload() → boolean */
static int ntop_initnDPIReload(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop->isnDPIReloadInProgress() || (!ntop->initnDPIReload())) {
/* initnDPIReload abort */
lua_pushboolean(vm, false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
lua_pushboolean(vm, true /* can now start reloading */);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Associates an IP or CIDR range with a custom nDPI category. Lua: ntop.loadCustomCategoryIp(cat_id, ip_or_cidr) → boolean */
static int ntop_loadCustomCategoryIp(lua_State* vm) {
char *net, *listname;
ndpi_protocol_category_t catid;
bool success;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK) {
lua_pushboolean(vm, false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
net = (char*)lua_tostring(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK) {
lua_pushboolean(vm, false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
catid = (ndpi_protocol_category_t)lua_tointeger(vm, 2);
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK) {
lua_pushboolean(vm, false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
listname = (char*)lua_tostring(vm, 3);
success = ntop->nDPILoadIPCategory(net, catid, listname);
lua_pushboolean(vm, success);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Associates a hostname pattern with a custom nDPI category. Lua: ntop.loadCustomCategoryHost(cat_id, hostname) → boolean */
static int ntop_loadCustomCategoryHost(lua_State* vm) {
char *host, *listname;
ndpi_protocol_category_t catid;
bool success;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK) {
lua_pushboolean(vm, false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
host = (char*)lua_tostring(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK) {
lua_pushboolean(vm, false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
catid = (ndpi_protocol_category_t)lua_tointeger(vm, 2);
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK) {
lua_pushboolean(vm, false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
listname = (char*)lua_tostring(vm, 3);
success = ntop->nDPILoadHostnameCategory(host, catid, listname);
lua_pushboolean(vm, success);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
static bool is_valid_host(char* _host, enum list_file_type t,
bool ignorePrivateIPs) {
char host[256], *div, *slash = strchr(_host, '/');
;
int cidr = 128;
if (slash) slash[0] = '\0';
snprintf(host, sizeof(host), "%s", _host);
if ((div = strchr(host, '\t')) != NULL) div[0] = '\0';
if ((div = strchr(host, ' ')) != NULL) div[0] = '\0';
if ((slash = strchr(host, '/')) != NULL) {
slash[0] = '\0';
cidr = atoi(&slash[1]);
}
if (cidr < 12) {
/* ntop->getTrace()->traceEvent(TRACE_WARNING, "CIDR too small %s [%d]",
* host, t); */
return (false);
}
if (t == list_type_hosts) {
if (strcmp(host, "localhost")) return (true);
} else {
if (ignorePrivateIPs) {
IpAddress ip;
if ((strcmp(host, "127.0.0.1") == 0) ||
(strcmp(host, "255.255.255.255") == 0) ||
(strncmp(host, "0.0.0.0", 7) == 0) ||
(strchr(host, ':') != NULL) /* Ignore IPv6 */
) {
/* ntop->getTrace()->traceEvent(TRACE_WARNING, "Discarding IP address
* %s", host); */
return (false);
}
ip.set((const char*)host);
if (ip.isPrivateAddress()) {
/* ntop->getTrace()->traceEvent(TRACE_INFO, "WARNING: xsIgnoring private
* IP address %s", host); */
return (false);
}
}
}
return (true);
}
/* ****************************************** */
/* @brief Loads IP/hostname entries from a file into a custom nDPI category. Lua: ntop.loadCustomCategoryFile(cat_id, path) → integer */
static int ntop_loadCustomCategoryFile(lua_State* vm) {
char *path, *listname;
const char* format;
enum list_file_type list_type;
ndpi_protocol_category_t catid;
FILE* fd;
u_int32_t num_lines_loaded = 0;
u_int32_t num_bad_lines = 0;
bool ignorePrivateIPs = false;
bool warn_once = true;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK) {
lua_pushinteger(vm, (int)num_lines_loaded);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
path = (char*)lua_tostring(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK) {
lua_pushinteger(vm, (int)num_lines_loaded);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
list_type = (enum list_file_type)lua_tointeger(vm, 2);
if (list_type >= list_type_max) {
lua_pushinteger(vm, (int)num_lines_loaded);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TNUMBER) != CONST_LUA_OK) {
lua_pushinteger(vm, (int)num_lines_loaded);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
catid = (ndpi_protocol_category_t)lua_tointeger(vm, 3);
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TSTRING) != CONST_LUA_OK) {
lua_pushinteger(vm, (int)num_lines_loaded);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
listname = (char*)lua_tostring(vm, 4);
if (ntop_lua_check(vm, __FUNCTION__, 5, LUA_TBOOLEAN) == CONST_LUA_OK)
ignorePrivateIPs = (bool)lua_toboolean(vm, 5);
if ((fd = fopen(path, "r")) == NULL) {
ntop->getTrace()->traceEvent(TRACE_NORMAL,
"Unable to open category list in %s", path);
lua_pushinteger(vm, (int)num_lines_loaded);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
switch (list_type) {
case list_type_hosts:
format = "%s\t%s";
break;
case list_type_ip_csv:
format = "%[^,],%lf";
break;
case list_type_ip_occurrencies:
format = "%s\t%d";
break;
case list_type_ip:
format = "%s";
break;
default:
format = NULL;
break;
}
while (1) {
char buffer[256];
char* line = fgets(buffer, sizeof(buffer), fd);
int len;
if (line == NULL || format == NULL) break;
len = strlen(line);
if ((len <= 1) || (line[0] == '#')) continue;
if ((line[len - 1] == '\n') || (line[len - 1] == '\r'))
line[len - 1] = '\0';
switch (list_type) {
case list_type_hosts:
case list_type_ip_csv:
case list_type_ip: {
/*o
Format
127.0.0.1 domainname
127.0.0.1,domainname
*/
char host[256], ignore[64];
bool loaded = false, success;
double f;
if (list_type == list_type_ip)
success = (sscanf(line, format, host) == 1) ? true : false;
else if (list_type == list_type_hosts)
success = (sscanf(line, format, ignore, host) == 2) ? true : false;
else
success = (sscanf(line, format, host, &f) == 2) ? true : false;
if (success) {
if (is_valid_host(host, list_type, ignorePrivateIPs)) {
if (list_type == list_type_hosts)
success = ntop->nDPILoadHostnameCategory(host, catid, listname);
else
success = ntop->nDPILoadIPCategory(host, catid, listname);
if (success) num_lines_loaded++, loaded = true;
}
}
if (!loaded
/* Silence Stratosphere Lab.txt (it has 2 possible formatting) */
&& (strcmp(line, "ip,score") &&
strcmp(line, "Number,IP address,Rating"))) {
num_bad_lines++;
if (warn_once) {
ntop->getTrace()->traceEvent(
TRACE_NORMAL, "Invalid line format %s%s [%s]",
ignorePrivateIPs ? "or private IP " : "", line, path);
warn_once = false;
}
}
} break;
case list_type_ip_occurrencies: {
/*
Format
127.0.0.1 occurrencies
*/
char host[64];
int occurrencies;
bool loaded = false;
if (sscanf(line, format, host, &occurrencies) == 2) {
if (is_valid_host(host, list_type, ignorePrivateIPs)) {
if (occurrencies >= 2) {
if (ntop->nDPILoadIPCategory(host, catid, listname))
num_lines_loaded++, loaded = true;
} else
continue;
}
}
if (!loaded) {
num_bad_lines++;
if (warn_once) {
ntop->getTrace()->traceEvent(
TRACE_ERROR, "Invalid line format %s [%s]", line, path);
warn_once = false;
}
}
} break;
default:
/* Not reached */
break;
}
} /* while */
fclose(fd);
if (num_bad_lines > 1) {
ntop->getTrace()->traceEvent(TRACE_ERROR, "%u invalid lines [%s]",
num_bad_lines - 1, path);
}
lua_pushinteger(vm, (int)num_lines_loaded);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* NOTE: ntop.initnDPIReload() must be called before this */
/* @brief Commits the nDPI category hot-reload started by initnDPIReload. Lua: ntop.finalizenDPIReload() → boolean */
static int ntop_finalizenDPIReload(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "Starting category lists reload");
ntop->finalizenDPIReload();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "Category lists reload done");
ntop->setLastInterfacenDPIReload(time(NULL));
ntop->setnDPICleanupNeeded(true);
lua_pushboolean(vm, true /* reload performed */);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the custom category id that matches a hostname, or nil. Lua: ntop.matchCustomCategory(hostname) → integer|nil */
static int ntop_match_custom_category(lua_State* vm) {
char* host_to_match;
NetworkInterface* iface;
ndpi_protocol_category_t match;
ndpi_protocol_breed_t breed;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
iface = ntop->getFirstInterface();
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
host_to_match = (char*)lua_tostring(vm, 1);
if ((!iface) || (ndpi_get_custom_category_match(
iface->get_ndpi_struct(), host_to_match,
strlen(host_to_match), &match, &breed) != 0))
lua_pushnil(vm);
else {
/* Remember to unshift `match` (see Ntop::nDPILoadHostnameCategory) */
lua_pushinteger(vm, ((int)match) & 0xFF);
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the human-readable TLS version string for a numeric id. Lua: ntop.getTLSVersionName(id) → string */
static int ntop_get_tls_version_name(lua_State* vm) {
u_int16_t tls_version;
u_int8_t unknown_version = 0;
char buf[32];
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
tls_version = (u_int16_t)lua_tonumber(vm, 1);
lua_pushstring(vm, ndpi_ssl_version2str(buf, sizeof(buf), tls_version,
&unknown_version));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Expands a 48-bit MAC address string to 64-bit EUI-64 format. Lua: ntop.getMac64(mac) → number */
static int ntop_get_mac_64(lua_State* vm) {
char* mac_str;
u_int8_t mac[6];
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
mac_str = (char*)lua_tostring(vm, 1);
Utils::parseMac(mac, mac_str);
lua_pushnumber(vm, Utils::encodeMacTo64(mac));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Decodes a 64-bit EUI-64 address back to 48-bit MAC format. Lua: ntop.decodeMac64(mac64) → string */
static int ntop_decode_mac_64(lua_State* vm) {
u_int64_t mac64;
u_int8_t mac[6];
char buf[20];
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
mac64 = lua_tonumber(vm, 1);
Utils::decode64ToMac(mac64, mac);
lua_pushstring(vm, Utils::formatMacAddress(mac, buf, sizeof(buf)));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the given address string is an IPv6 address. Lua: ntop.isIPv6(ip) → boolean */
static int ntop_is_ipv6(lua_State* vm) {
char* ip;
struct in6_addr addr6;
bool rv;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ip = (char*)lua_tostring(vm, 1);
if (!ip || (inet_pton(AF_INET6, ip, &addr6) != 1))
rv = false;
else
rv = true;
lua_pushboolean(vm, rv);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns execution statistics for all flow check scripts. Lua: ntop.getFlowChecksStats() → table|nil */
static int ntop_get_flow_checks_stats(lua_State* vm) {
FlowChecksLoader* fcl = ntop->getFlowChecksLoader();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (fcl)
fcl->lua(vm);
else
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Triggers a hot-reload of flow check scripts. Lua: ntop.reloadFlowChecks() → nil */
static int ntop_reload_flow_checks(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->reloadFlowChecks();
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Triggers a hot-reload of host check scripts. Lua: ntop.reloadHostChecks() → nil */
static int ntop_reload_host_checks(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->reloadHostChecks();
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the default risk score for a flow alert type id. Lua: ntop.getFlowAlertScore(alert_id) → integer */
static int ntop_get_flow_alert_score(lua_State* vm) {
FlowAlertTypeEnum alert_id;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
alert_id = (FlowAlertTypeEnum)lua_tonumber(vm, 1);
lua_pushinteger(vm, ntop->getFlowAlertScore(alert_id));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns a table of all known flow risk ids and their names. Lua: ntop.getRiskList() → table */
static int ntop_get_risk_list(lua_State* vm) {
lua_newtable(vm);
for (int i = 0; i < NDPI_MAX_RISK; i++) {
lua_pushstring(vm, ntop->getRiskStr((ndpi_risk_enum)i));
lua_rawseti(vm, -2, i + 1);
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#define MAX_RSP_LEN 512
bool check_network_entry(char* ip_addr, char* rsp, void* user_data) {
AddressTree* at = (AddressTree*)user_data;
char a[64], *slash;
u_int8_t network_mask_bits;
snprintf(a, sizeof(a), "%s", ip_addr);
slash = strchr(a, '/');
if (slash != NULL) slash[0] = '\0'; /* Remove slash if present */
if (at->find(a, &network_mask_bits) != -1) {
/* Overlapping address */
bool ok = false;
if (slash != NULL) {
if (atoi(&slash[1]) > network_mask_bits) {
/* This is smaller subnet, so we accept it */
ok = true;
}
}
if (!ok) {
snprintf(rsp, MAX_RSP_LEN, "Overlapping address error %s", ip_addr);
return (false);
}
}
at->addAddress(ip_addr);
return true;
}
/*
This function is called whenever a new network configuration is is
modified/defined.
*/
/* @brief Evaluates and returns the network policy applicable to an IP address. Lua: ntop.checkNetworkPolicy(ip) → table */
static int ntop_check_network_policy(lua_State* vm) {
char *local_devices, *corporate_devices, *whitelisted_networks;
char* rsp = NULL;
AddressTree at;
lua_newtable(vm);
if ((rsp = (char*)malloc(MAX_RSP_LEN)) == NULL) {
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((local_devices = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((corporate_devices = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((whitelisted_networks = (char*)lua_tostring(vm, 3)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
/*
We need to check if the networks are well defined and if there are no
overlaps in networks
*/
if (!Utils::checkNetworkList(local_devices, rsp, check_network_entry,
(void*)&at)) {
lua_push_bool_table_entry(vm, "error", true);
lua_push_str_table_entry(vm, "error_msg", rsp);
goto free;
}
if (!Utils::checkNetworkList(corporate_devices, rsp, check_network_entry,
(void*)&at)) {
lua_push_bool_table_entry(vm, "error", true);
lua_push_str_table_entry(vm, "error_msg", rsp);
goto free;
}
if (!Utils::checkNetworkList(whitelisted_networks, rsp, check_network_entry,
(void*)&at)) {
lua_push_bool_table_entry(vm, "error", true);
lua_push_str_table_entry(vm, "error_msg", rsp);
goto free;
}
lua_push_bool_table_entry(vm, "error", false);
lua_push_str_table_entry(vm, "error_msg", "");
free:
if (rsp) free(rsp);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the human-readable name string for a flow risk id. Lua: ntop.getRiskStr(risk_id) → string */
static int ntop_get_risk_str(lua_State* vm) {
ndpi_risk_enum risk_id;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
risk_id = (ndpi_risk_enum)lua_tonumber(vm, 1);
lua_pushstring(vm, ntop->getRiskStr(risk_id));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the nDPI risk id associated with a flow alert type. Lua: ntop.getFlowAlertRisk(alert_id) → integer */
static int ntop_get_flow_alert_risk(lua_State* vm) {
FlowAlertTypeEnum alert_id;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
alert_id = (FlowAlertTypeEnum)lua_tonumber(vm, 1);
lua_pushinteger(vm, ntop->getFlowAlertRisk(alert_id));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns a table mapping nDPI risk ids to corresponding flow alert types. Lua: ntop.getFlowRiskAlerts() → table */
static int ntop_get_flow_risk_alerts(lua_State* vm) {
FlowRiskAlerts::lua(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns metadata table for a specific flow check. Lua: ntop.getFlowCheckInfo(check_id) → table|nil */
static int ntop_get_flow_check_info(lua_State* vm) {
const char* check_name;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
check_name = lua_tostring(vm, 1);
if (!ntop->luaFlowCheckInfo(vm, check_name)) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns metadata table for a specific host check. Lua: ntop.getHostCheckInfo(check_id) → table|nil */
static int ntop_get_host_check_info(lua_State* vm) {
const char* check_name;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
check_name = lua_tostring(vm, 1);
if (!ntop->luaHostCheckInfo(vm, check_name)) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Triggers a reload of alert exclusion rules from configuration. Lua: ntop.reloadAlertExclusions() → nil */
static int ntop_reload_alert_exclusions(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->reloadAlertExclusions();
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if DNS resolution should be attempted for this host. Lua: ntop.shouldResolveHost(ip) → boolean */
static int ntop_should_resolve_host(lua_State* vm) {
char* ip;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((ip = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm, Utils::shouldResolveHost(ip));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Sets the whitelist of allowed IEC 104 SCADA type identifiers. Lua: ntop.setIEC104AllowedTypeIDs(ids_table) → boolean */
static int ntop_set_iec104_allowed_typeids(lua_State* vm) {
char* typeids;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((typeids = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ntop->getPrefs()->setIEC104AllowedTypeIDs(typeids);
lua_pushboolean(vm, true);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if flow deduplication is active. Lua: ntop.isFlowDedupEnabled() → boolean */
static int ntop_is_flow_deduplication_enabled(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->getPrefs()->isFlowDedupEnabled());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#ifdef NTOPNG_PRO
/* @brief Sets the whitelist of allowed Modbus function codes (Pro only). Lua: ntop.setModbusAllowedFunctionCodes(codes_table) → boolean */
static int ntop_set_modbus_allowed_function_codes(lua_State* vm) {
char* function_codes;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((function_codes = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ntop->getPrefs()->setModbusAllowedFunctionCodes(function_codes);
lua_pushboolean(vm, true);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
/* ****************************************** */
/* @brief Temporarily re-acquires elevated write capabilities on Unix. Lua: ntop.gainWriteCapabilities() → boolean */
static int ntop_gainWriteCapabilities(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, Utils::gainWriteCapabilities() == 0);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Drops back to low-privilege mode after gainWriteCapabilities. Lua: ntop.dropWriteCapabilities() → boolean */
static int ntop_dropWriteCapabilities(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, Utils::dropWriteCapabilities() == 0);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the well-known service name for a port/protocol pair. Lua: ntop.getservbyport(port, proto) → string|nil */
static int ntop_getservbyport(lua_State* vm) {
int port;
char* proto;
struct servent* s = NULL;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
port = (int)lua_tonumber(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
proto = (char*)lua_tostring(vm, 2);
if ((port > 0) && (proto != NULL)) s = getservbyport(htons(port), proto);
if (s && s->s_name)
lua_pushstring(vm, s->s_name);
else {
char buf[32];
snprintf(buf, sizeof(buf), "%d", port);
lua_pushstring(vm, buf);
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Sleeps for the given number of milliseconds. Lua: ntop.msleep(ms) → nil */
static int ntop_msleep(lua_State* vm) {
u_int ms_duration, max_duration = 60000 /* 1 min */;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ms_duration = (u_int)lua_tonumber(vm, 1);
if (ms_duration > max_duration) ms_duration = max_duration;
_usleep(ms_duration * 1000);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* https://www.linuxquestions.org/questions/programming-9/connect-timeout-change-145433/
*/
static int non_blocking_connect(int sock, struct sockaddr_in* sa, int timeout) {
int flags = 0, error = 0, ret = 0;
fd_set rset, wset;
socklen_t len = sizeof(error);
// clear out descriptor sets for select
// add socket to the descriptor sets
FD_ZERO(&rset);
FD_SET(sock, &rset);
wset = rset; // structure assignment ok
#ifdef WIN32
// Windows sockets are created in blocking mode by default
// currently on windows, there is no easy way to obtain the socket's current
// blocking mode since WSAIsBlocking was deprecated
u_long f = 1;
if (ioctlsocket(sock, FIONBIO, &f) != NO_ERROR) return -1;
#else
// set socket nonblocking flag
if ((flags = fcntl(sock, F_GETFL, 0)) < 0) return -1;
if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) return -1;
#endif
// initiate non-blocking connect
if ((ret = connect(sock, (struct sockaddr*)sa, sizeof(struct sockaddr_in))) <
0)
if (errno != EINPROGRESS) return -1;
if (ret == 0) // then connect succeeded right away
goto done;
// we are waiting for connect to complete now
if ((ret = Utils::pollSocket(sock,
timeout ? (timeout * 1000) : -1 /* wait */)) < 0)
return -1;
if (ret == 0) {
// we had a timeout
errno = ETIMEDOUT;
return -1;
}
// we had a positivite return so a descriptor is ready
if (FD_ISSET(sock, &rset) || FD_ISSET(sock, &wset)) {
if (getsockopt(sock, SOL_SOCKET, SO_ERROR,
#ifdef WIN32
(char*)
#endif
&error,
&len) < 0) {
return -1;
}
} else {
return -1;
}
if (error) { // check if we had a socket error
errno = error;
return -1;
}
done:
#ifdef WIN32
f = 0;
if (ioctlsocket(sock, FIONBIO, &f) != NO_ERROR) return -1;
#else
// put socket back in blocking mode
if (fcntl(sock, F_SETFL, flags) < 0) return -1;
#endif
return 0;
}
/* ****************************************** */
/* Millisecond sleep */
/* @brief Tests TCP reachability; returns true if connection succeeds. Lua: ntop.tcpProbe(host, port[, timeout]) → string|nil */
static int ntop_tcp_probe(lua_State* vm) {
char* server_ip;
u_int server_port, timeout = 3;
int sockfd;
struct sockaddr_in serv_addr;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
server_ip = (char*)lua_tostring(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
server_port = (u_int)lua_tonumber(vm, 2);
if (lua_type(vm, 3) == LUA_TNUMBER) timeout = (u_int16_t)lua_tonumber(vm, 3);
if ((sockfd = Utils::openSocket(AF_INET, SOCK_STREAM, 0, "Lua TCP Probe")) <
0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(server_port);
serv_addr.sin_addr.s_addr = inet_addr(server_ip);
if (non_blocking_connect(sockfd, &serv_addr, timeout) < 0)
lua_pushnil(vm);
else {
u_int timeout = 1, offset = 0;
char buf[512];
while (true) {
int rc;
rc = Utils::pollSocket(sockfd, timeout * 1000);
timeout = 0;
if (rc <= 0)
break;
else {
int l = read(sockfd, &buf[offset], sizeof(buf) - offset - 1);
if (l <= 0)
break;
else
offset += l;
}
}
buf[offset] = 0;
lua_pushstring(vm, buf);
}
Utils::closeSocket(sockfd);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns a table listing filenames in the given directory. Lua: ntop.readdir(path) → table */
static int ntop_list_dir_files(lua_State* vm) {
char* path;
DIR* dirp;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
path = (char*)lua_tostring(vm, 1);
ntop->fixPath(path);
ntop->getTrace()->traceEvent(TRACE_DEBUG, "Listing directory %s", path);
lua_newtable(vm);
if ((dirp = opendir(path)) != NULL) {
struct dirent* dp;
while ((dp = readdir(dirp)) != NULL)
if ((dp->d_name[0] != '\0') && (dp->d_name[0] != '.')) {
lua_push_str_table_entry(vm, dp->d_name, dp->d_name);
}
(void)closedir(dirp);
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Recursively removes a directory and all its contents. Lua: ntop.rmdir(path) → boolean */
static int ntop_remove_dir_recursively(lua_State* vm) {
char* path = NULL;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (lua_type(vm, 1) == LUA_TSTRING) path = (char*)lua_tostring(vm, 1);
if (path) ntop->fixPath(path);
lua_pushboolean(vm, path && !Utils::remove_recursively(path)
? true /* OK */
: false /* Errors */);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Deletes a single file. Lua: ntop.unlink(path) → boolean */
static int ntop_unlink_file(lua_State* vm) {
char* path = NULL;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (lua_type(vm, 1) == LUA_TSTRING) path = (char*)lua_tostring(vm, 1);
if (path) ntop->fixPath(path);
lua_pushboolean(
vm, path && (unlink(path) == 0) ? true /* OK */ : false /* Errors */);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Registers a runtime PCAP or DB interface from Lua. Lua: ntop.registerRuntimeInterface(params) → integer */
static int ntop_register_runtime_interface(lua_State* vm) {
char *source = NULL, *name = NULL;
int if_id = -1, new_if_id = -99;
bool create_new_interface;
NetworkInterface* iface = getCurrentInterface(vm);
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (lua_type(vm, 1) == LUA_TSTRING) source = (char*)lua_tostring(vm, 1);
if (lua_type(vm, 2) == LUA_TSTRING) name = (char*)lua_tostring(vm, 2);
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
create_new_interface = (bool)lua_toboolean(vm, 3);
if (lua_type(vm, 4) == LUA_TNUMBER) {
if_id = (u_int32_t)lua_tonumber(vm, 4);
create_new_interface = false;
}
if (create_new_interface) {
if ((!ntop->isUserAdministrator(vm)) || (source == NULL) ||
(ntop->get_num_interfaces() >= MAX_NUM_DEFINED_INTERFACES)) {
; /* No way */
} else {
if_id = -1; /* -1 = allocate new interface */
bool rc = ntop->createRuntimeInterface(name, source, &if_id);
if (rc) new_if_id = if_id;
}
} else {
/* Upload pcap on this interface */
if (if_id == -1) if_id = iface->get_id();
bool rc = ntop->createRuntimeInterface(name, source, &if_id);
if (rc) new_if_id = if_id;
}
lua_pushinteger(vm, new_if_id);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#if defined(NTOPNG_PRO) && defined(HAVE_KAFKA)
/* @brief Publishes a message to a Kafka topic (Pro + Kafka build). Lua: ntop.sendKafkaMessage(topic, msg) → boolean */
static int ntop_send_kafka_message(lua_State* vm) {
char *kafka_broker_info, *message;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
/* <brokers>;<topic>;<options> */
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
kafka_broker_info = (char*)lua_tostring(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
message = (char*)lua_tostring(vm, 2);
if (kafka_broker_info && message)
lua_pushboolean(vm, ntop->sendKafkaMessage(kafka_broker_info, message,
strlen(message)));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
/* ****************************************** */
/* @brief Returns the current time as a floating-point millisecond timestamp. Lua: ntop.gettimemsec() → number */
static int ntop_gettimemsec(lua_State* vm) {
struct timeval tp;
double ret;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
gettimeofday(&tp, NULL);
ret = (((double)tp.tv_usec) / (double)1000000) + tp.tv_sec;
lua_pushnumber(vm, ret);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the current CPU tick counter value. Lua: ntop.getticks() → number */
static int ntop_getticks(lua_State* vm) {
lua_pushnumber(vm, Utils::getticks());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the number of CPU ticks per second. Lua: ntop.gettickspersec() → number */
static int ntop_gettickspersec(lua_State* vm) {
lua_pushnumber(vm, Utils::gettickspersec());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/**
* @brief Refreshes the timezone after a change
*
* @param vm The lua state.
* @return CONST_LUA_OK.
*/
/* @brief Refreshes the process timezone from the TZ environment variable. Lua: ntop.tzset() → nil */
static int ntop_tzset(lua_State* vm) {
#ifndef WIN32
tzset();
#endif
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Rounds a Unix epoch down to the nearest multiple of secs. Lua: ntop.roundTime(epoch, secs[, tz]) → integer */
static int ntop_round_time(lua_State* vm) {
time_t now;
u_int32_t rounder;
bool align_to_localtime;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
now = lua_tonumber(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
rounder = lua_tonumber(vm, 2);
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
align_to_localtime = lua_toboolean(vm, 3);
lua_pushinteger(
vm, Utils::roundTime(now, rounder,
align_to_localtime ? ntop->get_time_offset() : 0));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Converts a 32-bit integer to an IPv4 dotted-decimal string. Lua: ntop.inet_ntoa(n) → string */
static int ntop_inet_ntoa(lua_State* vm) {
u_int32_t ip;
struct in_addr in;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (lua_type(vm, 1) == LUA_TSTRING)
ip = atol((char*)lua_tostring(vm, 1));
else if (lua_type(vm, 1) == LUA_TNUMBER)
ip = (u_int32_t)lua_tonumber(vm, 1);
else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
in.s_addr = htonl(ip);
lua_pushstring(vm, inet_ntoa(in));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Converts an IPv4 dotted-decimal string to a 32-bit integer. Lua: ntop.ipToNumber(ip) → integer */
static int ntop_ip_to_number(lua_State* vm) {
char* device_ip = NULL;
struct in_addr addr;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
device_ip = (char*)lua_tostring(vm, 1);
if (inet_pton(AF_INET, device_ip, &addr) != 1)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushinteger(vm, ntohl(addr.s_addr));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#ifndef HAVE_NEDGE
/* @brief Broadcasts a string message to the IPS subsystem (non-nEdge only). Lua: ntop.broadcastIPSMessage(msg) → nil */
static int ntop_brodcast_ips_message(lua_State* vm) {
char* msg;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
msg = (char*)lua_tostring(vm, 1);
ntop->broadcastIPSMessage(msg);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* @brief Returns true if IPS rules are due for a periodic refresh. Lua: ntop.timeToRefreshIPSRules() → boolean */
static int ntop_time_to_refresh_ips_rules(lua_State* vm) {
/* Read and reset the variable */
lua_pushboolean(vm, ntop->timeToRefreshIPSRules());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* @brief Signals the IPS subsystem to refresh its rules. Lua: ntop.askToRefreshIPSRules() → boolean */
static int ntop_ask_to_refresh_ips_rules(lua_State* vm) {
ntop->askToRefreshIPSRules();
lua_pushboolean(vm, true);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Connects to a ZMQ publisher endpoint (non-nEdge builds with ZMQ support). Lua: ntop.zmq_connect(endpoint, topic) → nil */
static int ntop_zmq_connect(lua_State* vm) {
char *endpoint, *topic;
void *context, *subscriber;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
#ifdef HAVE_ZMQ
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((endpoint = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((topic = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
context = zmq_ctx_new(), subscriber = zmq_socket(context, ZMQ_SUB);
if (zmq_connect(subscriber, endpoint) != 0) {
zmq_close(subscriber);
zmq_ctx_destroy(context);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
}
if (zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, topic, strlen(topic)) != 0) {
zmq_close(subscriber);
zmq_ctx_destroy(context);
return -1;
}
getLuaVMUservalue(vm, zmq_context) = context;
getLuaVMUservalue(vm, zmq_subscriber) = subscriber;
#endif
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
/* ****************************************** */
/* @brief Returns Redis memory usage and command execution statistics. Lua: ntop.getCacheStats() → table */
static int ntop_get_redis_stats(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->getRedis()->lua(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Deletes a key (or pattern of keys) from Redis. Lua: ntop.delCache(key) → nil */
static int ntop_delete_redis_key(lua_State* vm) {
char* key;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ntop->getRedis()->del(key);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Atomically renames a Redis key. Lua: ntop.renameCache(old_key, new_key) → nil */
static int ntop_rename_redis_key(lua_State* vm) {
char *key, *new_key;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((new_key = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ntop->getRedis()->rename(key, new_key);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Flushes ALL Redis data — destructive operation, admin only. Lua: ntop.flushCache() → boolean */
static int ntop_flush_redis(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushboolean(vm, (ntop->getRedis()->flushDb() == 0) ? true : false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Adds a member to a Redis set. Lua: ntop.setMembersCache(key, member) → nil */
static int ntop_add_set_member_redis(lua_State* vm) {
char *key, *value;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((value = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop->getRedis()->sadd(key, value) == 0) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
/* ****************************************** */
/* @brief Removes a member from a Redis set. Lua: ntop.delMembersCache(key, member) → nil */
static int ntop_del_set_member_redis(lua_State* vm) {
char *key, *value;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((value = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop->getRedis()->srem(key, value) == 0) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
/* ****************************************** */
/* @brief Returns all members of a Redis set as a Lua table. Lua: ntop.getMembersCache(key) → table */
static int ntop_get_set_members_redis(lua_State* vm) {
char* key;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ntop->getRedis()->smembers(vm, key);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#ifdef HAVE_ZMQ
#ifndef HAVE_NEDGE
/* @brief Disconnects from the previously connected ZMQ publisher endpoint. Lua: ntop.zmq_disconnect() → nil */
static int ntop_zmq_disconnect(lua_State* vm) {
void* context;
void* subscriber;
context = getLuaVMUserdata(vm, zmq_context);
subscriber = getLuaVMUserdata(vm, zmq_subscriber);
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
zmq_close(subscriber);
zmq_ctx_destroy(context);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
/* ****************************************** */
#ifndef HAVE_NEDGE
/* @brief Receives and returns the next message from the active ZMQ subscription. Lua: ntop.zmq_receive() → string */
static int ntop_zmq_receive(lua_State* vm) {
NetworkInterface* curr_iface = getCurrentInterface(vm);
void* subscriber;
int size;
struct zmq_msg_hdr_v1 h;
char* payload;
int payload_len;
zmq_pollitem_t item;
int rc;
subscriber = getLuaVMUserdata(vm, zmq_subscriber);
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
item.socket = subscriber;
item.events = ZMQ_POLLIN;
do {
rc = zmq_poll(&item, 1, 1000);
if (rc < 0 || !curr_iface->isRunning()) /* CHECK */
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
} while (rc == 0);
size = zmq_recv(subscriber, &h, sizeof(h), 0);
if (size != sizeof(h) || h.version != ZMQ_MSG_VERSION) {
ntop->getTrace()->traceEvent(
TRACE_WARNING, "Unsupported publisher version [%d]", h.version);
return -1;
}
payload_len = h.size + 1;
if ((payload = (char*)malloc(payload_len)) != NULL) {
size = zmq_recv(subscriber, payload, payload_len, 0);
payload[h.size] = '\0';
if (size > 0) {
enum json_tokener_error jerr = json_tokener_success;
json_object* o = json_tokener_parse_verbose(payload, &jerr);
if (o != NULL) {
struct json_object_iterator it = json_object_iter_begin(o);
struct json_object_iterator itEnd = json_object_iter_end(o);
while (!json_object_iter_equal(&it, &itEnd)) {
char* key = (char*)json_object_iter_peek_name(&it);
const char* value =
json_object_get_string(json_object_iter_peek_value(&it));
ntop->getTrace()->traceEvent(TRACE_NORMAL, "[%s]=[%s]", key, value);
json_object_iter_next(&it);
}
json_object_put(o);
} else
ntop->getTrace()->traceEvent(TRACE_WARNING, "JSON Parse error [%s]: %s",
json_tokener_error_desc(jerr), payload);
lua_pushfstring(vm, "%s", payload);
ntop->getTrace()->traceEvent(TRACE_INFO, "[%u] %s", h.size, payload);
free(payload);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else {
free(payload);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
}
} else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
}
#endif
#endif
/* ****************************************** */
/* @brief Reloads all system preferences from Redis into process memory. Lua: ntop.reloadPreferences([set_defaults]) → nil */
static int ntop_reload_preferences(lua_State* vm) {
bool set_redis_defaults = false;
if (lua_type(vm, 1) == LUA_TBOOLEAN)
set_redis_defaults = lua_toboolean(vm, 1) ? true : false;
if (set_redis_defaults) ntop->getRedis()->setDefaults();
ntop->getPrefs()->reloadPrefsFromRedis();
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Applies default ntopng file permissions (0640) to a path (Unix only). Lua: ntop.setDefaultFilePermissions(path) → nil */
static int ntop_set_default_file_permissions(lua_State* vm) {
char* fpath;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
fpath = (char*)lua_tostring(vm, 1);
if (!fpath) return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
#ifndef WIN32
chmod(fpath, CONST_DEFAULT_FILE_MODE);
#endif
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Logs a message only when verbose tracing mode is enabled. Lua: ntop.verboseTrace(msg) → nil */
static int ntop_verbose_trace(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, (ntop->getTrace()->get_trace_level() == MAX_TRACE_LEVEL)
? true
: false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Sends a UDP datagram to the specified host and port. Lua: ntop.send_udp_data(host, port, data) → nil */
static int ntop_send_udp_data(lua_State* vm) {
int port;
char *host, *data;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
host = (char*)lua_tostring(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
port = (u_int16_t)lua_tonumber(vm, 2);
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
data = (char*)lua_tostring(vm, 3);
if (Utils::sendUDPData(host, port, data)) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else {
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
}
/* ****************************************** */
/* @brief Sends data over TCP to the specified host and port. Lua: ntop.send_tcp_data(host, port, data) → nil */
static int ntop_send_tcp_data(lua_State* vm) {
bool rv = true;
char *host, *data;
int port;
int timeout = 0;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((host = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
port = (int32_t)lua_tonumber(vm, 2);
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((data = (char*)lua_tostring(vm, 3)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
/* Optional timeout */
if (lua_type(vm, 4) == LUA_TNUMBER) timeout = lua_tonumber(vm, 4);
rv = Utils::sendTCPData(host, port, data, timeout);
lua_pushboolean(vm, rv);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the current periodic script is nearing its execution deadline. Lua: ntop.isDeadlineApproaching() → boolean */
static int ntop_script_is_deadline_approaching(lua_State* vm) {
NtopngLuaContext* ctx = getLuaVMContext(vm);
if (ctx && ctx->deadline && ctx->threaded_activity) {
ThreadedActivity* ta = (ThreadedActivity*)ctx->threaded_activity;
lua_pushboolean(vm, ta->isDeadlineApproaching(ctx->deadline));
} else
lua_pushboolean(vm, false);
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Returns the Unix epoch deadline for the current periodic script execution. Lua: ntop.getDeadline() → integer */
static int ntop_script_get_deadline(lua_State* vm) {
NtopngLuaContext* ctx = getLuaVMContext(vm);
lua_pushinteger(vm, ctx && ctx->deadline ? ctx->deadline : 0);
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Returns true if network speedtest functionality is compiled in. Lua: ntop.hasSpeedtestSupport() → boolean */
static int ntop_has_speedtest_support(lua_State* vm) {
#ifdef HAVE_EXPAT
lua_pushboolean(vm, true);
#else
lua_pushboolean(vm, false);
#endif
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Runs a network speedtest and returns download/upload/latency results (Pro). Lua: ntop.speedtest() → table */
static int ntop_speedtest(lua_State* vm) {
ntop->speedtest(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns IP blacklist hit counts and per-list statistics. Lua: ntop.getBlacklistStats() → table */
static int ntop_get_bl_stats(lua_State* vm) {
ntop->getBlacklistStats()->lua(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Resets all IP blacklist statistics counters to zero. Lua: ntop.resetBlacklistStats() → nil */
static int ntop_reset_bl_stats(lua_State* vm) {
ntop->resetBlacklistStats();
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the ClickHouse historical flows backend is active. Lua: ntop.isClickHouseEnabled() → boolean */
static int ntop_clickhouse_enabled(lua_State* vm) {
NetworkInterface* curr_iface = getCurrentInterface(vm);
bool enabled = ntop->getPrefs()->do_dump_flows_on_clickhouse();
/* Make sure database is enabled - e.g. not enabled on 'database'
* runtime interfaces */
if (curr_iface->getDB() == NULL) enabled = false;
lua_pushboolean(vm, enabled);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
// *** API ***
/* @brief Issues an HTTP 302 redirect to the given URL (for page-level Lua scripts). Lua: ntop.httpRedirect(url) → nil */
static int ntop_http_redirect(lua_State* vm) {
char *url, str[512];
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((url = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
build_redirect(url, NULL, str, sizeof(str));
lua_pushstring(vm, str);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
// *** API ***
/* @brief Performs an outbound HTTP GET request and optionally returns the response body. Lua: ntop.httpGet(url[,user,pass,timeout,return_content,...]) → string */
static int ntop_http_get(lua_State* vm) {
char *url, *username = NULL, *pwd = NULL;
int connection_timeout = 30, lifetime_timeout = 0;
bool return_content = true, use_cookie_authentication = false;
bool follow_redirects = true;
int ip_version = 0;
HTTPTranferStats stats;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((url = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 2) == LUA_TSTRING) {
username = (char*)lua_tostring(vm, 2);
if (lua_type(vm, 3) == LUA_TSTRING) {
pwd = (char*)lua_tostring(vm, 3);
}
}
if (lua_type(vm, 4) == LUA_TNUMBER) {
connection_timeout = lua_tointeger(vm, 4);
if (connection_timeout < 1) connection_timeout = 1;
}
/*
This optional parameter specifies if the result of HTTP GET has to be
returned to LUA or not. Usually the content has to be returned, but in some
causes it just matters to time (for instance when use for testing HTTP
services)
*/
if (lua_type(vm, 5) == LUA_TBOOLEAN) {
return_content = lua_toboolean(vm, 5) ? true : false;
}
if (lua_type(vm, 6) == LUA_TBOOLEAN) {
use_cookie_authentication = lua_toboolean(vm, 6) ? true : false;
}
if (lua_type(vm, 7) == LUA_TBOOLEAN) {
follow_redirects = lua_toboolean(vm, 7) ? true : false;
}
if (lua_type(vm, 8) == LUA_TNUMBER) ip_version = lua_tointeger(vm, 8);
Utils::httpGetPostPutPatch(
vm, url, username, pwd, NULL /* user_header_token */, connection_timeout,
lifetime_timeout, return_content, use_cookie_authentication, &stats, NULL,
NULL, follow_redirects, ip_version, method_get);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
// *** API ***
/* @brief Performs an HTTP GET with a Bearer authorization token header. Lua: ntop.httpGetAuthToken(url, token[,timeout,return_content,no_verify]) → string */
static int ntop_http_get_auth_token(lua_State* vm) {
char *url, *auth_token = NULL;
int connection_timeout = 30, lifetime_timeout = 0;
bool return_content = true, use_cookie_authentication = false;
bool follow_redirects = true;
int ip_version = 0;
HTTPTranferStats stats;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((url = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((auth_token = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 3) == LUA_TNUMBER) {
connection_timeout = lua_tointeger(vm, 3);
if (connection_timeout < 1) connection_timeout = 1;
}
/*
This optional parameter specifies if the result of HTTP GET has to be
returned to LUA or not. Usually the content has to be returned, but in some
causes it just matters to time (for instance when use for testing HTTP
services)
*/
if (lua_type(vm, 4) == LUA_TBOOLEAN)
return_content = lua_toboolean(vm, 4) ? true : false;
if (lua_type(vm, 5) == LUA_TBOOLEAN)
use_cookie_authentication = lua_toboolean(vm, 5) ? true : false;
if (lua_type(vm, 6) == LUA_TBOOLEAN)
follow_redirects = lua_toboolean(vm, 6) ? true : false;
if (lua_type(vm, 7) == LUA_TNUMBER) ip_version = lua_tointeger(vm, 7);
Utils::httpGetPostPutPatch(vm, url, NULL /* username */, NULL /* pwd */,
auth_token, connection_timeout, lifetime_timeout,
return_content, use_cookie_authentication, &stats,
NULL, NULL, follow_redirects, ip_version,
method_get);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the HTTP path prefix configured for this ntopng instance. Lua: ntop.getHttpPrefix() → string */
static int ntop_http_get_prefix(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushstring(vm, ntop->getPrefs()->get_http_prefix());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the Unix epoch when ntopng was last started. Lua: ntop.getStartupEpoch() → integer */
static int ntop_http_get_startup_epoch(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushinteger(vm, ntop->getLastModifiedStaticFileEpoch());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns an epoch value used for HTTP static-file cache busting. Lua: ntop.getStaticFileEpoch() → integer */
static int ntop_http_get_static_file_epoch(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushinteger(vm, ntop->getLastModifiedStaticFileEpoch());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Sanitizes a string to prevent XSS by removing dangerous characters. Lua: ntop.httpPurifyParam(str) → string */
static int ntop_http_purify_param(lua_State* vm) {
char *str, *buf;
bool strict = false, allowURL = true, allowDots = false;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
}
if ((str = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 2) == LUA_TBOOLEAN)
strict = lua_toboolean(vm, 2) ? true : false;
if (lua_type(vm, 3) == LUA_TBOOLEAN)
allowURL = lua_toboolean(vm, 3) ? true : false;
if (lua_type(vm, 4) == LUA_TBOOLEAN)
allowDots = lua_toboolean(vm, 4) ? true : false;
buf = strdup(str);
if (buf == NULL) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
}
Utils::purifyHTTPparam(buf, strict, allowURL, allowDots);
lua_pushstring(vm, buf);
free(buf);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns all current system preferences as a flat Lua table. Lua: ntop.getPrefs() → table */
static int ntop_get_prefs(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->getPrefs()->lua(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if raw ICMP ping is available on this system. Lua: ntop.isPingAvailable() → boolean */
static int ntop_is_ping_available(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->canSendICMP());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if ICMP ping is available on the given network interface. Lua: ntop.isPingIfaceAvailable(ifname) → boolean */
static int ntop_is_ping_iface_available(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->canSelectNetworkIfaceICMP());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Sends an ICMP ping to a host; use collectPingResults to retrieve RTT. Lua: ntop.pingHost(host, is_v6, iface) → nil */
static int ntop_ping_host(lua_State* vm) {
#ifdef WIN32
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
#else
char *host, *ifname = NULL;
bool is_v6;
bool continuous = false;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((host = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
is_v6 = (bool)lua_toboolean(vm, 2);
if (lua_type(vm, 3) == LUA_TBOOLEAN)
continuous = lua_toboolean(vm, 3) ? true : false;
if (lua_type(vm, 4) == LUA_TSTRING) ifname = (char*)lua_tostring(vm, 4);
if (!continuous) {
/* Ping one shot */
Ping* ping = ntop->getPing(ifname);
if (ping == NULL) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else
ping->ping(host, is_v6);
} else {
/* This is a continuous ping instead */
ContinuousPing* c = ntop->getContinuousPing();
if (c) {
c->start(); /* In case not started it will now start */
c->ping(host, is_v6, ifname);
} else {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
#endif
}
/* ****************************************** */
/* @brief Collects and returns RTT results from recently sent pings. Lua: ntop.collectPingResults() → table */
static int ntop_collect_ping_results(lua_State* vm) {
#ifdef WIN32
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
#else
bool continuous = false;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
continuous = lua_toboolean(vm, 1) ? true : false;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!continuous) {
/* Ping one shot */
ntop->collectResponses(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else {
ntop->collectContinuousResponses(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
}
/* ****************************************** */
/* @brief Returns a table of interface names usable for ICMP ping. Lua: ntop.getPingIfNames() → table */
static int ntop_get_ping_interface_names(lua_State* vm) {
#ifndef WIN32
ContinuousPing* cping = ntop->getContinuousPing();
#endif
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_newtable(vm);
#ifndef WIN32
if (cping) cping->getAllInterfaces(vm);
#endif
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the special no-login username constant used for unauthenticated access. Lua: ntop.getNologinUser() → string */
static int ntop_get_nologin_username(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushstring(vm, NTOP_NOLOGIN_USER);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns a table of all configured users with their attributes. Lua: ntop.getUsers() → table */
static int ntop_get_users(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->getUsers(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the network CIDRs visible to the current user. Lua: ntop.getAllowedNetworks() → table */
static int ntop_get_allowed_networks(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->getAllowedNetworks(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the current user has permission to download PCAP files. Lua: ntop.isPcapDownloadAllowed() → boolean */
static int ntop_is_pcap_download_allowed(lua_State* vm) {
NetworkInterface* curr_iface = getCurrentInterface(vm);
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->isPcapDownloadAllowed(vm, curr_iface->get_name()));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the current request is authenticated as an administrator. Lua: ntop.isAdministrator() → boolean */
static int ntop_is_administrator(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->isUserAdministrator(vm));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
static bool allowLocalUserManagement(lua_State* vm) {
if (!ntop->isLocalUser(vm) && !ntop->isLocalAuthEnabled()) return (false);
if (!ntop->isUserAdministrator(vm)) return (false);
return (true);
}
/* ****************************************** */
/* @brief Changes a user password (requires old password or admin privileges). Lua: ntop.resetUserPassword(who, username, old_pw, new_pw) → boolean */
static int ntop_reset_user_password(lua_State* vm) {
char *who, *username, *old_password, *new_password;
bool is_admin = ntop->isUserAdministrator(vm), ret;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
/* Username who requested the password change */
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((who = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((old_password = (char*)lua_tostring(vm, 3)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((new_password = (char*)lua_tostring(vm, 4)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
/* non-local users cannot change their local password */
if ((strcmp(who, username) == 0) && !ntop->isLocalUser(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
/* only the administrator can change other users passwords */
if ((strcmp(who, username) != 0) && !allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
/* only the administrator can use and empty old password */
if ((old_password[0] == '\0') && !is_admin)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ret = ntop->resetUserPassword(username, old_password, new_password);
lua_pushboolean(vm, ret);
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Changes a user role: administrator, unprivileged, or captivePortal. Lua: ntop.changeUserRole(username, role) → boolean */
static int ntop_change_user_role(lua_State* vm) {
char *username, *user_role;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((user_role = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm, ntop->changeUserRole(username, user_role));
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Updates the comma-separated allowed network CIDRs for a user. Lua: ntop.changeAllowedNets(username, nets_csv) → boolean */
static int ntop_change_allowed_nets(lua_State* vm) {
char *username, *allowed_nets;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((allowed_nets = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm, ntop->changeAllowedNets(username, allowed_nets));
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Updates the allowed interface restriction for a user. Lua: ntop.changeAllowedIfname(username, ifname) → boolean */
static int ntop_change_allowed_ifname(lua_State* vm) {
char *username, *allowed_ifname;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((allowed_ifname = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm, ntop->changeAllowedIfname(username, allowed_ifname));
return CONST_LUA_OK;
}
/* ****************************************** */
/*
* Set the host pool for a captive portal user on authentication
* (this is a 1-1 user-pool binding used for policy enforcement)
*/
/* @brief Sets the captive portal host pool for a user. Lua: ntop.changeUserHostPool(username, pool_id) → boolean */
static int ntop_change_user_host_pool(lua_State* vm) {
char *username, *host_pool_id;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((host_pool_id = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm, ntop->changeUserHostPool(username, host_pool_id));
return CONST_LUA_OK;
}
/* ****************************************** */
/* Set which pools an unprivileged user is allowed to view */
/* @brief Sets the host pools viewable by an unprivileged user. Lua: ntop.changeAllowedHostPools(username, pools) → boolean */
static int ntop_change_user_allowed_host_pools(lua_State* vm) {
char *username, *allowed_host_pools;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((allowed_host_pools = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm,
ntop->changeAllowedHostPools(username, allowed_host_pools));
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Returns the host pools the current user is allowed to see. Lua: ntop.getAllowedHostPools() → table */
static int ntop_get_allowed_host_pools(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->getAllowedHostPools(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Updates the display name for a user. Lua: ntop.changeUserFullName(username, full_name) → boolean */
static int ntop_change_user_full_name(lua_State* vm) {
char *username, *full_name;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((full_name = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm, ntop->changeUserFullName(username, full_name));
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Updates the UI language preference for a user. Lua: ntop.changeUserLanguage(username, lang) → boolean */
static int ntop_change_user_language(lua_State* vm) {
char *username, *language;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((language = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm, ntop->changeUserLanguage(username, language));
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Grants or revokes historical flow data access for a user. Lua: ntop.changeHistoricalFlowPermission(username, allow) → boolean */
static int ntop_change_user_historical_flow_permission(lua_State* vm) {
char* username;
bool allow_historical_flows = false;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
allow_historical_flows = lua_toboolean(vm, 2) ? true : false;
lua_pushboolean(vm, ntop->changeUserHistoricalFlowPermission(
username, allow_historical_flows));
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Grants or revokes alerts viewing permission for a user. Lua: ntop.changeAlertsPermission(username, allow) → boolean */
static int ntop_change_user_alerts_permission(lua_State* vm) {
char* username;
bool allow_alerts = false;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
allow_alerts = lua_toboolean(vm, 2) ? true : false;
lua_pushboolean(vm, ntop->changeUserAlertsPermission(username, allow_alerts));
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Grants or revokes PCAP download permission for a user. Lua: ntop.changePcapDownloadPermission(username, allow) → boolean */
static int ntop_change_user_pcap_download_permission(lua_State* vm) {
char* username;
bool allow_pcap_download = false;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
allow_pcap_download = lua_toboolean(vm, 2) ? true : false;
lua_pushboolean(vm, ntop->changeUserPcapDownloadPermission(
username, allow_pcap_download));
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Posts a JSON string body to a URL via HTTP POST. Lua: ntop.postHTTPJsonData(url, json_body) → boolean */
static int ntop_post_http_json_data(lua_State* vm) {
char *username, *password, *url, *json, *bearer_token = NULL;
HTTPTranferStats stats;
int connection_timeout = 0, lifetime_timeout = 0;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((password = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((url = (char*)lua_tostring(vm, 3)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((json = (char*)lua_tostring(vm, 4)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
/* Optional connection timeout */
if (lua_type(vm, 5) == LUA_TNUMBER) connection_timeout = lua_tonumber(vm, 5);
/* Optional Bearer Token */
if (lua_type(vm, 6) == LUA_TSTRING) bearer_token = (char*)lua_tostring(vm, 6);
bool rv =
Utils::postHTTPJsonData(bearer_token, username, password, url, json,
connection_timeout, lifetime_timeout, &stats);
lua_pushboolean(vm, rv);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Performs an outbound HTTP POST request. Lua: ntop.httpPost(url, body[,user,pass,timeout,return_content,content_type]) → string */
static int ntop_http_post(lua_State* vm) {
char *username = (char*)"", *password = (char*)"", *url, *form_data;
int connection_timeout = 30, lifetime_timeout = 0;
bool return_content = false;
bool use_cookie_authentication = false;
HTTPTranferStats stats;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((url = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((form_data = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 3) == LUA_TSTRING) /* Optional */
if ((username = (char*)lua_tostring(vm, 3)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 4) == LUA_TSTRING) /* Optional */
if ((password = (char*)lua_tostring(vm, 4)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 5) == LUA_TNUMBER) /* Optional */
connection_timeout = lua_tonumber(vm, 5);
if (lua_type(vm, 6) == LUA_TBOOLEAN) /* Optional */
return_content = lua_toboolean(vm, 6) ? true : false;
if (lua_type(vm, 7) == LUA_TBOOLEAN) /* Optional */
use_cookie_authentication = lua_toboolean(vm, 7) ? true : false;
Utils::httpGetPostPutPatch(
vm, url, username, password, NULL /* user_header_token */,
connection_timeout, lifetime_timeout, return_content,
use_cookie_authentication, &stats, form_data, NULL, true, 0, method_post);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Internal helper for HTTP requests requiring multiple auth token types. Lua: (internal multi-auth helper) → string */
static int ntop_http_multi_auth_token(lua_State* vm, HttpMethod method) {
char *url, *auth_token = NULL, *form_data;
int connection_timeout = 30, lifetime_timeout = 0;
bool return_content = false;
bool use_cookie_authentication = false;
HTTPTranferStats stats;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((url = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((auth_token = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((form_data = (char*)lua_tostring(vm, 3)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 4) == LUA_TNUMBER) /* Optional */
connection_timeout = lua_tonumber(vm, 4);
if (lua_type(vm, 5) == LUA_TBOOLEAN) /* Optional */
return_content = lua_toboolean(vm, 5) ? true : false;
if (lua_type(vm, 6) == LUA_TBOOLEAN) /* Optional */
use_cookie_authentication = lua_toboolean(vm, 6) ? true : false;
Utils::httpGetPostPutPatch(vm, url, NULL /* username */, NULL /* pwd */,
auth_token, connection_timeout, lifetime_timeout,
return_content, use_cookie_authentication, &stats,
form_data, NULL, true, 0, method);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Performs an HTTP POST request with a Bearer authorization token. Lua: ntop.httpPostAuthToken(url, token, body[,timeout,content_type]) → string */
static int ntop_http_post_auth_token(lua_State* vm) {
return (ntop_http_multi_auth_token(vm, method_post));
}
/* @brief Performs an HTTP PUT request with a Bearer authorization token. Lua: ntop.httpPutAuthToken(url, token, body[,timeout]) → string */
static int ntop_http_put_auth_token(lua_State* vm) {
return (ntop_http_multi_auth_token(vm, method_put));
}
/* @brief Performs an HTTP PATCH request with a Bearer authorization token. Lua: ntop.httpPatchAuthToken(url, token, body[,timeout]) → string */
static int ntop_http_patch_auth_token(lua_State* vm) {
return (ntop_http_multi_auth_token(vm, method_patch));
}
/* ****************************************** */
/* @brief Full-featured HTTP fetch accepting all options in a single parameter table. Lua: ntop.httpFetch(params_table) → table */
static int ntop_http_fetch(lua_State* vm) {
char *url, *f, fname[PATH_MAX];
HTTPTranferStats stats;
int connection_timeout = 30, lifetime_timeout = 0;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((url = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((f = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 3) == LUA_TNUMBER) /* Optional */
connection_timeout = lua_tonumber(vm, 3);
snprintf(fname, sizeof(fname), "%s", f);
ntop->fixPath(fname);
Utils::httpGetPostPutPatch(vm, url, NULL, NULL, NULL /* user_header_token */,
connection_timeout, lifetime_timeout, false, false,
&stats, NULL, fname, true, 0, method_post);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Posts the contents of a text file to a URL via HTTP POST. Lua: ntop.postHTTPTextFile(url, file_path) → boolean */
static int ntop_post_http_text_file(lua_State* vm) {
char *username, *password, *url, *path;
bool delete_file_after_post = false;
int connection_timeout = 30, lifetime_timeout = 0;
HTTPTranferStats stats;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((password = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((url = (char*)lua_tostring(vm, 3)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((path = (char*)lua_tostring(vm, 4)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 5) == LUA_TBOOLEAN) /* Optional */
delete_file_after_post = lua_toboolean(vm, 5) ? true : false;
if (lua_type(vm, 6) == LUA_TNUMBER) {
/* Optional */
connection_timeout = lua_tonumber(vm, 6);
if (connection_timeout < 1) connection_timeout = 1;
}
if (Utils::postHTTPTextFile(vm, username, password, url, path,
connection_timeout, lifetime_timeout, &stats)) {
if (delete_file_after_post) {
if (unlink(path) != 0)
ntop->getTrace()->traceEvent(TRACE_WARNING, "Unable to delete file %s",
path);
else
ntop->getTrace()->traceEvent(TRACE_INFO, "Deleted file %s", path);
}
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#ifdef HAVE_CURL_SMTP
/* @brief Sends an email via SMTP (requires HAVE_CURL_SMTP build option). Lua: ntop.sendMail(params_table) → boolean */
static int ntop_send_mail(lua_State* vm) {
char *from, *to, *cc, *msg, *smtp_server, *username = NULL, *password = NULL;
bool verbose = false, use_proxy = false;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((from = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((to = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((cc = (char*)lua_tostring(vm, 3)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((msg = (char*)lua_tostring(vm, 4)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 5, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((smtp_server = (char*)lua_tostring(vm, 5)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 6) == LUA_TSTRING) /* Optional */
username = (char*)lua_tostring(vm, 6);
if (lua_type(vm, 7) == LUA_TSTRING) /* Optional */
password = (char*)lua_tostring(vm, 7);
if (lua_type(vm, 8) == LUA_TBOOLEAN) /* Optional */
use_proxy = lua_toboolean(vm, 8);
if (lua_type(vm, 9) == LUA_TBOOLEAN) /* Optional */
verbose = lua_toboolean(vm, 9);
Utils::sendMail(vm, from, to, cc, msg, smtp_server, username, password,
use_proxy, verbose);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
/* ****************************************** */
/* @brief Creates a new user account with specified permissions and restrictions. Lua: ntop.addUser(username, full_name, password, role, nets, iface, ...) → boolean */
static int ntop_add_user(lua_State* vm) {
char *username, *full_name, *password, *host_role, *allowed_networks,
*allowed_interface;
char *host_pool_id = NULL, *language = NULL, *allowed_host_pools = NULL;
bool allow_pcap_download = false;
bool allow_historical_flows = false;
bool allow_alerts = false;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((full_name = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((password = (char*)lua_tostring(vm, 3)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((host_role = (char*)lua_tostring(vm, 4)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 5, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((allowed_networks = (char*)lua_tostring(vm, 5)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 6, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((allowed_interface = (char*)lua_tostring(vm, 6)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 7) == LUA_TSTRING)
if ((host_pool_id = (char*)lua_tostring(vm, 7)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 8) == LUA_TSTRING)
if ((language = (char*)lua_tostring(vm, 8)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 9) == LUA_TBOOLEAN)
allow_pcap_download = lua_toboolean(vm, 9);
if (lua_type(vm, 10) == LUA_TBOOLEAN)
allow_historical_flows = lua_toboolean(vm, 10);
if (lua_type(vm, 11) == LUA_TBOOLEAN) allow_alerts = lua_toboolean(vm, 11);
if (lua_type(vm, 12) == LUA_TSTRING)
allowed_host_pools = (char*)lua_tostring(vm, 12);
lua_pushboolean(
vm, ntop->addUser(username, full_name, password, host_role,
allowed_networks, allowed_interface, host_pool_id,
language, allow_pcap_download, allow_historical_flows,
allow_alerts, allowed_host_pools));
return CONST_LUA_OK;
}
/* ******************************************* */
/* @brief Creates a login session for a user and returns the session id. Lua: ntop.createUserSession(username[, duration]) → string */
static int ntop_create_user_session(lua_State* vm) {
char* username;
char session_id[NTOP_SESSION_ID_LENGTH];
u_int session_duration = 0;
session_id[0] = '\0';
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (strlen(username) == 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 2) == LUA_TNUMBER) /* Optional */
session_duration = lua_tonumber(vm, 2);
/* Admin or the same user is allowed to get a session */
if (!ntop->isUserAdministrator(vm)) {
char* curr_user = getLuaVMUserdata(vm, user);
if (strcmp(curr_user, username) != 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
ntop->get_HTTPserver()->authorize_noconn(
username, session_id, sizeof(session_id), session_duration);
lua_pushstring(vm, session_id);
return CONST_LUA_OK;
}
/* ******************************************* */
/* @brief Generates and stores a new API token for a user. Lua: ntop.createUserAPIToken(username) → string */
static int ntop_create_user_api_token(lua_State* vm) {
char* username = NULL;
char api_token[NTOP_SESSION_ID_LENGTH];
api_token[0] = '\0';
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop->get_HTTPserver()->create_api_token(username, api_token,
sizeof(api_token)))
lua_pushstring(vm, api_token);
else
lua_pushnil(vm);
return CONST_LUA_OK;
}
/* ******************************************* */
/* @brief Returns the existing API token for a user, or nil if none exists. Lua: ntop.getUserAPIToken(username) → string */
static int ntop_get_user_api_token(lua_State* vm) {
char* username = NULL;
char api_token[NTOP_SESSION_ID_LENGTH];
api_token[0] = '\0';
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
// get the username param from the Lua vm
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
char* curr_user = getLuaVMUserdata(vm, user);
if (ntop->isUserAdministrator(vm) ||
strncmp(curr_user, username, strlen(username)) == 0) {
if (ntop->getUserAPIToken(username, api_token, NTOP_SESSION_ID_LENGTH)) {
lua_pushstring(vm, api_token);
} else {
lua_pushnil(vm);
}
return CONST_LUA_OK;
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
/* ****************************************** */
/* @brief Permanently deletes a user account and all associated settings. Lua: ntop.deleteUser(username) → boolean */
static int ntop_delete_user(lua_State* vm) {
char* username;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm, ntop->deleteUser(username));
return CONST_LUA_OK;
}
/* ****************************************** */
/* MFA/TOTP Lua bindings */
/* @brief Generates a new base32 TOTP secret for two-factor authentication setup. Lua: ntop.generateTOTPSecret() → string */
static int ntop_generate_totp_secret(lua_State* vm) {
char secret[64];
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!ntop->generateTOTPSecret(secret, sizeof(secret)))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushstring(vm, secret);
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Stores a TOTP secret for a user. Lua: ntop.setUserTOTPSecret(username, secret) → boolean */
static int ntop_set_user_totp_secret(lua_State* vm) {
char *username, *secret;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((secret = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm, ntop->setUserTOTPSecret(username, secret));
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Returns the TOTP secret for a user (admin only). Lua: ntop.getUserTOTPSecret(username) → string */
static int ntop_get_user_totp_secret(lua_State* vm) {
char *username, secret[64];
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
/* Only admins or the user themselves can retrieve the TOTP secret */
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop->getUserTOTPSecret(username, secret, sizeof(secret)))
lua_pushstring(vm, secret);
else
lua_pushnil(vm);
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Returns true if TOTP two-factor authentication is enabled for a user. Lua: ntop.isTOTPEnabled(username) → boolean */
static int ntop_is_totp_enabled(lua_State* vm) {
char* username;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm, ntop->isTOTPEnabled(username));
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Enables or disables TOTP two-factor authentication for a user. Lua: ntop.setUserTOTPEnabled(username, enabled) → boolean */
static int ntop_set_user_totp_enabled(lua_State* vm) {
char* username;
bool enabled;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!allowLocalUserManagement(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
enabled = lua_toboolean(vm, 2);
lua_pushboolean(vm, ntop->setUserTOTPEnabled(username, enabled));
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Validates a 6-digit TOTP code against the user's stored secret. Lua: ntop.validateTOTP(username, code) → boolean */
static int ntop_validate_totp(lua_State* vm) {
char *username, *code;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((code = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm, ntop->validateTOTPCode(username, code));
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Returns the otpauth:// URI for scanning with an authenticator app. Lua: ntop.getTOTPProvisioningUri(username) → string */
static int ntop_get_totp_provisioning_uri(lua_State* vm) {
char *username, uri[256];
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((username = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ntop->getTOTPProvisioningUri(username, uri, sizeof(uri));
if (uri[0] != '\0')
lua_pushstring(vm, uri);
else
lua_pushnil(vm);
return CONST_LUA_OK;
}
/* ****************************************** */
/* Similar to ntop_get_resolved_address but actually perfoms the address
* resolution now */
/* @brief Triggers asynchronous DNS reverse lookup for an IP (prefer resolveAddress() from lua_utils). Lua: ntop.resolveName(ip) → nil */
static int ntop_resolve_address(lua_State* vm) {
char *numIP, symIP[64];
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((numIP = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ntop->resolveHostName(numIP, symIP, sizeof(symIP));
lua_pushstring(vm, symIP);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
void lua_push_str_table_entry(lua_State* L, const char* key,
const char* value) {
if (L) {
lua_pushstring(L, key);
lua_pushstring(L, value);
lua_settable(L, -3);
}
}
/* ****************************************** */
void lua_push_str_len_table_entry(lua_State* L, const char* key,
const char* value, const unsigned int len) {
if (L) {
char* v = (char*)malloc(len + 1);
;
if (v != NULL) {
memcpy(v, value, len);
v[len] = 0;
}
lua_pushstring(L, key);
if (v != NULL) {
lua_pushstring(L, v);
free(v);
} else
lua_pushstring(L, value);
lua_settable(L, -3);
}
}
/* ****************************************** */
void lua_push_nil_table_entry(lua_State* L, const char* key) {
if (L) {
lua_pushstring(L, key);
lua_pushnil(L);
lua_settable(L, -3);
}
}
/* ****************************************** */
void lua_push_bool_table_entry(lua_State* L, const char* key, bool value) {
if (L) {
lua_pushstring(L, key);
lua_pushboolean(L, value ? 1 : 0);
lua_settable(L, -3);
}
}
/* ****************************************** */
void lua_push_uint64_table_entry(lua_State* L, const char* key,
u_int64_t value) {
if (L) {
lua_pushstring(L, key);
/* NOTE since LUA 5.3 integers are 64 bits */
lua_pushinteger(L, (lua_Integer)value);
lua_settable(L, -3);
}
}
/* ****************************************** */
void lua_push_int64_table_entry(lua_State* L, const char* key, int64_t value) {
if (L) {
lua_pushstring(L, key);
/* NOTE since LUA 5.3 integers are 64 bits */
lua_pushinteger(L, (lua_Integer)value);
lua_settable(L, -3);
}
}
/* ****************************************** */
void lua_push_uint32_table_entry(lua_State* L, const char* key,
u_int32_t value) {
if (L) {
lua_pushstring(L, key);
lua_pushinteger(L, (lua_Integer)value);
lua_settable(L, -3);
}
}
/* ****************************************** */
void lua_push_int32_table_entry(lua_State* L, const char* key, int32_t value) {
if (L) {
lua_pushstring(L, key);
#if defined(LUA_MAXINTEGER) && defined(LUA_MININTEGER)
if ((lua_Integer)value > LUA_MAXINTEGER ||
(lua_Integer)value < LUA_MININTEGER)
lua_pushnumber(L, (lua_Number)value);
else
#endif
lua_pushinteger(L, (lua_Integer)value);
lua_settable(L, -3);
}
}
/* ****************************************** */
void lua_push_float_table_entry(lua_State* L, const char* key, float value) {
if (L) {
lua_pushstring(L, key);
lua_pushnumber(L, value);
lua_settable(L, -3);
}
}
/* ****************************************** */
/* @brief Returns true if ntopng is installed from a distribution package. Lua: ntop.isPackage() → boolean */
static int ntop_is_package(lua_State* vm) {
bool is_package = false;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
#ifdef NTOPNG_PRO
#ifndef WIN32
is_package = (getppid() == 1 /* parent is systemd */);
#else
is_package = true;
#endif
#endif
lua_pushboolean(vm, is_package);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if ntopng is forced to run in Community mode. Lua: ntop.isForcedCommunity() → boolean */
static int ntop_is_forced_community(lua_State* vm) {
bool is_forced_community = true;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
#ifdef NTOPNG_PRO
is_forced_community = ntop->getPro()->forced_community_edition();
#endif
lua_pushboolean(vm, is_forced_community);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if running Pro edition or higher. Lua: ntop.isPro() → boolean */
static int ntop_is_pro(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->getPrefs()->is_pro_edition());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if running Enterprise M edition or higher. Lua: ntop.isEnterpriseM() / ntop.isEnterprise() → boolean */
static int ntop_is_enterprise_m(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->getPrefs()->is_enterprise_m_edition());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if running Enterprise L edition or higher. Lua: ntop.isEnterpriseL() → boolean */
static int ntop_is_enterprise_l(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->getPrefs()->is_enterprise_l_edition());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if running Enterprise XL edition or higher. Lua: ntop.isEnterpriseXL() → boolean */
static int ntop_is_enterprise_xl(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->getPrefs()->is_enterprise_xl_edition());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if running Enterprise XXL edition or higher. Lua: ntop.isEnterpriseXXL() → boolean */
static int ntop_is_enterprise_xxl(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->getPrefs()->is_enterprise_xxl_edition());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if running Enterprise XXXL edition or higher. Lua: ntop.isEnterpriseXXXL() → boolean */
static int ntop_is_enterprise_xxxl(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->getPrefs()->is_enterprise_xxxl_edition());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if running nEdge Pro edition. Lua: ntop.isnEdge() → boolean */
static int ntop_is_nedge(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->getPrefs()->is_nedge_pro_edition());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if running nEdge Enterprise edition. Lua: ntop.isnEdgeEnterprise() → boolean */
static int ntop_is_nedge_enterprise(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->getPrefs()->is_nedge_enterprise_edition());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if running on a dedicated ntopng hardware appliance. Lua: ntop.isAppliance() → boolean */
static int ntop_is_appliance(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
#ifndef HAVE_NEDGE
lua_pushboolean(vm, ntop->getPrefs()->is_appliance());
#else
lua_pushboolean(vm, false);
#endif
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if ntopng is configured in IoT Bridge mode. Lua: ntop.isIoTBridge() → boolean */
static int ntop_is_iot_bridge(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
#ifndef HAVE_NEDGE
bool is_supported = false;
#ifdef HAVE_EMBEDDED_SUPPORT
is_supported = true; /* TODO Restrict this check to supported devices */
#endif
lua_pushboolean(vm, ntop->getPrefs()->is_appliance() && is_supported);
#else
lua_pushboolean(vm, false);
#endif
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Starts a PCAP extraction job from recorded traffic (admin only). Lua: ntop.runExtraction(id, ifid, from, to, filter[,max_bytes,timeline]) → nil */
static int ntop_run_extraction(lua_State* vm) {
int id, ifid;
time_t time_from, time_to;
char* filter;
u_int64_t max_bytes;
char* timeline_path = NULL;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 5, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 6) == LUA_TNUMBER)
max_bytes = lua_tonumber(vm, 6);
else
max_bytes = 0; /* optional */
if (lua_tostring(vm, 7)) timeline_path = (char*)lua_tostring(vm, 7);
id = lua_tointeger(vm, 1);
ifid = lua_tointeger(vm, 2);
time_from = lua_tointeger(vm, 3);
time_to = lua_tointeger(vm, 4);
if ((filter = (char*)lua_tostring(vm, 5)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
max_bytes = lua_tonumber(vm, 6);
ntop->getTimelineExtract()->runExtractionJob(id, ntop->getInterfaceById(ifid),
time_from, time_to, filter,
max_bytes, timeline_path);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Stops a running PCAP extraction job by id. Lua: ntop.stopExtraction(job_id) → nil */
static int ntop_stop_extraction(lua_State* vm) {
int id;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
id = lua_tointeger(vm, 1);
ntop->getTimelineExtract()->stopExtractionJob(id);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if any PCAP extraction job is currently running. Lua: ntop.isExtractionRunning() → boolean */
static int ntop_is_extraction_running(lua_State* vm) {
bool rv;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
rv = ntop->getTimelineExtract()->isRunning();
lua_pushboolean(vm, rv);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Reserved; returns extraction job status information. Lua: ntop.getExtractionStatus() → nil */
static int ntop_get_extraction_status(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ntop->getTimelineExtract()->getStatus(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Starts a live PCAP stream extraction for the given time window and BPF filter. Lua: ntop.runLiveExtraction(ifid, from, to, bpf[, timeline]) → boolean */
static int ntop_run_live_extraction(lua_State* vm) {
NtopngLuaContext* c = NULL;
NetworkInterface* iface = NULL;
TimelineExtract timeline;
int ifid = 0;
time_t time_from = 0, time_to = 0;
char* bpf = NULL;
bool allow = false, success = false;
char* timeline_path = NULL;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
c = getLuaVMContext(vm);
if (!c) return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ifid = lua_tointeger(vm, 1);
time_from = lua_tointeger(vm, 2);
time_to = lua_tointeger(vm, 3);
if ((bpf = (char*)lua_tostring(vm, 4)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
/* Optional: by default use <id>/timeline as path */
if (lua_tostring(vm, 5)) timeline_path = (char*)lua_tostring(vm, 5);
iface = ntop->getInterfaceById(ifid);
if (!iface) return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (!ntop->isPcapDownloadAllowed(vm, iface->get_name()))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
live_extraction_num_lock.lock(__FILE__, __LINE__);
if (live_extraction_num < CONST_MAX_NUM_LIVE_EXTRACTIONS) {
allow = true;
live_extraction_num++;
}
live_extraction_num_lock.unlock(__FILE__, __LINE__);
if (allow) {
bpf = ntop->preparePcapDownloadFilter(vm, bpf);
if (bpf) {
success = timeline.extractLive(c->conn, iface, time_from, time_to, bpf,
timeline_path);
live_extraction_num_lock.lock(__FILE__, __LINE__);
live_extraction_num--;
live_extraction_num_lock.unlock(__FILE__, __LINE__);
free(bpf);
}
}
lua_pushboolean(vm, success);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the specified bit is set in the bitmap integer. Lua: ntop.bitmapIsSet(bitmap, bit_value) → boolean */
static int ntop_bitmap_is_set(lua_State* vm) {
u_int64_t bitmap;
u_int64_t val;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
bitmap = lua_tointeger(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
val = lua_tointeger(vm, 2);
lua_pushboolean(vm, Utils::bitmapIsSet(bitmap, val));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Sets the specified bit in the bitmap and returns the new bitmap value. Lua: ntop.bitmapSet(bitmap, bit_value) → integer */
static int ntop_bitmap_set(lua_State* vm) {
u_int64_t bitmap;
u_int64_t val;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
bitmap = lua_tointeger(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
val = lua_tointeger(vm, 2);
lua_pushinteger(vm, Utils::bitmapSet(bitmap, val));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Clears the specified bit in the bitmap and returns the new bitmap value. Lua: ntop.bitmapClear(bitmap, bit_value) → integer */
static int ntop_bitmap_clear(lua_State* vm) {
u_int64_t bitmap;
u_int64_t val;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
bitmap = lua_tointeger(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
val = lua_tointeger(vm, 2);
lua_pushinteger(vm, Utils::bitmapClear(bitmap, val));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Converts a numeric alert score to an alert severity enum value. Lua: ntop.mapScoreToSeverity(score) → integer */
static int ntop_map_score_to_severity(lua_State* vm) {
u_int64_t score;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
score = lua_tointeger(vm, 1);
lua_pushinteger(vm, (u_int32_t)Utils::mapScoreToSeverity(score));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Converts an alert severity enum value to a numeric score. Lua: ntop.mapSeverityToScore(severity) → integer */
static int ntop_map_severity_to_score(lua_State* vm) {
AlertLevel alert_level;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
alert_level = (AlertLevel)lua_tointeger(vm, 1);
lua_pushinteger(vm, Utils::mapSeverityToScore(alert_level));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Resets all per-interface traffic statistics counters. Lua: ntop.resetStats() → nil */
static int ntop_reset_stats(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->resetStats();
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the absolute path of the currently executing scripts directory. Lua: ntop.getCurrentScriptsDir() → string */
static int ntop_get_current_scripts_dir(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushstring(vm, ntop->get_scripts_dir());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns a table of all key directory paths: installdir, scriptdir, httpdocsdir, workingdir, etc.. Lua: ntop.getDirs() → table */
static int ntop_get_dirs(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_newtable(vm);
lua_push_str_table_entry(vm, "bindir", ntop->get_bin_dir());
lua_push_str_table_entry(vm, "installdir", ntop->get_install_dir());
lua_push_str_table_entry(vm, "workingdir", ntop->get_working_dir());
lua_push_str_table_entry(vm, "scriptdir",
ntop->getPrefs()->get_scripts_dir());
lua_push_str_table_entry(vm, "httpdocsdir", ntop->getPrefs()->get_docs_dir());
lua_push_str_table_entry(vm, "callbacksdir",
ntop->getPrefs()->get_callbacks_dir());
lua_push_str_table_entry(vm, "pcapdir", ntop->getPrefs()->get_pcap_dir());
lua_push_str_table_entry(vm, "dbarchivedir",
ntop->getPrefs()->get_clickhouse_archive_dir());
lua_push_str_table_entry(vm, "etcdir", CONST_ETC_DIR);
lua_push_str_table_entry(vm, "sharedir", CONST_SHARE_DIR);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Enables the asset discovery logging feature. Lua: ntop.enableAssetsLog() → nil */
static int ntop_enable_assets_log(lua_State* vm) {
bool enable_assets_log = false;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK) {
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
}
enable_assets_log = (bool)lua_tonumber(vm, 1);
ntop->getPrefs()->do_enable_assets_log(enable_assets_log);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the assets discovery and logging feature is enabled. Lua: ntop.assetsEnabled() → boolean */
static int ntop_assets_enabled(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
#ifdef NTOPNG_PRO
lua_pushboolean(vm, ntop->getPrefs()->isAssetInventoryEnabled());
#else
lua_pushboolean(vm, false);
#endif
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Recursively finds all files matching a pattern under base_path. Lua: ntop.getAllPaths(base_path, filename_pattern) → table */
static int ntop_get_all_paths(lua_State* vm) {
const char *path, *filename;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((path = (const char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((filename = (const char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_newtable(vm);
Utils::lua_getpaths_recursively(vm, path, filename);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the ntopng uptime in seconds since last restart. Lua: ntop.getUptime() → integer */
static int ntop_get_uptime(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushinteger(vm, ntop->getGlobals()->getUptime());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns system statistics including CPU load, memory usage, and alert queue info. Lua: ntop.systemHostStat() → table */
static int ntop_system_host_stat(lua_State* vm) {
float cpu_load;
u_int64_t dropped_alerts = 0, written_alerts = 0, alerts_queries = 0;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_newtable(vm);
if (ntop->getCPULoad(&cpu_load))
lua_push_float_table_entry(vm, "cpu_load", cpu_load);
Utils::luaMeminfo(vm);
for (int i = -1; i < ntop->get_num_interfaces(); i++) {
NetworkInterface* iface =
(i == -1) ? ntop->getSystemInterface() : ntop->getInterface(i);
if (iface) {
dropped_alerts += iface->getNumDroppedAlerts();
written_alerts += iface->getNumWrittenAlerts();
alerts_queries += iface->getNumAlertsQueries();
}
}
lua_push_uint64_table_entry(vm, "dropped_alerts", dropped_alerts);
lua_push_uint64_table_entry(vm, "written_alerts", written_alerts);
lua_push_uint64_table_entry(vm, "alerts_queries", alerts_queries);
/* ntopng alert queues stats */
lua_newtable(vm);
ntop->lua_alert_queues_stats(vm);
lua_pushstring(vm, "alerts_stats");
lua_insert(vm, -2);
lua_settable(vm, -3);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns information about all running ntopng threads and their status. Lua: ntop.threadsInfo() → table */
static int ntop_threads_info(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_newtable(vm);
ntop->lua_threadsInfo(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns system-level alert queue statistics (drops and writes). Lua: ntop.getSystemAlertsStats() → table */
static int ntop_get_system_alerts_stats(lua_State* vm) {
NetworkInterface* iface;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
iface = ntop->getSystemInterface();
if (!iface) return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_newtable(vm);
iface->luaNumEngagedAlerts(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Refreshes and returns the current CPU load percentage. Lua: ntop.refreshCPULoad() → number */
static int ntop_refresh_cpu_load(lua_State* vm) {
float cpu_load;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->refreshCPULoad();
if (ntop->getCPULoad(&cpu_load))
lua_pushnumber(vm, cpu_load);
else
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Triggers a license validation check and returns 1. Lua: ntop.checkLicense() → integer */
static int ntop_check_license(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
#ifdef NTOPNG_PRO
ntop->getPro()->check_license();
#endif
lua_pushinteger(vm, 1);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns comprehensive product info: version, OS, license, uptime, listening ports. Lua: ntop.getInfo([verbose]) → table */
static int ntop_get_info(lua_State* vm) {
char rsp[256];
#ifdef NTOPNG_PRO
char buf[128];
#endif
#ifndef HAVE_NEDGE
int major, minor, patch;
#endif
bool verbose = true;
char* zoneinfo = ntop->getZoneInfo();
FILE* fd = fopen("/proc/device-tree/model", "r");
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (lua_type(vm, 1) == LUA_TBOOLEAN)
verbose = lua_toboolean(vm, 1) ? true : false;
lua_newtable(vm);
lua_push_str_table_entry(vm, "product",
#ifdef NTOPNG_PRO
ntop->getPro()->get_product_name()
#else
(char*)"ntopng"
#endif
);
lua_push_bool_table_entry(vm, "oem",
#ifdef NTOPNG_PRO
ntop->getPro()->is_oem()
#else
false
#endif
);
lua_push_str_table_entry(
vm, "copyright",
#ifdef NTOPNG_PRO
ntop->getPro()->is_oem() ? (char*)"" :
#endif
(char*)"&copy; 1998-26 - ntop");
lua_push_str_table_entry(vm, "authors", (char*)"The ntop team");
lua_push_str_table_entry(vm, "license", (char*)"GNU GPLv3");
lua_push_str_table_entry(vm, "platform", (char*)PACKAGE_MACHINE);
lua_push_str_table_entry(vm, "version", (char*)PACKAGE_VERSION);
lua_push_str_table_entry(vm, "revision", (char*)PACKAGE_REVISION);
lua_push_str_table_entry(vm, "git", (char*)NTOPNG_GIT_RELEASE);
#ifndef WIN32
lua_push_uint64_table_entry(vm, "pid", getpid());
#endif
#ifdef HAVE_JEMALLOC
lua_push_bool_table_entry(vm, "jemalloc", true);
#endif
snprintf(rsp, sizeof(rsp), "%s [%s]", PACKAGE_OS, PACKAGE_MACHINE);
lua_push_str_table_entry(vm, "platform", rsp);
lua_push_str_table_entry(vm, "OS",
#ifdef WIN32
(char*)"Windows"
#else
(char*)PACKAGE_OS
#endif
);
if (fd != NULL) {
char* rc = fgets(rsp, sizeof(rsp), fd);
if (rc != NULL) lua_push_str_table_entry(vm, "hw_model", rsp);
fclose(fd);
}
lua_push_uint64_table_entry(vm, "bits", (sizeof(void*) == 4) ? 32 : 64);
lua_push_uint64_table_entry(vm, "uptime", ntop->getGlobals()->getUptime());
lua_push_str_table_entry(vm, "command_line",
ntop->getPrefs()->get_command_line());
lua_push_uint32_table_entry(vm, "http_port",
ntop->getPrefs()->get_http_port());
lua_push_uint32_table_entry(vm, "https_port",
ntop->getPrefs()->get_https_port());
lua_push_str_table_entry(vm, "tzname", ntop->getTZname()); /* Timezone name */
if (zoneinfo) lua_push_str_table_entry(vm, "zoneinfo", zoneinfo);
#ifdef __linux__
lua_push_int32_table_entry(vm, "timezone",
timezone); /* Seconds west of UTC */
#endif
if (verbose) {
lua_push_str_table_entry(vm, "version.rrd", rrd_strversion());
lua_push_str_table_entry(vm, "version.redis",
ntop->getRedis()->getVersion());
lua_push_str_table_entry(vm, "version.httpd", (char*)mg_version());
lua_push_str_table_entry(vm, "version.git", (char*)NTOPNG_GIT_RELEASE);
lua_push_str_table_entry(vm, "version.curl", (char*)LIBCURL_VERSION);
lua_push_str_table_entry(vm, "version.lua", (char*)LUA_RELEASE);
#ifdef HAVE_MAXMINDDB
lua_push_str_table_entry(vm, "version.geoip", (char*)MMDB_lib_version());
#endif
lua_push_str_table_entry(vm, "version.ndpi", ndpi_revision());
lua_push_bool_table_entry(vm, "pro.release",
ntop->getPrefs()->is_pro_edition());
lua_push_bool_table_entry(vm, "version.enterprise_edition",
ntop->getPrefs()->is_enterprise_m_edition());
lua_push_bool_table_entry(vm, "version.enterprise_m_edition",
ntop->getPrefs()->is_enterprise_m_edition());
lua_push_bool_table_entry(vm, "version.enterprise_l_edition",
ntop->getPrefs()->is_enterprise_l_edition());
lua_push_bool_table_entry(vm, "version.enterprise_xl_edition",
ntop->getPrefs()->is_enterprise_xl_edition());
lua_push_bool_table_entry(vm, "version.enterprise_xxl_edition",
ntop->getPrefs()->is_enterprise_xxl_edition());
lua_push_bool_table_entry(vm, "version.enterprise_xxxl_edition",
ntop->getPrefs()->is_enterprise_xxxl_edition());
lua_push_bool_table_entry(vm, "version.nedge_edition",
ntop->getPrefs()->is_nedge_pro_edition());
lua_push_bool_table_entry(vm, "version.nedge_enterprise_edition",
ntop->getPrefs()->is_nedge_enterprise_edition());
lua_push_bool_table_entry(vm, "version.embedded_edition",
ntop->getPrefs()->is_embedded_edition());
lua_push_uint64_table_entry(vm, "pro.demo_ends_at",
ntop->getPrefs()->pro_edition_demo_ends_at());
#ifdef NTOPNG_PRO
#ifndef FORCE_VALID_LICENSE
time_t until_then;
int days_left;
if (ntop->getPro()->get_maintenance_expiration_time(&until_then,
&days_left)) {
lua_push_uint64_table_entry(vm, "pro.license_ends_at",
(u_int64_t)until_then);
lua_push_int64_table_entry(vm, "pro.license_days_left", days_left);
}
#endif
lua_push_str_table_entry(vm, "pro.license", ntop->getPro()->get_license());
lua_push_str_table_entry(vm, "pro.license_encoded",
ntop->getPro()->get_encoded_license());
lua_push_bool_table_entry(vm, "pro.has_valid_license",
ntop->getPro()->has_valid_license());
lua_push_str_table_entry(
vm, "pro.license_type",
ntop->getPro()->get_license_type(buf, sizeof(buf)));
lua_push_bool_table_entry(vm, "pro.forced_community",
ntop->getPro()->is_forced_community());
lua_push_bool_table_entry(vm, "pro.out_of_maintenance",
ntop->getPro()->is_out_of_maintenance());
lua_push_bool_table_entry(vm, "pro.use_redis_license",
ntop->getPro()->use_redis_license());
lua_push_str_table_entry(vm, "pro.systemid",
ntop->getPro()->get_system_id());
#endif
lua_push_uint64_table_entry(vm, "constants.max_num_host_pools",
MAX_NUM_HOST_POOLS);
lua_push_uint64_table_entry(vm, "constants.max_num_pool_members",
MAX_NUM_POOL_MEMBERS);
lua_push_uint64_table_entry(vm, "constants.max_num_profiles",
MAX_NUM_PROFILES);
#ifdef HAVE_ZMQ
#ifndef HAVE_NEDGE
zmq_version(&major, &minor, &patch);
snprintf(rsp, sizeof(rsp), "%d.%d.%d", major, minor, patch);
lua_push_str_table_entry(vm, "version.zmq", rsp);
#endif
#endif
}
#ifdef NTOPNG_PRO
ntop->getPro()->lua(vm);
#endif
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the HTTP cookie security attributes string (e.g. SameSite=Strict; Secure). Lua: ntop.getCookieAttributes() → string */
static int ntop_get_cookie_attributes(lua_State* vm) {
struct mg_request_info* request_info;
struct mg_connection* conn;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!(conn = getLuaVMUserdata(vm, conn)))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (!(request_info = mg_get_request_info(conn)))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushstring(vm, (char*)get_secure_cookie_attributes(request_info));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the current user is allowed to access the given interface. Lua: ntop.isAllowedInterface(ifname) → boolean */
static int ntop_is_allowed_interface(lua_State* vm) {
int id;
NetworkInterface* iface;
bool rv = false;
char* allowed_ifname = getLuaVMUserdata(vm, allowed_ifname);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
id = lua_tointeger(vm, 1);
if ((allowed_ifname == NULL) || (allowed_ifname[0] == '\0'))
rv = true;
else if (((iface = ntop->getNetworkInterface(vm, id)) != NULL) &&
(iface->get_id() == id) &&
matches_allowed_ifname(allowed_ifname, iface->get_name()))
rv = true;
lua_pushboolean(vm, rv);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the current user is allowed to see the given network. Lua: ntop.isAllowedNetwork(network) → boolean */
static int ntop_is_allowed_network(lua_State* vm) {
bool rv = false;
u_int16_t vlan_id = 0;
char *host, buf[64];
AddressTree* allowed_nets = get_allowed_nets(vm);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
get_host_vlan_info((char*)lua_tostring(vm, 1), &host, &vlan_id, buf,
sizeof(buf));
if (!allowed_nets /* e.g., when the user is 'nologin' there's no allowed
network to enforce */
|| allowed_nets->match(host))
rv = true;
lua_pushboolean(vm, rv);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the IP belongs to one of this machine's network interfaces. Lua: ntop.isLocalInterfaceAddress(ip) → boolean */
static int ntop_is_local_interface_address(lua_State* vm) {
char* host;
IpAddress ipa;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
host = (char*)lua_tostring(vm, 1);
ipa.set(host);
/* Check if this IP address is local to this machine */
lua_pushboolean(vm, ipa.isLocalInterfaceAddress());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the IP is in one of the configured local networks. Lua: ntop.isLocalAddress(ip) → boolean */
static int ntop_is_local_address(lua_State* vm) {
char *host, *slash;
IpAddress ipa;
char shadow[64];
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
host = (char*)lua_tostring(vm, 1);
snprintf(shadow, sizeof(shadow), "%s", host);
if ((slash = strchr(shadow, '/')) != NULL) {
/* network/CIDR */
char *ip, *mask;
u_int8_t nmask_bits;
int32_t local_network_id;
shadow[0] = '\0';
ip = shadow, mask = &shadow[1];
nmask_bits = (u_int8_t)atoi(mask);
if (strchr(ip, ':') != NULL) {
/* IPv6 */
struct ndpi_in6_addr ipv6;
if (inet_pton(AF_INET6, ip, &ipv6) <= 0)
lua_pushboolean(vm, false);
else
lua_pushboolean(
vm, ntop->isLocalAddress(AF_INET6, (void*)&ipv6, &local_network_id,
&nmask_bits));
} else {
/* IPv4 */
u_int32_t addr = inet_addr(ip);
lua_pushboolean(vm, ntop->isLocalAddress(AF_INET, &addr,
&local_network_id, &nmask_bits));
}
} else {
ipa.set(shadow);
/* Check if this IP address is local (-m) */
lua_pushboolean(vm, ipa.isLocalHost());
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the local network info table for the network containing the given IP. Lua: ntop.getAddressNetwork(ip) → table */
static int ntop_get_address_network(lua_State* vm) {
char* ip;
IpAddress ipa;
int32_t local_network_id = -1;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ip = (char*)lua_tostring(vm, 1);
ipa.set(ip);
ipa.isLocalHost(&local_network_id);
lua_pushinteger(vm, (u_int32_t)local_network_id);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Retrieves a cached DNS reverse lookup result (prefer getResolvedAddress() from lua_utils). Lua: ntop.getResolvedName(ip) → string */
static int ntop_get_resolved_address(lua_State* vm) {
char *key, *tmp, rsp[256], value[280];
Redis* redis = ntop->getRedis();
u_int16_t vlan_id = 0;
char buf[64];
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
get_host_vlan_info((char*)lua_tostring(vm, 1), &key, &vlan_id, buf,
sizeof(buf));
if (key == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((redis->getAddress(key, rsp, sizeof(rsp), true) == 0) && (rsp[0] != '\0'))
tmp = rsp;
else
tmp = key;
if (vlan_id != 0)
snprintf(value, sizeof(value), "%s@%u", tmp, vlan_id);
else
snprintf(value, sizeof(value), "%s", tmp);
lua_pushfstring(vm, "%s", value);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Synchronously resolves a hostname to its IP address. Lua: ntop.resolveHost(hostname) → string */
static int ntop_resolve_host(lua_State* vm) {
char buf[64];
char* host;
bool ipv4 = false;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((host = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ipv4 = lua_toboolean(vm, 2);
if (ntop->resolveHost(host, buf, sizeof(buf), ipv4))
lua_pushstring(vm, buf);
else
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Enables or disables full (fat) MIB polling mode for SNMP. Lua: ntop.snmpSetFatMibPollingMode(enabled) → nil */
static int ntop_snmp_set_fat_mib_polling_mode(lua_State* vm) {
NtopngLuaContext* ctx = getLuaVMContext(vm);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ctx && ctx->threaded_activity_stats)
ctx->threaded_activity_stats->setFatMIBMode((bool)lua_toboolean(vm, 1));
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if the corresponding SNMP capability is compiled in. Lua: ntop.snmpv3available()/snmpsetavailable()/snmpgetbulkavailable() → boolean */
static int ntop_is_libsnmp_available(lua_State* vm) {
lua_pushboolean(vm,
#ifdef HAVE_LIBSNMP
true
#else
false
#endif
);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the maximum number of concurrent SNMP engines supported. Lua: ntop.snmpMaxNumEngines() → integer */
static int ntop_snmp_max_num_engines(lua_State* vm) {
u_int16_t num = 0;
#ifdef NTOPNG_PRO
if (ntop->getPro()->has_valid_enterprise_xxxl_license())
num = NTOPNG_MAX_NUM_SNMP_DEVICES_ENT_XXXL;
else if (ntop->getPro()->has_valid_enterprise_xxl_license())
num = NTOPNG_MAX_NUM_SNMP_DEVICES_ENT_XXL;
else if (ntop->getPro()->has_valid_enterprise_xl_license())
num = NTOPNG_MAX_NUM_SNMP_DEVICES_ENT_XL;
else if (ntop->getPro()->has_valid_enterprise_l_license())
num = NTOPNG_MAX_NUM_SNMP_DEVICES_ENT_L;
else if (ntop->getPro()->has_valid_enterprise_m_license())
num = NTOPNG_MAX_NUM_SNMP_DEVICES_ENT_M;
#endif
#ifdef HAVE_NEDGE
if (ntop->getPro()->has_valid_nedge_enterprise_license())
num = NTOPNG_MAX_NUM_SNMP_DEVICES_NEDGE;
#endif
lua_pushinteger(vm, num);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Sets the maximum number of variable repetitions for SNMP GETBULK requests. Lua: ntop.snmpSetBulkMaxNumRepetitions(n) → nil */
static int ntop_snmp_set_bulk_max_repetitions(lua_State* vm) {
NtopngLuaContext* c = getLuaVMContext(vm);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
c->getbulkMaxNumRepetitions = (u_int8_t)lua_tointeger(vm, 1);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* Synchronous calls */
/* @brief Performs a blocking SNMP GET and returns the OID response table. Lua: ntop.snmpget(host, community, oid, version) → table */
static int ntop_snmpget(lua_State* vm) {
SNMP s;
return (s.get(vm, false));
}
/* ****************************************** */
/* @brief Performs a blocking SNMP GETNEXT and returns the next OID response. Lua: ntop.snmpgetnext(host, community, oid, version) → table */
static int ntop_snmpgetnext(lua_State* vm) {
SNMP s;
return (s.getnext(vm, false));
}
/* ****************************************** */
/* @brief Performs a blocking SNMP GETBULK and returns all OID responses. Lua: ntop.snmpgetnextbulk(host, community, oid, version) → table */
static int ntop_snmpgetnextbulk(lua_State* vm) {
SNMP s;
return (s.getnextbulk(vm, false));
}
/* ****************************************** */
/* @brief Performs a blocking SNMP SET operation on a remote OID. Lua: ntop.snmpset(host, community, oid, type, value, version) → boolean */
static int ntop_snmpset(lua_State* vm) {
SNMP s;
return (s.set(vm, false));
}
/* ****************************************** */
/* Asynchronous calls */
/* @brief Allocates an async SNMP engine and returns its integer handle. Lua: ntop.snmpallocasnyncengine() → integer */
static int ntop_allocasnyncengine(lua_State* vm) {
SNMP** snmpAsyncEngine = getLuaVMUserdata(vm, snmpAsyncEngine);
u_int16_t slot_id;
bool found_empty_slot = false;
for (slot_id = 0; slot_id < MAX_NUM_ASYNC_SNMP_ENGINES; slot_id++) {
if (snmpAsyncEngine[slot_id] == NULL) {
found_empty_slot = true;
break;
}
} /* for */
if (found_empty_slot) {
if ((snmpAsyncEngine[slot_id] = new SNMP()) != NULL) {
lua_pushinteger(vm, slot_id);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
}
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Frees an async SNMP engine previously allocated with snmpallocasnyncengine. Lua: ntop.snmpfreeasnycengine(handle) → nil */
static int ntop_freeasnyncengine(lua_State* vm) {
SNMP** snmpAsyncEngine = getLuaVMUserdata(vm, snmpAsyncEngine);
u_int16_t slot_id;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
slot_id = (u_int16_t)lua_tonumber(vm, 1);
if ((slot_id >= MAX_NUM_ASYNC_SNMP_ENGINES) ||
(snmpAsyncEngine[slot_id] == NULL))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
delete snmpAsyncEngine[slot_id];
snmpAsyncEngine[slot_id] = NULL;
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Queues an asynchronous SNMP GET request on the given engine handle. Lua: ntop.snmpgetasync(handle, host, community, oid, version) → nil */
static int ntop_snmpgetasync(lua_State* vm) {
SNMP** snmpAsyncEngine = getLuaVMUserdata(vm, snmpAsyncEngine);
u_int16_t slot_id;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
slot_id = (u_int16_t)lua_tonumber(vm, 1);
if ((slot_id >= MAX_NUM_ASYNC_SNMP_ENGINES) ||
(snmpAsyncEngine[slot_id] == NULL))
return (ntop_lua_return_value(vm, __FUNCTION__,
CONST_LUA_ERROR)); /* Invalid slot selected */
return (snmpAsyncEngine[slot_id]->get(vm, true /* Skip first param */));
}
/* ****************************************** */
/* @brief Queues an asynchronous SNMP GETNEXT request on the given engine handle. Lua: ntop.snmpgetnextasync(handle, host, community, oid, version) → nil */
static int ntop_snmpgetnextasync(lua_State* vm) {
SNMP** snmpAsyncEngine = getLuaVMUserdata(vm, snmpAsyncEngine);
u_int16_t slot_id;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
slot_id = (u_int16_t)lua_tonumber(vm, 1);
if ((slot_id >= MAX_NUM_ASYNC_SNMP_ENGINES) ||
(snmpAsyncEngine[slot_id] == NULL))
return (ntop_lua_return_value(vm, __FUNCTION__,
CONST_LUA_ERROR)); /* Invalid slot selected */
return (snmpAsyncEngine[slot_id]->getnext(vm, true /* Skip first param */));
}
/* ****************************************** */
/* @brief Queues an asynchronous SNMP GETBULK request on the given engine handle. Lua: ntop.snmpgetnextbulkasync(handle, ...) → nil */
static int ntop_snmpgetnextbulkasync(lua_State* vm) {
SNMP** snmpAsyncEngine = getLuaVMUserdata(vm, snmpAsyncEngine);
u_int16_t slot_id;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
slot_id = (u_int16_t)lua_tonumber(vm, 1);
if ((slot_id >= MAX_NUM_ASYNC_SNMP_ENGINES) ||
(snmpAsyncEngine[slot_id] == NULL))
return (ntop_lua_return_value(vm, __FUNCTION__,
CONST_LUA_ERROR)); /* Invalid slot selected */
return (
snmpAsyncEngine[slot_id]->getnextbulk(vm, true /* Skip first param */));
}
/* ****************************************** */
/* @brief Reads and returns all pending async SNMP responses from an engine handle. Lua: ntop.snmpreadasyncrsp(handle) → table */
static int ntop_snmpreadasyncrsp(lua_State* vm) {
SNMP** snmpAsyncEngine = getLuaVMUserdata(vm, snmpAsyncEngine);
u_int16_t slot_id;
u_int timeout = 0; /* Don't wait */
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
slot_id = (u_int16_t)lua_tonumber(vm, 1);
if ((slot_id >= MAX_NUM_ASYNC_SNMP_ENGINES) ||
(snmpAsyncEngine[slot_id] == NULL))
return (ntop_lua_return_value(vm, __FUNCTION__,
CONST_LUA_ERROR)); /* Invalid slot selected */
if (lua_type(vm, 2) == LUA_TNUMBER) timeout = (u_int8_t)lua_tonumber(vm, 2);
snmpAsyncEngine[slot_id]->snmp_fetch_responses(vm, timeout);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Internal helper that handles the SNMPv3-specific portion of batch GET operations. Lua: (internal SNMPv3 helper) → nil */
static int ntop_snmpv3_batch_get(lua_State* vm) {
#ifdef HAVE_LIBSNMP
NetworkInterface* curr_iface = getCurrentInterface(vm);
char* oid[SNMP_MAX_NUM_OIDS] = {NULL};
char value_types[SNMP_MAX_NUM_OIDS];
SNMP* snmp;
bool ret;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!curr_iface)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 5, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 6, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 7, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 8, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 9, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
oid[0] = (char*)lua_tostring(vm, 9);
snmp = getLuaVMUserdata(vm, snmpBatch);
if (snmp == NULL) {
snmp = new SNMP();
if (!snmp)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
getLuaVMUservalue(vm, snmpBatch) = snmp;
}
ret = snmp->send_snmpv3_request(
(char*)lua_tostring(vm, 1), /* agent_host */
(char*)lua_tostring(vm, 2), /* level */
(char*)lua_tostring(vm, 3), /* username */
(char*)lua_tostring(vm, 4), /* auth_protocol */
(char*)lua_tostring(vm, 5), /* auth_passphrase */
(char*)lua_tostring(vm, 6), /* privacy_protocol */
(char*)lua_tostring(vm, 7), /* privacy_passphrase */
(char*)lua_tostring(vm, 8), /* context_name */
snmp_get_pdu, oid, /* oid */
value_types, NULL, true /* batch */);
if (ret) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
#else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
#endif
}
/* ****************************************** */
/* @brief Submits a batch of SNMP GET requests (v1/v2c/v3) for async collection. Lua: ntop.snmpGetBatch(params_table) → nil */
static int ntop_snmp_batch_get(lua_State* vm) {
NetworkInterface* curr_iface = getCurrentInterface(vm);
char* oid[SNMP_MAX_NUM_OIDS] = {NULL};
SNMP* snmp;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!curr_iface)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (lua_type(vm, 4) != LUA_TNUMBER) return (ntop_snmpv3_batch_get(vm));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
oid[0] = (char*)lua_tostring(vm, 3);
snmp = getLuaVMUserdata(vm, snmpBatch);
if (snmp == NULL) {
snmp = new SNMP();
if (!snmp)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
getLuaVMUservalue(vm, snmpBatch) = snmp;
}
snmp->send_snmpv1v2c_request((char*)lua_tostring(vm, 1), /* agent_host */
(char*)lua_tostring(vm, 2), /* community */
snmp_get_pdu,
(u_int)lua_tonumber(vm, 4), /* version */
oid, true /* batch */);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Collects and returns all pending batch SNMP GET responses. Lua: ntop.snmpReadResponses() → table */
static int ntop_snmp_read_responses(lua_State* vm) {
NetworkInterface* curr_iface = getCurrentInterface(vm);
SNMP* snmp = getLuaVMUserdata(vm, snmpBatch);
int timeout = 0;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if ((!curr_iface) || (!snmp))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
/* Optional timeout */
if (lua_type(vm, 1) == LUA_TNUMBER) timeout = lua_tonumber(vm, 1);
snmp->snmp_fetch_responses(vm, timeout);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#if defined(NTOPNG_PRO)
/* @brief Enables the SNMP interface roles set by ntop.snmpSetInterfaceRole,. Lua: ntop.activateSnmpInterfaceRoles() → nil */
static int ntop_activate_snmp_interface_roles(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->activateSnmpInterfaceRoles();
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Sets the LAN/WAN role for an SNMP-managed interface (Pro only). Lua: ntop.snmpSetInterfaceRole(host, ifidx, role) → nil */
static int ntop_snmp_set_interface_role(lua_State* vm) {
u_int32_t exporter_ip_v4;
u_int32_t interface_id;
SNMPInterfaceRole interface_role;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if ((ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK) ||
(ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK) ||
(ntop_lua_check(vm, __FUNCTION__, 3, LUA_TNUMBER) != CONST_LUA_OK))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
exporter_ip_v4 = ntohl((u_int32_t)inet_addr((char*)lua_tostring(vm, 1)));
interface_id = (u_int32_t)lua_tonumber(vm, 2);
interface_role = (SNMPInterfaceRole)lua_tonumber(vm, 3);
if (interface_role < role_max_value) {
/* Set data */
ntop->snmpSetInterfaceRole(exporter_ip_v4, interface_id, interface_role);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
}
#endif
/* ****************************************** */
/* @brief Enables or disables SNMP trap collection. Lua: ntop.snmpToggleTrapCollection(enabled) → nil */
static int ntop_snmp_toggle_trap_collection(lua_State* vm) {
#ifdef HAVE_SNMP_TRAP
bool enable = false;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
enable = (bool)lua_toboolean(vm, 1);
ntop->toggleSNMPTrapCollector(enable);
#endif
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#ifndef WIN32
/* @brief Writes a message to the system syslog at the given severity level (Unix only). Lua: ntop.syslog(level, msg) → nil */
static int ntop_syslog(lua_State* vm) {
char* msg;
int syslog_severity = LOG_INFO;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
msg = (char*)lua_tostring(vm, 1);
if (lua_type(vm, 2) == LUA_TNUMBER)
syslog_severity = (int)lua_tonumber(vm, 2);
syslog(syslog_severity, "%s", msg);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
/* ****************************************** */
/**
* @brief Get the random value associated to the user session to prevent CSRF
* attacks
* @details See https://owasp.org/www-community/attacks/csrf . ntopng uses
* per-session tokens as explained in
* https://www.sjoerdlangkemper.nl/2019/12/18/different-csrf-token-for-each-form
*/
/* @brief Returns the current CSRF token for use in forms and AJAX requests. Lua: ntop.getRandomCSRFValue() → string */
static int ntop_get_csrf_value(lua_State* vm) {
const char* csrf = getLuaVMUservalue(vm, csrf);
if (!csrf) return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushstring(vm, csrf);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the MD5 hex digest of the given string. Lua: ntop.md5(data) → string */
static int ntop_md5(lua_State* vm) {
char result[33];
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
mg_md5(result, lua_tostring(vm, 1), NULL);
lua_pushstring(vm, result);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if RADIUS authentication support is compiled in. Lua: ntop.hasRadiusSupport() → boolean */
static int ntop_has_radius_support(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
#ifdef HAVE_RADIUS
lua_pushboolean(vm, true);
#else
lua_pushboolean(vm, false);
#endif
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Logs a RADIUS authentication event with user and result details. Lua: ntop.logRadius(info_table) → nil */
static int ntop_log_radius(lua_State* vm) {
bool logged = false;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
#ifdef HAVE_RADIUS
Radius* radius = ntop->getRadius();
char *event_type, *message;
if (radius) {
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
event_type = (char*)lua_tostring(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
message = (char*)lua_tostring(vm, 2);
radius->logRadius(event_type, "%s", message);
logged = true;
}
#endif
lua_pushboolean(vm, logged);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if LDAP authentication support is compiled in. Lua: ntop.hasLdapSupport() → boolean */
static int ntop_has_ldap_support(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
#if defined(NTOPNG_PRO) && defined(HAVE_LDAP) && !defined(HAVE_NEDGE)
lua_pushboolean(vm, true);
#else
lua_pushboolean(vm, false);
#endif
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#ifdef UNUSED_CODE
struct ntopng_sqlite_state {
lua_State* vm;
u_int num_rows;
};
static int sqlite_callback(void* data, int argc, char** argv,
char** azColName) {
struct ntopng_sqlite_state* s = (struct ntopng_sqlite_state*)data;
lua_newtable(s->vm);
for (int i = 0; i < argc; i++)
lua_push_str_table_entry(s->vm, (const char*)azColName[i],
(char*)(argv[i] ? argv[i] : "NULL"));
lua_pushinteger(s->vm, ++s->num_rows);
lua_insert(s->vm, -2);
lua_settable(s->vm, -3);
return (0);
}
#endif
/* ****************************************** */
/**
* @brief Insert a new minute sampling in the historical database
* @details Given a certain sampling point, store statistics for said
* sampling point.
*
* @param vm The lua state.
* @return @ref CONST_LUA_PARAM_ERROR in case of wrong parameter,
* CONST_LUA_ERROR in case of generic error, CONST_LUA_OK
* otherwise.
*/
/* @brief Inserts a minute-granularity statistics sample for an interface into the historical DB. Lua: ntop.insertMinuteSampling(ifid, json_data) → nil */
static int ntop_stats_insert_minute_sampling(lua_State* vm) {
char* sampling;
time_t rawtime;
int ifid;
NetworkInterface* iface;
StatsManager* sm;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ifid = lua_tointeger(vm, 1);
if (ifid < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((sampling = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (!(iface = ntop->getInterfaceById(ifid)) ||
!(sm = iface->getStatsManager()))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
time(&rawtime);
if (sm->insertMinuteSampling(rawtime, sampling))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/**
* @brief Insert a new hour sampling in the historical database
* @details Given a certain sampling point, store statistics for said
* sampling point.
*
* @param vm The lua state.
* @return @ref CONST_LUA_PARAM_ERROR in case of wrong parameter,
* CONST_LUA_ERROR in case of generic error, CONST_LUA_OK
* otherwise.
*/
/* @brief Inserts an hour-granularity statistics sample for an interface into the historical DB. Lua: ntop.insertHourSampling(ifid, json_data) → nil */
static int ntop_stats_insert_hour_sampling(lua_State* vm) {
char* sampling;
time_t rawtime;
int ifid;
NetworkInterface* iface;
StatsManager* sm;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ifid = lua_tointeger(vm, 1);
if (ifid < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((sampling = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (!(iface = ntop->getInterfaceById(ifid)) ||
!(sm = iface->getStatsManager()))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
time(&rawtime);
rawtime -= (rawtime % 60);
if (sm->insertHourSampling(rawtime, sampling))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/**
* @brief Insert a new day sampling in the historical database
* @details Given a certain sampling point, store statistics for said
* sampling point.
*
* @param vm The lua state.
* @return @ref CONST_LUA_PARAM_ERROR in case of wrong parameter,
* CONST_LUA_ERROR in case of generic error, CONST_LUA_OK
* otherwise.
*/
/* @brief Inserts a day-granularity statistics sample for an interface into the historical DB. Lua: ntop.insertDaySampling(ifid, json_data) → nil */
static int ntop_stats_insert_day_sampling(lua_State* vm) {
char* sampling;
time_t rawtime;
int ifid;
NetworkInterface* iface;
StatsManager* sm;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ifid = lua_tointeger(vm, 1);
if (ifid < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((sampling = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (!(iface = ntop->getInterfaceById(ifid)) ||
!(sm = iface->getStatsManager()))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
time(&rawtime);
rawtime -= (rawtime % 60);
if (sm->insertDaySampling(rawtime, sampling))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/**
* @brief Get a minute sampling from the historical database
* @details Given a certain sampling point, get statistics for said
* sampling point.
*
* @param vm The lua state.
* @return @ref CONST_LUA_PARAM_ERROR in case of wrong parameter,
* CONST_LUA_ERROR in case of generic error, CONST_LUA_OK
* otherwise.
*/
/* @brief Retrieves the minute statistics sample for an interface at a given epoch. Lua: ntop.getMinuteSampling(ifid, epoch) → string */
static int ntop_stats_get_minute_sampling(lua_State* vm) {
time_t epoch;
string sampling;
int ifid;
NetworkInterface* iface;
StatsManager* sm;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ifid = lua_tointeger(vm, 1);
if (ifid < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
epoch = (time_t)lua_tointeger(vm, 2);
if (!(iface = ntop->getInterfaceById(ifid)) ||
!(sm = iface->getStatsManager()))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (sm->getMinuteSampling(epoch, &sampling))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushstring(vm, sampling.c_str());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/**
* @brief Delete minute stats older than a certain number of days.
* @details Given a number of days, delete stats for the current interface that
* are older than a certain number of days.
*
* @param vm The lua state.
* @return @ref CONST_LUA_PARAM_ERROR in case of wrong parameter,
* CONST_LUA_ERROR in case of generic error, CONST_LUA_OK
* otherwise.
*/
/* @brief Purges minute-granularity statistics records older than the given number of days. Lua: ntop.deleteMinuteStatsOlderThan(ifid, num_days) → nil */
static int ntop_stats_delete_minute_older_than(lua_State* vm) {
int num_days;
int ifid;
NetworkInterface* iface;
StatsManager* sm;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ifid = lua_tointeger(vm, 1);
if (ifid < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
num_days = lua_tointeger(vm, 2);
if (num_days < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (!(iface = ntop->getInterfaceById(ifid)) ||
!(sm = iface->getStatsManager()))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (sm->deleteMinuteStatsOlderThan(num_days))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/**
* @brief Delete hour stats older than a certain number of days.
* @details Given a number of days, delete stats for the current interface that
* are older than a certain number of days.
*
* @param vm The lua state.
* @return @ref CONST_LUA_PARAM_ERROR in case of wrong parameter,
* CONST_LUA_ERROR in case of generic error, CONST_LUA_OK
* otherwise.
*/
/* @brief Purges hour-granularity statistics records older than the given number of days. Lua: ntop.deleteHourStatsOlderThan(ifid, num_days) → nil */
static int ntop_stats_delete_hour_older_than(lua_State* vm) {
int num_days;
int ifid;
NetworkInterface* iface;
StatsManager* sm;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ifid = lua_tointeger(vm, 1);
if (ifid < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
num_days = lua_tointeger(vm, 2);
if (num_days < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (!(iface = ntop->getInterfaceById(ifid)) ||
!(sm = iface->getStatsManager()))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (sm->deleteHourStatsOlderThan(num_days))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/**
* @brief Delete day stats older than a certain number of days.
* @details Given a number of days, delete stats for the current interface that
* are older than a certain number of days.
*
* @param vm The lua state.
* @return @ref CONST_LUA_PARAM_ERROR in case of wrong parameter,
* CONST_LUA_ERROR in case of generic error, CONST_LUA_OK
* otherwise.
*/
/* @brief Purges day-granularity statistics records older than the given number of days. Lua: ntop.deleteDayStatsOlderThan(ifid, num_days) → nil */
static int ntop_stats_delete_day_older_than(lua_State* vm) {
int num_days;
int ifid;
NetworkInterface* iface;
StatsManager* sm;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ifid = lua_tointeger(vm, 1);
if (ifid < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
num_days = lua_tointeger(vm, 2);
if (num_days < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (!(iface = ntop->getInterfaceById(ifid)) ||
!(sm = iface->getStatsManager()))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (sm->deleteDayStatsOlderThan(num_days))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/**
* @brief Get an interval of minute stats samplings from the historical database
* @details Given a certain interval of sampling points, get statistics for said
* sampling points.
*
* @param vm The lua state.
* @return @ref CONST_LUA_PARAM_ERROR in case of wrong parameter,
* CONST_LUA_ERROR in case of generic error, CONST_LUA_OK
* otherwise.
*/
/* @brief Returns minute statistics samples in the given epoch range. Lua: ntop.getMinuteSamplingsInterval(ifid, from_epoch, to_epoch) → table */
static int ntop_stats_get_minute_samplings_interval(lua_State* vm) {
time_t epoch_start, epoch_end;
int ifid;
NetworkInterface* iface;
StatsManager* sm;
struct statsManagerRetrieval retvals;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ifid = lua_tointeger(vm, 1);
if (ifid < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
epoch_start = lua_tointeger(vm, 2);
if (epoch_start < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
epoch_end = lua_tointeger(vm, 3);
if (epoch_end < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (!(iface = ntop->getInterfaceById(ifid)) ||
!(sm = iface->getStatsManager()))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (sm->retrieveMinuteStatsInterval(epoch_start, epoch_end, &retvals))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_newtable(vm);
for (unsigned i = 0; i < retvals.rows.size(); i++)
lua_push_str_table_entry(vm, retvals.rows[i].c_str(), (char*)"");
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/**
* @brief Given an epoch, get minute stats for the latest n minutes
* @details Given a certain sampling point, get statistics for that point and
* for all timepoints spanning an interval of a given number of
* minutes.
*
* @param vm The lua state.
* @return @ref CONST_LUA_PARAM_ERROR in case of wrong parameter,
* CONST_LUA_ERROR in case of generic error, CONST_LUA_OK
* otherwise.
*/
/* @brief Returns all minute-granularity statistics samples starting from a given epoch. Lua: ntop.getMinuteSamplingsFromEpoch(ifid, epoch) → table */
static int ntop_stats_get_samplings_of_minutes_from_epoch(lua_State* vm) {
time_t epoch_start, epoch_end;
NetworkInterface* iface = getCurrentInterface(vm);
StatsManager* sm;
struct statsManagerRetrieval retvals;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
epoch_end = lua_tointeger(vm, 1);
/* Round at the closest hour */
epoch_end -= (epoch_end % 60);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
epoch_start = lua_tointeger(vm, 2);
/* Round at the closest hour */
epoch_start -= (epoch_start % 60);
if (!(sm = iface->getStatsManager()))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (sm->retrieveMinuteStatsInterval(epoch_start, epoch_end, &retvals))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_newtable(vm);
for (unsigned i = 0; i < retvals.rows.size(); i++)
lua_push_str_table_entry(vm, retvals.rows[i].c_str(), (char*)"");
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/**
* @brief Given an epoch, get hour stats for the latest n hours
* @details Given a certain sampling point, get statistics for that point and
* for all timepoints spanning an interval of a given number of
* hours.
*
* @param vm The lua state.
* @return @ref CONST_LUA_PARAM_ERROR in case of wrong parameter,
* CONST_LUA_ERROR in case of generic error, CONST_LUA_OK
* otherwise.
*/
/* @brief Returns all hour-granularity statistics samples starting from a given epoch. Lua: ntop.getHourSamplingsFromEpoch(ifid, epoch) → table */
static int ntop_stats_get_samplings_of_hours_from_epoch(lua_State* vm) {
time_t epoch_start, epoch_end;
NetworkInterface* iface = getCurrentInterface(vm);
StatsManager* sm;
struct statsManagerRetrieval retvals;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
epoch_end = lua_tointeger(vm, 1);
/* Round at the closest hour */
epoch_end -= (epoch_end % 60);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
epoch_start = lua_tointeger(vm, 2);
/* Round at the closest hour */
epoch_start -= (epoch_start % 60);
if (!(sm = iface->getStatsManager()))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (sm->retrieveHourStatsInterval(epoch_start, epoch_end, &retvals))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_newtable(vm);
for (unsigned i = 0; i < retvals.rows.size(); i++)
lua_push_str_table_entry(vm, retvals.rows[i].c_str(), (char*)"");
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/**
* @brief Given an epoch, get hour stats for the latest n days
* @details Given a certain sampling point, get statistics for that point and
* for all timepoints spanning an interval of a given number of
* days.
*
* @param vm The lua state.
* @return @ref CONST_LUA_PARAM_ERROR in case of wrong parameter,
* CONST_LUA_ERROR in case of generic error, CONST_LUA_OK
* otherwise.
*/
/* @brief Returns all day-granularity statistics samples starting from a given epoch. Lua: ntop.getDaySamplingsFromEpoch(ifid, epoch) → table */
static int ntop_stats_get_samplings_of_days_from_epoch(lua_State* vm) {
time_t epoch_start, epoch_end;
NetworkInterface* iface = getCurrentInterface(vm);
StatsManager* sm;
struct statsManagerRetrieval retvals;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
epoch_end = lua_tointeger(vm, 1);
/* Round at the closest hour */
epoch_end -= (epoch_end % 60);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
epoch_start = lua_tointeger(vm, 2);
/* Round at the closest hour */
epoch_start -= (epoch_start % 60);
if (!(sm = iface->getStatsManager()))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (sm->retrieveDayStatsInterval(epoch_start, epoch_end, &retvals))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_newtable(vm);
for (unsigned i = 0; i < retvals.rows.size(); i++)
lua_push_str_table_entry(vm, retvals.rows[i].c_str(), (char*)"");
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/*
Code partially taken from third-party/rrdtool-1.4.7/bindings/lua/rrdlua.c
and made reentrant
*/
static void reset_rrd_state(void) {
optind = 0;
opterr = 0;
rrd_clear_error();
}
/* ****************************************** */
static int ntop_rrd_get_lastupdate(const char* filename, time_t* last_update,
unsigned long* ds_count) {
char** ds_names;
char** last_ds;
unsigned long i;
int status;
reset_rrd_state();
status =
rrd_lastupdate_r(filename, last_update, ds_count, &ds_names, &last_ds);
if (status != 0) {
return (-1);
} else {
for (i = 0; i < *ds_count; i++) free(last_ds[i]), free(ds_names[i]);
free(last_ds), free(ds_names);
return (0);
}
}
/* ****************************************** */
static bool ntop_delete_old_rrd_files_recursive(const char* dir_name,
time_t now,
int older_than_seconds) {
struct dirent* result;
int path_length;
char path[MAX_PATH];
DIR* d;
time_t last_update;
unsigned long ds_count;
if (!dir_name || strlen(dir_name) > MAX_PATH) return false;
d = opendir(dir_name);
if (!d) return false;
while ((result = readdir(d)) != NULL) {
if (result->d_type & DT_REG) {
if ((path_length = snprintf(path, MAX_PATH, "%s/%s", dir_name,
result->d_name)) <= MAX_PATH) {
ntop->fixPath(path);
if (ntop_rrd_get_lastupdate(path, &last_update, &ds_count) == 0) {
if ((now >= last_update) &&
((now - last_update) > older_than_seconds)) {
// printf("DELETE %s\n", path);
unlink(path);
}
}
}
} else if (result->d_type & DT_DIR) {
if (strncmp(result->d_name, "..", 2) && strncmp(result->d_name, ".", 1)) {
if ((path_length = snprintf(path, MAX_PATH, "%s/%s", dir_name,
result->d_name)) <= MAX_PATH) {
ntop->fixPath(path);
ntop_delete_old_rrd_files_recursive(path, now, older_than_seconds);
}
}
}
}
rmdir(dir_name); /* Remove the directory, if empty */
closedir(d);
return true;
}
/* ****************************************** */
/* @brief Removes stale/unused RRD files from the data directory. Lua: ntop.deleteOldRRDs() → nil */
static int ntop_delete_old_rrd_files(lua_State* vm) {
char path[PATH_MAX + 8];
int older_than_seconds;
time_t now = time(NULL);
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
strncpy(path, lua_tostring(vm, 1), sizeof(path) - 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((older_than_seconds = lua_tointeger(vm, 2)) < 0)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ntop->fixPath(path);
if (ntop_delete_old_rrd_files_recursive(path, now, older_than_seconds))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Creates a directory tree recursively, equivalent to 'mkdir -p'. Lua: ntop.mkdir(path) → nil */
static int ntop_mkdir_tree(lua_State* vm) {
char* dir;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushnil(vm);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((dir = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (dir[0] == '\0') {
lua_pushboolean(vm, true);
return (ntop_lua_return_value(vm, __FUNCTION__,
CONST_LUA_OK)); /* Nothing to do */
}
ntop->getTrace()->traceEvent(TRACE_DEBUG, "Trying to created directory %s",
dir);
lua_pushboolean(vm, Utils::mkdir_tree(dir));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns a table listing available report files. Lua: ntop.listReports() → table */
static int ntop_list_reports(lua_State* vm) {
DIR* dir;
char fullpath[MAX_PATH + 64];
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_newtable(vm);
snprintf(fullpath, sizeof(fullpath) - 1, "%s/%s", ntop->get_working_dir(),
"reports");
ntop->fixPath(fullpath);
if ((dir = opendir(fullpath)) != NULL) {
struct dirent* ent;
while ((ent = readdir(dir)) != NULL) {
char filepath[MAX_PATH + MAX_PATH + 64 + 1];
struct stat buf;
snprintf(filepath, sizeof(filepath), "%s/%s", fullpath, ent->d_name);
ntop->fixPath(filepath);
if (!stat(filepath, &buf) && !S_ISDIR(buf.st_mode))
lua_push_str_table_entry(vm, ent->d_name, (char*)"");
}
closedir(dir);
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns Redis connection status and server information. Lua: ntop.getCacheStatus() → table */
static int ntop_info_redis(lua_State* vm) {
char* rsp;
u_int rsp_len = CONST_MAX_LEN_REDIS_VALUE;
Redis* redis = ntop->getRedis();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_newtable(vm);
if ((rsp = (char*)malloc(rsp_len)) != NULL) {
lua_push_str_table_entry(
vm, "info", (redis->info(rsp, rsp_len) == 0) ? rsp : (char*)"");
lua_push_uint64_table_entry(vm, "dbsize", redis->dbsize());
free(rsp);
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Retrieves a string value from Redis by key; returns nil if not found. Lua: ntop.getCache(key) / ntop.getPref(key) → string */
static int ntop_get_redis(lua_State* vm) {
char *key, *rsp = NULL;
Redis* redis = ntop->getRedis();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
rsp = redis->getWithAlloc(key);
if (rsp) {
lua_pushfstring(vm, "%s", rsp);
free(rsp);
} else
lua_pushfstring(vm, "");
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Atomically increments a Redis integer counter (default increment: 1). Lua: ntop.incrCache(key[, increment]) → integer */
static int ntop_incr_redis(lua_State* vm) {
char* key;
u_int rsp;
int amount = 1;
Redis* redis = ntop->getRedis();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 2) == LUA_TNUMBER) amount = lua_tonumber(vm, 2);
rsp = redis->incr(key, amount);
lua_pushinteger(vm, rsp);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Retrieves a single field value from a Redis hash. Lua: ntop.getHashCache(key, field) → string */
static int ntop_get_hash_redis(lua_State* vm) {
char *key, *member, *rsp;
Redis* redis = ntop->getRedis();
u_int json_len;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((member = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
json_len = ntop->getRedis()->hstrlen(key, member);
if (json_len == 0) {
#ifdef WIN32
json_len = CONST_MAX_LEN_REDIS_VALUE;
#else
/*
We assume that redis is recent enough to return 0 when string is missing
and not because it is an outdated value
*/
lua_pushstring(vm, "");
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
#endif
} else
json_len += 8; /* Little overhead */
if ((rsp = (char*)malloc(json_len)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushfstring(
vm, "%s",
(redis->hashGet(key, member, rsp, json_len - 1) == 0) ? rsp : (char*)"");
free(rsp);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Sets a field value in a Redis hash. Lua: ntop.setHashCache(key, field, value) → nil */
static int ntop_set_hash_redis(lua_State* vm) {
char *key, *member, *value;
Redis* redis = ntop->getRedis();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((member = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((value = (char*)lua_tostring(vm, 3)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
redis->hashSet(key, member, value);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
static void ntop_reset_host_name(lua_State* vm, char* address) {
NetworkInterface* iface;
char buf[64], *host_ip;
Host* host;
u_int16_t vlan_id;
get_host_vlan_info(address, &host_ip, &vlan_id, buf, sizeof(buf));
for (int i = 0; i < ntop->get_num_interfaces(); i++) {
if ((iface = ntop->getInterface(i)) != NULL) {
host = iface->findHostByIP(get_allowed_nets(vm), host_ip, vlan_id,
getLuaVMUservalue(vm, observationPointId));
if (host) host->requestNameReset();
}
}
}
/* ****************************************** */
/* @brief Caches a DNS reverse mapping for an IP address in Redis. Lua: ntop.setResolvedAddress(ip, hostname) → nil */
static int ntop_set_resolved_address(lua_State* vm) {
char *ip, *name;
Redis* redis = ntop->getRedis();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((ip = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((name = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
redis->setResolvedAddress(ip, name);
ntop_reset_host_name(vm, ip);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Deletes a field from a Redis hash. Lua: ntop.delHashCache(key, field) → nil */
static int ntop_delete_hash_redis_key(lua_State* vm) {
char *key, *member;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((member = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ntop->getRedis()->hashDel(key, member);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns all field names present in a Redis hash. Lua: ntop.getHashKeysCache(key) → table */
static int ntop_get_hash_keys_redis(lua_State* vm) {
char *key, **vals;
Redis* redis = ntop->getRedis();
int rc;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
rc = redis->hashKeys(key, &vals);
if (rc > 0) {
lua_newtable(vm);
for (int i = 0; i < rc; i++) {
lua_push_str_table_entry(vm, vals[i] ? vals[i] : "", (char*)"");
if (vals[i]) free(vals[i]);
}
free(vals);
} else
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns all field-value pairs from a Redis hash as a Lua table. Lua: ntop.getHashAllCache(key) → table */
static int ntop_get_hash_all_redis(lua_State* vm) {
char *key, **keys, **values;
Redis* redis = ntop->getRedis();
int rc;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
rc = redis->hashGetAll(key, &keys, &values);
if (rc > 0) {
lua_newtable(vm);
for (int i = 0; i < rc; i++) {
lua_push_str_table_entry(vm, keys[i] ? keys[i] : (char*)"",
values[i] ? values[i] : (char*)"");
if (values[i]) free(values[i]);
if (keys[i]) free(keys[i]);
}
free(keys);
free(values);
} else
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns all Redis keys matching the given glob pattern. Lua: ntop.getKeysCache(pattern) → table */
static int ntop_get_keys_redis(lua_State* vm) {
char *pattern, **keys = NULL;
Redis* redis = ntop->getRedis();
int rc;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((pattern = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
rc = redis->keys(pattern, &keys);
if (rc > 0) {
lua_newtable(vm);
for (int i = 0; i < rc; i++) {
lua_push_str_table_entry(vm, keys[i] ? keys[i] : "", (char*)"");
if (keys[i]) free(keys[i]);
}
} else
lua_pushnil(vm);
if (keys) free(keys);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns a range of elements from a Redis list (0-based indices). Lua: ntop.lrangeCache(key, start, stop) → table */
static int ntop_lrange_redis(lua_State* vm) {
char *l_name, **l_elements = NULL;
Redis* redis = ntop->getRedis();
int start_offset = 0, end_offset = -1;
int rc;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((l_name = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 2) == LUA_TNUMBER) {
start_offset = lua_tointeger(vm, 2);
}
if (lua_type(vm, 3) == LUA_TNUMBER) {
end_offset = lua_tointeger(vm, 3);
}
rc = redis->lrange(l_name, &l_elements, start_offset, end_offset);
if (rc > 0) {
lua_newtable(vm);
for (int i = 0; i < rc; i++) {
lua_pushstring(vm, l_elements[i] ? l_elements[i] : "");
lua_rawseti(vm, -2, i + 1);
if (l_elements[i]) free(l_elements[i]);
}
} else
lua_pushnil(vm);
if (l_elements) free(l_elements);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the current length of a Redis list. Lua: ntop.llenCache(key) → integer */
static int ntop_llen_redis(lua_State* vm) {
char* l_name;
Redis* redis = ntop->getRedis();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!redis) return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((l_name = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushinteger(vm, redis->llen(l_name));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if a binary RDB dump is available for a Redis key. Lua: ntop.hasDumpCache(key) → boolean */
static int ntop_redis_has_dump(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->getRedis()->hasRedisDump());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns a binary serialization (RDB dump) of a Redis key's value. Lua: ntop.dumpCache(key) → string */
static int ntop_redis_dump(lua_State* vm) {
char *key, *dump;
Redis* redis = ntop->getRedis();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!redis->hasRedisDump()) {
lua_pushnil(vm); /* This is old redis */
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else {
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
dump = redis->dump(key);
if (dump) {
lua_pushfstring(vm, "%s", dump);
free(dump);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
}
/* ****************************************** */
/* @brief Restores a Redis key from a previously obtained binary RDB dump. Lua: ntop.restoreCache(key, dump_data) → boolean */
static int ntop_redis_restore(lua_State* vm) {
char *key, *dump;
Redis* redis = ntop->getRedis();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!redis->hasRedisDump()) {
lua_pushnil(vm); /* This is old redis */
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else {
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((dump = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lua_pushboolean(vm, (redis->restore(key, dump) != 0));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
}
/* ****************************************** */
/* @brief Returns the element at the given 0-based index in a Redis list. Lua: ntop.listIndexCache(key, index) → string */
static int ntop_list_index_redis(lua_State* vm) {
char *index_name, *rsp;
Redis* redis = ntop->getRedis();
int idx;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((index_name = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
idx = lua_tointeger(vm, 2);
if ((rsp = (char*)malloc(CONST_MAX_LEN_REDIS_VALUE)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (redis->lindex(index_name, idx, rsp, CONST_MAX_LEN_REDIS_VALUE) != 0) {
free(rsp);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
lua_pushfstring(vm, "%s", rsp);
free(rsp);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Internal helper implementing lpop/rpop; called by ntop_lpop_redis and ntop_rpop_redis. Lua: (internal helper) → string */
static int ntop_lrpop_redis(lua_State* vm, bool lpop) {
char msg[1024], *list_name;
Redis* redis = ntop->getRedis();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((list_name = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((lpop ? redis->lpop(list_name, msg, sizeof(msg))
: redis->rpop(list_name, msg, sizeof(msg))) == 0) {
lua_pushfstring(vm, "%s", msg);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
/* ****************************************** */
/* @brief Pops and returns the leftmost (head) element from a Redis list. Lua: ntop.lpopCache(key) → string */
static int ntop_lpop_redis(lua_State* vm) {
return ntop_lrpop_redis(vm, true /* LPOP */);
}
/* ****************************************** */
/* @brief Pops and returns the rightmost (tail) element from a Redis list. Lua: ntop.rpopCache(key) → string */
static int ntop_rpop_redis(lua_State* vm) {
return ntop_lrpop_redis(vm, false /* RPOP */);
}
/* ****************************************** */
/* @brief Removes up to count matching elements from a Redis list. Lua: ntop.lremCache(key, count, value) → nil */
static int ntop_lrem_redis(lua_State* vm) {
char *list_name, *rem_value;
int ret;
Redis* redis = ntop->getRedis();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((list_name = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((rem_value = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ret = redis->lrem(list_name, rem_value);
if (ret == 0)
lua_pushboolean(vm, true);
else
lua_pushboolean(vm, false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Trims a Redis list to only the elements in the specified index range. Lua: ntop.ltrimCache(key, start, stop) → nil */
static int ntop_ltrim_redis(lua_State* vm) {
char* list_name;
int start_idx, end_idx;
Redis* redis = ntop->getRedis();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((list_name = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
start_idx = lua_tonumber(vm, 2);
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
end_idx = lua_tonumber(vm, 3);
if (redis && redis->ltrim(list_name, start_idx, end_idx) == 0) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
/* ****************************************** */
/* @brief Internal helper implementing lpush/rpush used by ntop_lpush_redis and ntop_rpush_redis. Lua: (internal helper) → nil */
static int ntop_push_redis(lua_State* vm, bool use_lpush) {
char *list_name, *value;
u_int list_trim_size = 0; // default 0 = no trim
Redis* redis = ntop->getRedis();
int rv;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((list_name = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((value = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
/* Optional trim list up to the specified number of elements */
if (lua_type(vm, 3) == LUA_TNUMBER)
list_trim_size = (u_int)lua_tonumber(vm, 3);
if (use_lpush)
rv = redis->lpush(list_name, value, list_trim_size);
else
rv = redis->rpush(list_name, value, list_trim_size);
if (rv == 0) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
/* ****************************************** */
/* @brief Pushes a value onto the left (head) of a Redis list. Lua: ntop.lpushCache(key, value) → nil */
static int ntop_lpush_redis(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
return ntop_push_redis(vm, true);
}
/* ****************************************** */
/* @brief Pushes a value onto the right (tail) of a Redis list. Lua: ntop.rpushCache(key, value) → nil */
static int ntop_rpush_redis(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
return ntop_push_redis(vm, false);
}
/* ****************************************** */
/* @brief Adds a CIDR network to the runtime list of local networks. Lua: ntop.addLocalNetwork(cidr) → nil */
static int ntop_add_local_network(lua_State* vm) {
char* local_network;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((local_network = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ntop->addLocalNetworkList(local_network);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the configured alias for a local network CIDR, or nil. Lua: ntop.getLocalNetworkAlias(cidr) → string */
static int ntop_check_local_network_alias(lua_State* vm) {
u_int32_t network_id = (u_int32_t)-1;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (lua_type(vm, 1) == LUA_TSTRING) {
char* local_network;
if ((local_network = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
network_id = ntop->getLocalNetworkId(local_network);
} else if (lua_type(vm, 1) == LUA_TNUMBER) {
network_id = (u_int32_t)lua_tonumber(vm, 1);
}
if (network_id != (u_int32_t)-1) {
if (!ntop->getLocalNetworkAlias(vm, network_id)) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the internal numeric id for a local network CIDR. Lua: ntop.getLocalNetworkID(cidr) → integer */
static int ntop_get_local_network_id(lua_State* vm) {
char* local_network;
u_int32_t network_id = (u_int32_t)-1;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((local_network = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
network_id = ntop->getLocalNetworkId(local_network);
lua_pushinteger(vm, network_id);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#ifndef HAVE_NEDGE
#ifdef NTOPNG_PRO
/* @brief Validates sub-interface configuration syntax (Pro, non-nEdge). Lua: ntop.checkSubInterfaceSyntax(str) → boolean */
static int ntop_check_sub_interface_syntax(lua_State* vm) {
#ifdef HAVE_NBPF
char* filter;
NetworkInterface* curr_iface = getCurrentInterface(vm);
#endif
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
#ifdef HAVE_NBPF
filter = (char*)lua_tostring(vm, 1);
#endif
lua_pushboolean(vm,
#ifdef HAVE_NBPF
curr_iface ? curr_iface->checkSubInterfaceSyntax(filter) :
#endif
false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
#endif
/* ****************************************** */
#ifdef NTOPNG_PRO
/* @brief Validates a BPF-like filter expression syntax (Pro). Lua: ntop.checkFilterSyntax(str) → boolean */
static int ntop_check_filter_syntax(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
#ifdef HAVE_NEDGE
lua_pushboolean(vm, true); /* TODO need to implement the logic */
#else
#ifdef HAVE_NBPF
char* filter;
NetworkInterface* curr_iface = getCurrentInterface(vm);
#endif
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
#ifdef HAVE_NBPF
filter = (char*)lua_tostring(vm, 1);
#endif
lua_pushboolean(vm,
#ifdef HAVE_NBPF
curr_iface ? curr_iface->checkFilterSyntax(filter) :
#endif
false);
#endif
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
/* ****************************************** */
#ifndef HAVE_NEDGE
#ifdef NTOPNG_PRO
/* @brief Reloads traffic profiles from Redis configuration (Pro, non-nEdge). Lua: ntop.reloadProfiles() → nil */
static int ntop_reload_traffic_profiles(lua_State* vm) {
NetworkInterface* curr_iface = getCurrentInterface(vm);
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (curr_iface)
curr_iface->updateFlowProfiles(); /* Reload profiles in memory */
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
#endif
/* ****************************************** */
static int _ntop_set_redis(bool do_setnx, lua_State* vm) {
char *key, *value, buf[21];
u_int expire_secs = 0; // default 0 = no expiration
Redis* redis = ntop->getRedis();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((key = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 2) == LUA_TSTRING) {
if ((value = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
} else if (lua_type(vm, 2) == LUA_TNUMBER) {
u_int64_t v = (u_int64_t)lua_tonumber(vm, 2);
snprintf(buf, sizeof(buf), "%llu", (unsigned long long)v);
value = buf;
} else if (lua_type(vm, 2) == LUA_TBOOLEAN) {
bool v = (bool)lua_toboolean(vm, 2);
snprintf(buf, sizeof(buf), "%s", v ? "true" : "false");
value = buf;
} else {
lua_pushboolean(vm, false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* Optional key expiration in SECONDS */
if (lua_type(vm, 3) == LUA_TNUMBER) expire_secs = (u_int)lua_tonumber(vm, 3);
if (do_setnx)
lua_pushboolean(vm, (redis->setnx(key, value, expire_secs) ==
1 /* value added (not existing) */)
? true
: false);
else
lua_pushboolean(vm, (redis->set(key, value, expire_secs) == 0));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Sets a string value in Redis with optional TTL expiration. Lua: ntop.setCache(key, value[, ttl_secs]) → nil */
static int ntop_set_redis(lua_State* vm) {
return (_ntop_set_redis(false, vm));
}
/* @brief Sets a Redis key only if it does not already exist (atomic set-if-not-exists). Lua: ntop.setnxCache(key, value) → boolean */
static int ntop_setnx_redis(lua_State* vm) {
return (_ntop_set_redis(true, vm));
}
/* ****************************************** */
/* @brief Sets a system preference in Redis (alias for setCache with ntopng.prefs. prefix). Lua: ntop.setPref(key, value) → nil */
static int ntop_set_preference(lua_State* vm) { return (ntop_set_redis(vm)); }
/* ****************************************** */
/* @brief Returns true if login authentication is globally disabled. Lua: ntop.isLoginDisabled() → boolean */
static int ntop_is_login_disabled(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
bool ret = ntop->getPrefs()->is_localhost_users_login_disabled() ||
!ntop->getPrefs()->is_users_login_enabled();
lua_pushboolean(vm, ret);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if a username is temporarily blocked due to brute-force attempts. Lua: ntop.isLoginBlacklisted(username) → boolean */
static int ntop_is_login_blacklisted(lua_State* vm) {
struct mg_connection* conn;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if ((conn = getLuaVMUserdata(vm, conn)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushboolean(vm, ntop->isBlacklistedLogin(conn));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if GUI access is restricted to specific source IP addresses. Lua: ntop.isGuiAccessRestricted() → boolean */
static int ntop_is_gui_access_restricted(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_INFO, "%s() called", __FUNCTION__);
lua_pushboolean(vm, ntop->get_HTTPserver()->is_gui_access_restricted());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Requests a ntopng service restart by writing a restart flag. Lua: ntop.serviceRestart() → nil */
static int ntop_service_restart(lua_State* vm) {
#if defined(__linux__) && defined(NTOPNG_PRO)
extern AfterShutdownAction afterShutdownAction;
ntop->getTrace()->traceEvent(TRACE_INFO, "%s() called", __FUNCTION__);
if (!ntop->isUserAdministrator(vm))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (getppid() == 1 /* parent is systemd */) {
/* See also ntop_shutdown (used by nEdge) */
afterShutdownAction = after_shutdown_restart_self;
ntop->getGlobals()->requestShutdown();
lua_pushboolean(vm, true);
}
lua_pushboolean(vm, false);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
#else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
#endif
}
/* ****************************************** */
/* @brief Returns the observation point id assigned to a user. Lua: ntop.getUserObservationPointId(username) → integer */
static int ntop_get_user_observation_point_id(lua_State* vm) {
char* username;
if ((username = getLuaVMUserdata(vm, user)) == NULL) {
lua_pushboolean(vm, false);
} else {
char key[64], val[16];
NetworkInterface* iface = getCurrentInterface(vm);
bool rc = false;
snprintf(key, sizeof(key), NTOPNG_PREFS_PREFIX ".%s.observationPointId",
username);
if (ntop->getRedis()->get(key, val, sizeof(val)) != -1) {
u_int16_t observationPointId = (u_int16_t)atoi(val);
if (iface->haveObservationPointsDefined()) {
if (!iface->hasObservationPointId(observationPointId)) {
observationPointId = iface->getFirstObservationPointId();
snprintf(val, sizeof(val), "%u", observationPointId);
ntop->getRedis()->set(key, val);
}
getLuaVMUservalue(vm, observationPointId) = observationPointId;
rc = true;
lua_pushinteger(vm, observationPointId);
}
}
if (!rc) lua_pushinteger(vm, 0 /* No observation point */);
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Sets the global log verbosity level (debug/normal/warning/error/quiet). Lua: ntop.setLoggingLevel(level_str) → nil */
static int ntop_set_logging_level(lua_State* vm) {
char* lvlStr;
ntop->getTrace()->traceEvent(TRACE_INFO, "%s() called", __FUNCTION__);
if (ntop->getPrefs()->hasCmdlTraceLevel())
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lvlStr = (char*)lua_tostring(vm, 1);
if (!strcmp(lvlStr, "trace"))
ntop->getTrace()->set_trace_level(TRACE_LEVEL_TRACE);
else if (!strcmp(lvlStr, "debug"))
ntop->getTrace()->set_trace_level(TRACE_LEVEL_DEBUG);
else if (!strcmp(lvlStr, "info"))
ntop->getTrace()->set_trace_level(TRACE_LEVEL_INFO);
else if (!strcmp(lvlStr, "normal"))
ntop->getTrace()->set_trace_level(TRACE_LEVEL_NORMAL);
else if (!strcmp(lvlStr, "warning"))
ntop->getTrace()->set_trace_level(TRACE_LEVEL_WARNING);
else if (!strcmp(lvlStr, "error"))
ntop->getTrace()->set_trace_level(TRACE_LEVEL_ERROR);
else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* NOTE: use lua traceError function */
/* @brief Logs a message at the specified trace level to the ntopng trace log. Lua: ntop.traceEvent(level, msg) → nil */
static int ntop_trace_event(lua_State* vm) {
char *msg, *fname;
int level, line;
ntop->getTrace()->traceEvent(TRACE_INFO, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
level = lua_tointeger(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((fname = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
line = lua_tointeger(vm, 3);
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if ((msg = (char*)lua_tostring(vm, 4)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ntop->getTrace()->traceEvent(level, fname, line, "%s", msg);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Computes the network address (e.g. 192.168.1.0) from an IP and prefix length. Lua: ntop.networkPrefix(ip, prefix_bits) → string */
static int ntop_network_prefix(lua_State* vm) {
char* address;
char buf[64];
u_int8_t mask;
IpAddress ip;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((address = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
mask = (int)lua_tonumber(vm, 2);
ip.set(address);
lua_pushstring(vm, ip.print(buf, sizeof(buf), mask));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
static const char** make_argv(lua_State* vm, int* argc_out, u_int offset,
int extra_args) {
const char** argv;
int i;
int argc = lua_gettop(vm) + 1 - offset + extra_args;
if (!(argv = (const char**)calloc(argc, sizeof(char*))))
/* raise an error and never return */
luaL_error(vm, "Can't allocate memory for arguments array");
/* fprintf(stderr, "%s\n", argv[0]); */
for (i = 0; i < argc; i++) {
if (i < extra_args) {
argv[i] = ""; /* put an empty extra argument */
} else {
int idx = (i - extra_args) + offset;
/* accepts string or number */
if (lua_isstring(vm, idx) || lua_isnumber(vm, idx)) {
if (!(argv[i] = (char*)lua_tostring(vm, idx))) {
/* raise an error and never return */
luaL_error(vm, "Error duplicating string area for arg #%d", i);
}
// printf("@%u: %s\n", i, argv[i]);
} else {
/* raise an error and never return */
luaL_error(vm, "Invalid arg #%d: args must be strings or numbers", i);
}
}
// ntop->getTrace()->traceEvent(TRACE_NORMAL, "[%d] %s", i, argv[i]);
}
*argc_out = argc;
return (argv);
}
/* ****************************************** */
/* @brief Creates a new RRD file with specified data sources and round-robin archives. Lua: ntop.rrd_create(path, step, start, ...) → nil */
static int ntop_rrd_create(lua_State* vm) {
const char* filename;
unsigned long pdp_step;
const char** argv;
int argc, status, offset = 3;
time_t start_time = time(NULL) - 86400 /* 1 day */;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((filename = (const char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
pdp_step = (unsigned long)lua_tonumber(vm, 2);
if (lua_type(vm, 3) == LUA_TNUMBER) {
start_time = (time_t)lua_tonumber(vm, 3);
offset++;
}
if (Utils::file_exists(filename))
ntop->getTrace()->traceEvent(
TRACE_WARNING, "Overwriting already existing RRD [%s]", filename);
ntop->getTrace()->traceEvent(TRACE_INFO, "%s(%s)", __FUNCTION__, filename);
argv = make_argv(vm, &argc, offset, 0);
reset_rrd_state();
status = rrd_create_r(filename, pdp_step, start_time, argc, argv);
free(argv);
if (status != 0) {
char* err = rrd_get_error();
if (err != NULL) {
char error_buf[256];
snprintf(error_buf, sizeof(error_buf), "Unable to create %s [%s]",
filename, err);
lua_pushstring(vm, error_buf);
} else
lua_pushstring(vm, "Unknown RRD error");
} else {
lua_pushnil(vm);
chmod(filename, CONST_DEFAULT_FILE_MODE);
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Appends a new timestamped data point to an existing RRD file. Lua: ntop.rrd_update(path, timestamp, ...) → nil */
static int ntop_rrd_update(lua_State* vm) {
NtopngLuaContext* ctx = getLuaVMContext(vm);
const char *filename, *when = NULL, *v1 = NULL, *v2 = NULL, *v3 = NULL,
*v4 = NULL, *v5 = NULL, *v6 = NULL;
int status;
ticks ticks_duration;
struct stat s;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((filename = (const char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (stat(filename, &s) != 0) {
char error_buf[256];
snprintf(error_buf, sizeof(error_buf), "File %s does not exist", filename);
lua_pushstring(vm, error_buf);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
// Delete empty rrd files which cause an mmap error
if (s.st_size == 0) {
char error_buf[256];
snprintf(error_buf, sizeof(error_buf), "Empty RRD: %s, deleting it\n",
filename);
lua_pushstring(vm, error_buf);
unlink(filename);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
if (lua_type(vm, 2) == LUA_TSTRING) {
if ((when = (const char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
} else if (lua_type(vm, 2) != LUA_TNIL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (lua_type(vm, 3) == LUA_TSTRING) v1 = (const char*)lua_tostring(vm, 3);
if (lua_type(vm, 4) == LUA_TSTRING) v2 = (const char*)lua_tostring(vm, 4);
if (lua_type(vm, 5) == LUA_TSTRING) v3 = (const char*)lua_tostring(vm, 5);
if (lua_type(vm, 6) == LUA_TSTRING) v4 = (const char*)lua_tostring(vm, 6);
if (lua_type(vm, 6) == LUA_TSTRING) v5 = (const char*)lua_tostring(vm, 7);
if (lua_type(vm, 6) == LUA_TSTRING) v6 = (const char*)lua_tostring(vm, 8);
/* Apparently RRD does not like static buffers, so we need to malloc */
u_int buf_len = 64;
char* buf = (char*)malloc(buf_len);
if (buf) {
snprintf(buf, buf_len, "%s:%s%s%s%s%s%s%s%s%s%s%s", when ? when : "N", v1,
v2 ? ":" : "", v2 ? v2 : "", v3 ? ":" : "", v3 ? v3 : "",
v4 ? ":" : "", v4 ? v4 : "", v5 ? ":" : "", v5 ? v5 : "",
v6 ? ":" : "", v6 ? v6 : "");
// ntop->getTrace()->traceEvent(TRACE_NORMAL, "%s(%s) %s", __FUNCTION__,
// filename, buf);
ticks_duration = Utils::getticks();
reset_rrd_state();
status = rrd_update_r(filename, NULL, 1, (const char**)&buf);
ticks_duration = Utils::getticks() - ticks_duration;
if (ctx && ctx->threaded_activity_stats)
ctx->threaded_activity_stats->updateTimeseriesWriteStats(ticks_duration);
if (status != 0) {
char* err = rrd_get_error();
if (err != NULL) {
char error_buf[256];
snprintf(error_buf, sizeof(error_buf),
"rrd_update_r() [%s][%s] failed [%s]", filename, buf, err);
lua_pushstring(vm, error_buf);
} else
lua_pushstring(vm, "Unknown RRD error");
} else
lua_pushnil(vm);
free(buf);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
/* ****************************************** */
/* @brief Returns the Unix timestamp of the last update recorded in an RRD file. Lua: ntop.rrd_lastupdate(path) → integer */
static int ntop_rrd_lastupdate(lua_State* vm) {
const char* filename;
time_t last_update;
unsigned long ds_count;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((filename = (const char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
reset_rrd_state();
if (ntop_rrd_get_lastupdate(filename, &last_update, &ds_count) == -1) {
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
} else {
lua_pushinteger(vm, last_update);
lua_pushinteger(vm, ds_count);
return (2 /* 2 values returned */);
}
}
/* ****************************************** */
/* @brief Modifies parameters (heartbeat, min/max values) of an existing RRD file. Lua: ntop.rrd_tune(path, ...) → nil */
static int ntop_rrd_tune(lua_State* vm) {
const char* filename;
const char** argv;
int argc, status, offset = 1;
int extra_args = 1; /* Program name arg */
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
argv = make_argv(vm, &argc, offset, extra_args);
if (argc < 2) {
ntop->getTrace()->traceEvent(TRACE_ERROR,
"ntop_rrd_tune: invalid number of arguments");
free(argv);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
filename = argv[1];
reset_rrd_state();
status = rrd_tune(
argc, (std::conditional<
std::is_same<decltype(rrd_tune), int(int, const char**)>::value,
const char**, char**>::type)argv);
if (status != 0) {
char* err = rrd_get_error();
if (err != NULL) {
char error_buf[256];
snprintf(error_buf, sizeof(error_buf),
"Unable to run rrd_tune on %s [%s]", filename, err);
lua_pushstring(vm, error_buf);
} else
lua_pushstring(vm, "Unknown RRD error");
} else
lua_pushnil(vm);
free(argv);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Increments the packet drop counter in an interface RRD file. Lua: ntop.rrd_inc_num_drops(path) → nil */
static int ntop_rrd_inc_num_drops(lua_State* vm) {
NtopngLuaContext* ctx = getLuaVMContext(vm);
u_long num_drops = 1;
if (lua_type(vm, 1) == LUA_TNUMBER) num_drops = lua_tonumber(vm, 1);
if (ctx && ctx->threaded_activity_stats)
ctx->threaded_activity_stats->incTimeseriesWriteDrops(num_drops);
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Returns statistics about the packet drop pool (packets dropped vs configured limit). Lua: ntop.getDropPoolInfo() → table */
static int ntop_get_drop_pool_info(lua_State* vm) {
lua_newtable(vm);
lua_push_str_table_entry(vm, "pool_name", DROP_HOST_POOL_NAME);
lua_push_str_table_entry(vm, "list_key", DROP_HOST_POOL_LIST);
lua_push_uint64_table_entry(vm, "expiration_time",
DROP_HOST_POOL_EXPIRATION_TIME);
return CONST_LUA_OK;
}
/* ****************************************** */
/* @brief Returns true if ntopng was forced offline via command-line flag. Lua: ntop.isForcedOffline() → boolean */
static int ntop_is_forced_offline(lua_State* vm) {
lua_pushboolean(vm, ntop->isForcedOffline());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if ntopng is currently in offline mode. Lua: ntop.isOffline() → boolean */
static int ntop_is_offline(lua_State* vm) {
lua_pushboolean(vm, ntop->isOffline());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Puts ntopng into offline mode (disables outbound connectivity features). Lua: ntop.setOffline() → nil */
static int ntop_set_offline(lua_State* vm) {
ntop->toggleOffline(true);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Updates stored RADIUS login state and session information for a user. Lua: ntop.updateRadiusLoginInfo(info_table) → nil */
static int ntop_update_radius_login_info(lua_State* vm) {
#ifdef HAVE_RADIUS
ntop->updateRadiusLoginInfo();
lua_pushnil(vm);
ntop->getTrace()->traceEvent(TRACE_INFO,
"Radius: updated radius login informations");
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
#else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
#endif
}
/* ****************************************** */
/* @brief Takes ntopng out of offline mode, re-enabling outbound connectivity. Lua: ntop.setOnline() → nil */
static int ntop_set_online(lua_State* vm) {
ntop->toggleOffline(false);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns true if ntopng is in the process of shutting down. Lua: ntop.isShuttingDown() → boolean */
static int ntop_is_shutting_down(lua_State* vm) {
lua_pushboolean(vm, ntop->getGlobals()->isShutdown());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Voluntarily throttles CPU usage of the current Lua thread to avoid overloading. Lua: ntop.limitResourcesUsage() → nil */
static int ntop_limit_resources_usage(lua_State* vm) {
lua_pushboolean(vm, ntop->getPrefs()->limitResourcesUsage());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* positional 1:4 parameters for ntop_rrd_fetch */
/* @brief Internal helper that parses and validates RRD argument lists from the Lua stack. Lua: (internal RRD helper) → nil */
static int __ntop_rrd_args(lua_State* vm, char** filename, char** cf,
time_t* start, time_t* end) {
char *start_s, *end_s, *err;
rrd_time_value_t start_tv, end_tv;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((*filename = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((*cf = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((lua_type(vm, 3) == LUA_TNUMBER) && (lua_type(vm, 4) == LUA_TNUMBER))
*start = (time_t)lua_tonumber(vm, 3), *end = (time_t)lua_tonumber(vm, 4);
else {
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((start_s = (char*)lua_tostring(vm, 3)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((err = rrd_parsetime(start_s, &start_tv)) != NULL) {
lua_pushstring(vm, err);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
}
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((end_s = (char*)lua_tostring(vm, 4)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((err = rrd_parsetime(end_s, &end_tv)) != NULL) {
lua_pushstring(vm, err);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
}
if (rrd_proc_start_end(&start_tv, &end_tv, start, end) == -1)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Internal helper that checks RRD operation status and pushes error/ok to Lua. Lua: (internal RRD helper) → nil */
static int __ntop_rrd_status(lua_State* vm, int status, char* filename,
char* cf) {
char* err;
if (status != 0) {
err = rrd_get_error();
if (err != NULL) {
ntop->getTrace()->traceEvent(TRACE_ERROR,
"Error '%s' while calling rrd_fetch_r(%s, "
"%s): is the RRD corrupted perhaps?",
err, filename, cf);
if (strstr(err, "fetching cdp from rra") != NULL)
unlink(filename); /* 99,99999% this is a corrupted file */
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* Fetches data from RRD by rows */
/* @brief Fetches consolidated data from an RRD file for the given time range. Lua: ntop.rrd_fetch(path, cf, start, stop[, step]) → table */
static int ntop_rrd_fetch(lua_State* vm) {
unsigned long i, j, step = 0, ds_cnt = 0;
rrd_value_t *data, *p;
char** names;
char *filename, *cf;
time_t t, start, end;
#if 0
time_t last_update;
unsigned long ds_count;
#endif
int status;
reset_rrd_state();
if ((status = __ntop_rrd_args(vm, &filename, &cf, &start, &end)) !=
CONST_LUA_OK) {
return status;
}
ntop->getTrace()->traceEvent(TRACE_INFO, "%s(%s)", __FUNCTION__, filename);
if ((status = __ntop_rrd_status(vm,
rrd_fetch_r(filename, cf, &start, &end, &step,
&ds_cnt, &names, &data),
filename, cf)) != CONST_LUA_OK)
return status;
lua_pushinteger(vm, (lua_Integer)start);
lua_pushinteger(vm, (lua_Integer)step);
/* fprintf(stderr, "%lu, %lu, %lu, %lu\n", start, end, step, num_points); */
/* create the ds names array */
lua_newtable(vm);
for (i = 0; i < ds_cnt; i++) {
lua_pushstring(vm, names[i]);
lua_rawseti(vm, -2, i + 1);
rrd_freemem(names[i]);
}
rrd_freemem(names);
/* create the data points array */
lua_newtable(vm);
p = data;
for (t = start + 1, i = 0; t < end; t += step, i++) {
#if 0
bool add_point;
/* Check for avoid going after the last point set */
if(t > last_update) {
ntop->getTrace()->traceEvent(TRACE_INFO, "Skipping %u / %u", t, last_update);
break;
}
if((t == last_update) && (i > 3)) {
/* Add the point only if not zero an dwith at least 3 points or more */
add_point = false;
for(j=0; j<ds_cnt; j++) {
rrd_value_t value = *p++;
if(value != DNAN /* Skip NaN */) {
if(value > 0) {
add_point = true;
break;
}
}
}
add_point = true;
} else
add_point = true;
if(add_point) {
#endif
lua_newtable(vm);
for (j = 0; j < ds_cnt; j++) {
rrd_value_t value = *p++;
if (value != DNAN /* Skip NaN */) {
lua_pushnumber(vm, (lua_Number)value);
lua_rawseti(vm, -2, j + 1);
// ntop->getTrace()->traceEvent(TRACE_NORMAL, "%u / %.f", t, value);
}
}
lua_rawseti(vm, -2, i + 1);
#if 0
} else
break;
#endif
}
rrd_freemem(data);
/* return the end as the last value */
lua_pushinteger(vm, (lua_Integer)end);
/* number of return values: start, step, names, data, end */
return (5);
}
/* ****************************************** */
/*
* Similar to ntop_rrd_fetch, but data series oriented (reads RRD by columns)
*
* Positional parameters:
* filename: RRD file path
* cf: RRD cf
* start: the start time you wish to query
* end: the end time you wish to query
*
* Positional return values:
* start: the time of the first data in the series
* step: the fetched data step
* data: a table, where each key is an RRD name, and the value is its series
* data end: the time of the last data in each series npoints: the number of
* points in each series
*/
/* @brief Fetches RRD data in column-oriented format (one array per data source). Lua: ntop.rrd_fetch_columns(path, cf, start, stop[, step]) → table */
static int ntop_rrd_fetch_columns(lua_State* vm) {
char *filename, *cf;
time_t start, end;
int status;
unsigned int npoints = 0, i, j;
char** names;
unsigned long step = 0, ds_cnt = 0;
rrd_value_t *data, *p;
reset_rrd_state();
if ((status = __ntop_rrd_args(vm, &filename, &cf, &start, &end)) !=
CONST_LUA_OK) {
return status;
}
ntop->getTrace()->traceEvent(TRACE_INFO, "%s(%s)", __FUNCTION__, filename);
if ((status = __ntop_rrd_status(vm,
rrd_fetch_r(filename, cf, &start, &end, &step,
&ds_cnt, &names, &data),
filename, cf)) != CONST_LUA_OK) {
return status;
}
npoints = (end - start) / step;
lua_pushinteger(vm, (lua_Integer)start);
lua_pushinteger(vm, (lua_Integer)step);
/* create the data series table */
lua_createtable(vm, 0, ds_cnt);
for (i = 0; i < ds_cnt; i++) {
/* a single series table, preallocated */
lua_createtable(vm, npoints, 0);
p = data + i;
for (j = 0; j < npoints; j++) {
rrd_value_t value = *p;
/* we are accessing data table by columns */
p = p + ds_cnt;
lua_pushnumber(vm, (lua_Number)value);
lua_rawseti(vm, -2, j + 1);
}
/* add the single series to the series table */
lua_setfield(vm, -2, names[i]);
} /* for */
/* end and npoints as last values */
lua_pushinteger(vm, (lua_Integer)end);
lua_pushinteger(vm, (lua_Integer)npoints);
lua_createtable(vm, 0, ds_cnt);
for (i = 0; i < ds_cnt; i++) {
lua_pushstring(vm, names[i]);
lua_rawseti(vm, -2, i + 1);
rrd_freemem(names[i]);
}
rrd_freemem(names);
rrd_freemem(data);
/* number of return values */
return (6);
}
/* ****************************************** */
/* @brief Returns the network CIDR or alias for the given local network id. Lua: ntop.getNetworkNameById(id) → string */
static int ntop_network_name_by_id(lua_State* vm) {
int id;
const char* name;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
id = (u_int32_t)lua_tonumber(vm, 1);
name = ntop->getLocalNetworkName(id);
lua_pushstring(vm, name ? name : "");
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the internal numeric id for a local network given its CIDR or alias. Lua: ntop.getNetworkIdByName(name) → integer */
static int ntop_network_id_by_name(lua_State* vm) {
u_int32_t num_local_networks = ntop->getNumLocalNetworks();
int found_id = -1;
char* name;
ntop->getTrace()->traceEvent(TRACE_INFO, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
name = (char*)lua_tostring(vm, 1);
for (u_int32_t network_id = 0; network_id < num_local_networks;
network_id++) {
if (!strcmp(ntop->getLocalNetworkName(network_id), name)) {
found_id = network_id;
break;
}
}
lua_pushinteger(vm, found_id);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns a table of all configured local networks with their ids and CIDRs. Lua: ntop.getNetworks() → table */
static int ntop_get_networks(lua_State* vm) {
u_int32_t num_local_networks = ntop->getNumLocalNetworks();
ntop->getTrace()->traceEvent(TRACE_INFO, "%s() called", __FUNCTION__);
lua_newtable(vm);
for (u_int32_t network_id = 0; network_id < num_local_networks; network_id++)
lua_push_uint64_table_entry(vm, ntop->getLocalNetworkName(network_id),
network_id);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Dequeues and returns pending internal alert events from the engine. Lua: ntop.popInternalAlerts() → table */
static int ntop_pop_internal_alerts(lua_State* vm) {
ndpi_serializer* alert = ntop->getInternalAlertsQueue()->dequeue();
if (alert) {
lua_newtable(vm);
Utils::tlv2lua(vm, alert);
ndpi_term_serializer(alert);
free(alert);
} else
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Enqueues a JSON notification string to the specified recipient channel. Lua: ntop.recipient_enqueue(recipient_id, notification_json) → nil */
static int ntop_recipient_enqueue(lua_State* vm) {
NtopngLuaContext* ctx = getLuaVMContext(vm);
u_int16_t recipient_id;
const char* alert;
bool rv = false;
AlertFifoItem* notification;
u_int16_t alert_id = 0;
u_int32_t score = 0;
AlertCategory alert_category = alert_category_other;
AlertEntity alert_entity = alert_entity_other;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
recipient_id = lua_tointeger(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
alert = lua_tostring(vm, 2);
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
score = lua_tonumber(vm, 3);
if (lua_type(vm, 4) == LUA_TNUMBER) alert_id = lua_tonumber(vm, 4);
if (lua_type(vm, 5) == LUA_TNUMBER)
alert_entity = (AlertEntity)lua_tonumber(vm, 5);
if (lua_type(vm, 6) == LUA_TNUMBER)
alert_category = (AlertCategory)lua_tonumber(vm, 6);
notification = new AlertFifoItem();
if (notification) {
notification->alert = alert;
notification->score = score;
notification->alert_severity = Utils::mapScoreToSeverity(score);
notification->alert_id = alert_id;
notification->alert_entity = alert_entity;
notification->alert_category = alert_category;
// ntop->getTrace()->traceEvent(TRACE_NORMAL, "Enqueing alert: %s", alert);
rv = ntop->recipient_enqueue(recipient_id, notification);
}
if (!rv) {
NetworkInterface* iface = getCurrentInterface(vm);
if (iface) {
iface->incNumDroppedAlerts(alert_entity_other);
if (ctx->threaded_activity_stats)
ctx->threaded_activity_stats->setAlertsDrops();
}
delete notification;
}
lua_pushboolean(vm, rv);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Dequeues and returns the next pending notification from a recipient channel. Lua: ntop.recipient_dequeue(recipient_id) → string */
static int ntop_recipient_dequeue(lua_State* vm) {
u_int16_t recipient_id;
AlertFifoItem* notification;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
recipient_id = lua_tointeger(vm, 1);
notification = ntop->recipient_dequeue(recipient_id);
if (notification) {
lua_newtable(vm);
lua_push_str_table_entry(vm, "alert", notification->alert.c_str());
lua_push_uint64_table_entry(vm, "score", notification->score);
lua_push_uint64_table_entry(vm, "alert_severity",
notification->alert_severity);
delete notification;
} else
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns queue length and throughput statistics for all recipient channels. Lua: ntop.recipient_stats() → table */
static int ntop_recipient_stats(lua_State* vm) {
u_int16_t recipient_id;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
recipient_id = lua_tointeger(vm, 1);
ntop->recipient_stats(recipient_id, vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Increments a named performance counter for a recipient channel. Lua: ntop.recipient_inc_stats(recipient_id, stat_name) → nil */
static int ntop_recipient_inc_stats(lua_State* vm) {
u_int16_t recipient_id;
u_int64_t delivered = 0;
u_int64_t filtered_out = 0;
u_int64_t delivery_failures = 0;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
recipient_id = lua_tointeger(vm, 1);
if (lua_type(vm, 2) == LUA_TNUMBER) delivered = lua_tonumber(vm, 2);
if (lua_type(vm, 3) == LUA_TNUMBER) filtered_out = lua_tonumber(vm, 3);
if (lua_type(vm, 4) == LUA_TNUMBER) delivery_failures = lua_tonumber(vm, 4);
ntop->inc_recipient_stats(recipient_id, delivered, filtered_out,
delivery_failures);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the Unix epoch when the recipient queue was last dequeued. Lua: ntop.recipient_last_use(recipient_id) → integer */
static int ntop_recipient_last_use(lua_State* vm) {
u_int16_t recipient_id;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
recipient_id = lua_tointeger(vm, 1);
lua_pushinteger(vm, ntop->recipient_last_use(recipient_id));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Unregisters and removes a recipient notification channel. Lua: ntop.recipient_delete(recipient_id) → nil */
static int ntop_recipient_delete(lua_State* vm) {
u_int16_t recipient_id;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
recipient_id = lua_tointeger(vm, 1);
ntop->recipient_delete(recipient_id);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Registers a new recipient channel for alert notification delivery. Lua: ntop.recipient_register(recipient_id) → nil */
static int ntop_recipient_register(lua_State* vm) {
u_int16_t recipient_id;
AlertLevel minimum_severity = alert_level_none;
char *str_categories, *str_host_pools, *str_entities, *str_flow_alert_types,
*str_host_alert_types, *str_other_alert_types;
bool match_alert_id = false, skip_alerts = false;
Bitmap128 enabled_categories, enabled_entities, enabled_flow_alert_types,
enabled_host_alert_types, enabled_other_alert_types;
Bitmap4096 enabled_host_pools;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
recipient_id = lua_tointeger(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
minimum_severity = (AlertLevel)lua_tointeger(vm, 2);
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((str_categories = (char*)lua_tostring(vm, 3)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
enabled_categories.setBits(str_categories);
if (ntop_lua_check(vm, __FUNCTION__, 4, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((str_host_pools = (char*)lua_tostring(vm, 4)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
enabled_host_pools.setBits(str_host_pools);
if (ntop_lua_check(vm, __FUNCTION__, 5, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((str_entities = (char*)lua_tostring(vm, 5)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
enabled_entities.setBits(str_entities);
if ((lua_type(vm, 6) == LUA_TSTRING) &&
((str_flow_alert_types = (char*)lua_tostring(vm, 6)) != NULL)) {
enabled_flow_alert_types.reset();
enabled_flow_alert_types.setBits(str_flow_alert_types);
match_alert_id = true; /* Match by ID (ignore severity, category, etc) */
}
if ((lua_type(vm, 7) == LUA_TSTRING) &&
((str_host_alert_types = (char*)lua_tostring(vm, 7)) != NULL)) {
enabled_host_alert_types.reset();
enabled_host_alert_types.setBits(str_host_alert_types);
match_alert_id = true; /* Match by ID (ignore severity, category, etc) */
}
if ((lua_type(vm, 8) == LUA_TSTRING) &&
((str_other_alert_types = (char*)lua_tostring(vm, 8)) != NULL)) {
enabled_other_alert_types.reset();
enabled_other_alert_types.setBits(str_other_alert_types);
match_alert_id = true; /* Match by ID (ignore severity, category, etc) */
}
if (lua_type(vm, 9) == LUA_TBOOLEAN) skip_alerts = (bool)lua_toboolean(vm, 9);
/*
char bitmap_buf[64];
ntop->getTrace()->traceEvent(TRACE_NORMAL, "Skip alerts: %s", skip_alerts ?
"true" : "false"); ntop->getTrace()->traceEvent(TRACE_NORMAL, "Recipient ID =
%u", recipient_id); ntop->getTrace()->traceEvent(TRACE_NORMAL, "Categories
bitmap: %s", enabled_categories.toHexString(bitmap_buf, sizeof(bitmap_buf)));
ntop->getTrace()->traceEvent(TRACE_NORMAL, "Hosts bitmap: %s",
enabled_host_pools.toHexString(bitmap_buf, sizeof(bitmap_buf)));
ntop->getTrace()->traceEvent(TRACE_NORMAL, "Entities bitmap: %s",
enabled_entities.toHexString(bitmap_buf, sizeof(bitmap_buf)));
ntop->getTrace()->traceEvent(TRACE_NORMAL, "Flow alert types bitmap: %s",
enabled_flow_alert_types.toHexString(bitmap_buf, sizeof(bitmap_buf)));
ntop->getTrace()->traceEvent(TRACE_NORMAL, "Host alert types bitmap: %s",
enabled_host_alert_types.toHexString(bitmap_buf, sizeof(bitmap_buf)));
ntop->getTrace()->traceEvent(TRACE_NORMAL, "Other alert types bitmap: %s",
enabled_other_alert_types.toHexString(bitmap_buf, sizeof(bitmap_buf)));
*/
ntop->recipient_register(
recipient_id, minimum_severity, enabled_categories, enabled_host_pools,
enabled_entities, enabled_flow_alert_types, enabled_host_alert_types,
enabled_other_alert_types, match_alert_id, skip_alerts);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Returns true if the given nDPI protocol id is a user-defined custom application. Lua: ntop.isCustomApplication(proto_id) → boolean */
static int ndpi_is_custom_application(lua_State* vm) {
u_int16_t app_id;
NetworkInterface* iface = getCurrentInterface(vm);
if ((iface == NULL) ||
(ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
app_id = (u_int16_t)lua_tonumber(vm, 1);
lua_pushboolean(vm, iface->isCustomDPIProtocol(app_id));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Executes a shell command synchronously and returns its stdout output. Lua: ntop.execCmd(cmd) → string */
static int ntop_exec_cmd(lua_State* vm) {
char* cmd;
std::string out;
bool rc;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((cmd = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
rc = Utils::execCmd(cmd, &out);
if (rc) lua_pushstring(vm, out.c_str());
return (ntop_lua_return_value(vm, __FUNCTION__,
rc ? CONST_LUA_OK : CONST_LUA_ERROR));
}
/* ****************************************** */
/* @brief Starts a shell command asynchronously and returns a result handle. Lua: ntop.execCmdAsync(cmd) → integer */
static int ntop_exec_cmd_async(lua_State* vm) {
char* cmd;
u_int32_t id;
bool rc;
JobQueue* jq = ntop->getJobsQueue();
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if ((cmd = (char*)lua_tostring(vm, 1)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
rc = jq->queueJob(cmd, &id);
if (rc)
lua_pushnumber(vm, (lua_Number)id);
else
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__,
rc ? CONST_LUA_OK : CONST_LUA_ERROR));
}
/* ****************************************** */
/* @brief Reads and returns available stdout from an async command handle. Lua: ntop.readResultCmdAsync(handle) → string */
static int ntop_read_result_cmd_async(lua_State* vm) {
u_int32_t id;
bool rc;
JobQueue* jq = ntop->getJobsQueue();
std::string out;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
else
id = (u_int32_t)lua_tonumber(vm, 1);
rc = jq->getJobResult(id, &out);
if (rc)
lua_pushstring(vm, out.c_str());
else
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__,
rc ? CONST_LUA_OK : CONST_LUA_ERROR));
}
/* ****************************************** */
/* @brief Reloads device-to-protocol policy rules from Redis configuration. Lua: ntop.reloadDeviceProtocols() → nil */
static int ntop_reload_device_protocols(lua_State* vm) {
DeviceType device_type = device_unknown;
char* dir; /* client or server */
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TTABLE) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
device_type = (DeviceType)lua_tointeger(vm, 1);
if ((dir = (char*)lua_tostring(vm, 2)) == NULL)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ntop->refreshAllowedProtocolPresets(device_type, !!strcmp(dir, "server"), vm,
3);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the ASN organization name for a given IP address via GeoIP. Lua: ntop.getASName(ip) → string */
static int ntop_get_asn_name(lua_State* vm) {
IpAddress a;
char* as_name;
u_int32_t asn = 0;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
a.set((char*)lua_tostring(vm, 1));
ntop->getGeolocation()->getAS(&a, &asn, &as_name);
if (as_name != NULL) {
lua_pushstring(vm, as_name);
free(as_name);
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the organization name for a given autonomous system number. Lua: ntop.getASNameFromASN(asn_number) → string */
static int ntop_get_as_name_from_asn(lua_State* vm) {
u_int32_t asn;
char as_name[128];
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
else
asn = (u_int32_t)lua_tonumber(vm, 1);
if (ntop->getGeolocation()->getASName(asn, as_name, sizeof(as_name)))
lua_pushstring(vm, as_name);
else
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns geolocation data (country, city, lat, lon) for an IP via GeoIP. Lua: ntop.getHostGeolocation(ip) → table */
static int ntop_get_host_geolocation(lua_State* vm) {
IpAddress ip;
char *continent = NULL, *country_name = NULL, *city = NULL;
float latitude = 0, longitude = 0;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ip.set((char*)lua_tostring(vm, 1));
ntop->getGeolocation()->getInfo(&ip, &continent, &country_name, &city,
&latitude, &longitude);
lua_newtable(vm);
lua_push_str_table_entry(vm, "continent", continent ? continent : (char*)"");
lua_push_str_table_entry(vm, "country",
country_name ? country_name : (char*)"");
lua_push_float_table_entry(vm, "latitude", latitude);
lua_push_float_table_entry(vm, "longitude", longitude);
lua_push_str_table_entry(vm, "city", city ? city : (char*)"");
ntop->getGeolocation()->freeInfo(&continent, &country_name, &city);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Returns the nDPI category id assigned to a protocol id. Lua: ntop.getnDPIProtoCategory(proto_id) → integer */
static int ntop_get_ndpi_protocol_category(lua_State* vm) {
NetworkInterface* curr_iface = getCurrentInterface(vm);
u_int proto;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (!curr_iface)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
proto = (u_int)lua_tonumber(vm, 1);
ndpi_protocol_category_t category = ntop->get_ndpi_proto_category(proto);
lua_newtable(vm);
lua_push_int32_table_entry(vm, "id", category);
lua_push_str_table_entry(vm, "name",
(char*)curr_iface->get_ndpi_category_name(category));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Overrides the nDPI category assignment for a protocol id. Lua: ntop.setnDPIProtoCategory(proto_id, category_id) → nil */
static int ntop_set_ndpi_protocol_category(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
u_int16_t proto;
ndpi_protocol_category_t category;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
proto = (u_int16_t)lua_tonumber(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
category = (ndpi_protocol_category_t)lua_tointeger(vm, 2);
ntop->setnDPIProtocolCategory(proto, category);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* Replace the interfaces configured with -i with the provided one */
/* @brief Overrides the current network interface context (Appliance builds only). Lua: ntop.overrideInterface(ifname) → nil */
static int ntop_override_interface(lua_State* vm) {
char* ifname;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
ifname = (char*)lua_tostring(vm, 1);
ntop->getPrefs()->resetDeferredInterfacesToRegister();
ntop->getPrefs()->addDeferredInterfaceToRegister(ifname);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
#ifdef HAVE_NEDGE
/* @brief Registers an interface as a LAN interface (nEdge only). Lua: ntop.addLanInterface(ifname) → nil */
static int ntop_add_lan_interface(lua_State* vm) {
char* lan_ifname;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lan_ifname = (char*)lua_tostring(vm, 1);
ntop->getPrefs()->add_lan_interface(lan_ifname);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Registers an interface as a WAN interface (nEdge only). Lua: ntop.addWanInterface(ifname) → nil */
static int ntop_add_wan_interface(lua_State* vm) {
char* lan_ifname;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
lan_ifname = (char*)lua_tostring(vm, 1);
ntop->getPrefs()->add_wan_interface(lan_ifname);
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* ****************************************** */
/* @brief Refreshes device-protocol policy configuration from preferences (nEdge only). Lua: ntop.refreshDeviceProtocolsPoliciesConf() → nil */
static int ntop_refresh_device_protocols_policies_pref(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->getPrefs()->refreshDeviceProtocolsPolicyPref();
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#endif
/* **************************************************************** */
/* @brief Adds a weighted data point to a named bin for similarity analysis. Lua: ntop.addBin(name, value, weight) → nil */
static int ntop_add_bin(lua_State* vm) {
#if defined(NTOPNG_PRO)
NtopngLuaContext* ctx = getLuaVMContext(vm);
if (ctx) {
if (ctx->bin == NULL) ctx->bin = new (std::nothrow) BinAnalysis();
if (ctx->bin) return (ctx->bin->addBin(vm));
}
#endif
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Finds and returns bins similar to the named bin by Euclidean distance. Lua: ntop.findSimilarities(name) → table */
static int ntop_find_bin_similarities(lua_State* vm) {
#if defined(NTOPNG_PRO)
NtopngLuaContext* ctx = getLuaVMContext(vm);
if (ctx && ctx->bin) {
return (ctx->bin->findSimilarities(vm));
}
#endif
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Returns true if nProbe IPS is configured and active. Lua: ntop.isNProbeIPSConfigured() → boolean */
static int ntop_check_nprobe_ips_configured(lua_State* vm) {
lua_pushboolean(vm,
(ntop->getPrefs()->getZMQPublishEventsURL() ? true : false));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Acquires the global pools write lock (must be paired with poolsUnlock). Lua: ntop.poolsLock() → nil */
static int ntop_pools_lock(lua_State* vm) {
u_int max_lock_duration;
struct timespec wait;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TNUMBER) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
max_lock_duration = lua_tonumber(vm, 1);
if (max_lock_duration > 10) max_lock_duration = 10;
wait.tv_sec = max_lock_duration, wait.tv_nsec = 0;
lua_pushboolean(
vm, ntop->get_pools_lock()->lockTimeout(__FILE__, __LINE__, &wait));
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Releases the global pools write lock acquired by poolsLock. Lua: ntop.poolsUnlock() → nil */
static int ntop_pools_unlock(lua_State* vm) {
ntop->get_pools_lock()->unlock(__FILE__, __LINE__);
lua_pushboolean(vm, true);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Enables or disables debug tracing of C++ new/delete memory allocation calls. Lua: ntop.toggleNewDeleteTrace(enabled) → nil */
static int ntop_toggle_new_delete_trace(lua_State* vm) {
trace_new_delete = !trace_new_delete;
lua_pushboolean(vm, trace_new_delete);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Returns the internal InfluxDB database name used by ntopng. Lua: ntop.getInfluxDBInternalDBName() → string */
static int ntop_get_influxdb_internal_db_name(lua_State* vm) {
lua_pushstring(vm, ntop->getPrefs()->get_influx_internal_db_name());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Sets the internal InfluxDB database name used by ntopng. Lua: ntop.setInfluxDBInternalDBName(name) → nil */
static int ntop_set_influxdb_internal_db_name(lua_State* vm) {
char* influx_internal_db;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
influx_internal_db = (char*)lua_tostring(vm, 1);
if (influx_internal_db && influx_internal_db[0] != '\0') {
ntop->getPrefs()->set_influx_internal_db_name(influx_internal_db);
}
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Returns true if the internal InfluxDB instance is ready and available. Lua: ntop.isInfluxDBInternalAvailable() → boolean */
static int ntop_get_influxdb_internal_available(lua_State* vm) {
lua_pushboolean(vm, ntop->getPrefs()->get_influx_internal_available());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Sets the availability flag for the internal InfluxDB instance. Lua: ntop.setInfluxDBInternalAvailable(available) → nil */
static int ntop_set_influxdb_internal_available(lua_State* vm) {
bool influx_internal_db_available;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TBOOLEAN) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
influx_internal_db_available = (bool)lua_toboolean(vm, 1);
ntop->getPrefs()->set_influx_internal_available(influx_internal_db_available);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Returns the capacity limits imposed by the current license (max hosts, flows, etc.). Lua: ntop.getLicenseLimits() → table */
static int ntop_get_license_limits(lua_State* vm) {
u_int32_t num_hosts = 0, num_local_hosts = 0, num_flows = 0;
for (int i = 0; i < ntop->get_num_interfaces(); i++) {
NetworkInterface* curr_iface = ntop->getInterface(i);
if (curr_iface) {
u_int32_t hosts = curr_iface->getNumHosts();
u_int32_t local_hosts = curr_iface->getNumLocalHosts();
u_int32_t rxonly_local_hosts = curr_iface->getNumLocalRxOnlyHosts();
if (local_hosts >= rxonly_local_hosts) // Safety check
local_hosts -=
rxonly_local_hosts; // Do not consider non-existing hosts
if (!curr_iface->isView()) num_flows += curr_iface->getNumFlows();
num_hosts += hosts;
num_local_hosts += local_hosts;
}
}
lua_newtable(vm);
lua_newtable(vm);
lua_push_uint32_table_entry(vm, "num_flow_exporters",
ntop->getNumFlowExporters());
lua_push_uint32_table_entry(vm, "num_flow_exporter_interfaces",
ntop->getNumFlowExportersInterfaces());
lua_push_uint32_table_entry(vm, "num_host_pools", ntop->getNumberHostPools());
lua_push_uint32_table_entry(vm, "num_pool_members",
ntop->getNumberHostPoolsMembers());
lua_push_uint32_table_entry(vm, "num_profiles", ntop->getNumberProfiles());
lua_push_uint32_table_entry(vm, "num_hosts", num_hosts);
lua_push_uint32_table_entry(vm, "num_local_hosts", num_local_hosts);
lua_push_uint32_table_entry(vm, "num_flows", num_flows);
lua_pushstring(vm, "current");
lua_insert(vm, -2);
lua_settable(vm, -3);
lua_newtable(vm);
#ifdef NTOPNG_PRO
lua_push_uint32_table_entry(vm, "num_flow_exporters",
get_max_num_flow_exporters());
lua_push_uint32_table_entry(vm, "num_flow_exporter_interfaces",
get_max_num_flow_exporters_interfaces());
lua_push_uint32_table_entry(vm, "num_profiles", MAX_NUM_PROFILES);
#endif
lua_push_uint32_table_entry(vm, "num_host_pools", MAX_NUM_HOST_POOLS);
lua_push_uint32_table_entry(vm, "num_pool_members", MAX_NUM_POOL_MEMBERS);
lua_push_uint32_table_entry(vm, "num_hosts", 0 /* no limit */);
lua_push_uint32_table_entry(vm, "num_local_hosts", MAX_NUM_ACTIVE_HOSTS);
lua_push_uint32_table_entry(vm, "num_flows", MAX_NUM_ACTIVE_FLOWS);
lua_pushstring(vm, "max");
lua_insert(vm, -2);
lua_settable(vm, -3);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
#if defined(NTOPNG_PRO)
/* **************************************************************** */
/* @brief Publishes a message to the internal message broker topic (Pro only). Lua: ntop.publish(topic, message) → nil */
static int m_broker_publish(lua_State* vm) {
char *topic, *message;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
topic = (char*)lua_tostring(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
message = (char*)lua_tostring(vm, 2);
MessageBroker* message_broker = ntop->getMessageBroker();
if (!message_broker)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (message_broker->publish(topic, message))
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
/* **************************************************************** */
/* @brief Performs a synchronous RPC call via the internal message broker (Pro only). Lua: ntop.rpcCall(topic, request) → string */
static int m_broker_rpc_call(lua_State* vm) {
char *topic, *message, rsp[BROKER_RPC_CALL_MAX_RSP_LEN];
u_int64_t timeout_ms;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
topic = (char*)lua_tostring(vm, 1);
if (ntop_lua_check(vm, __FUNCTION__, 2, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
message = (char*)lua_tostring(vm, 2);
if (ntop_lua_check(vm, __FUNCTION__, 3, LUA_TNUMBER) != CONST_LUA_OK)
timeout_ms = BROKER_RPC_CALL_DEFAULT_TIMEOUT_MS;
else
timeout_ms = (u_int64_t)lua_tonumber(vm, 3);
MessageBroker* message_broker = ntop->getMessageBroker();
if (!message_broker)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (message_broker->rpcCall(topic, message, timeout_ms, (char*)rsp,
BROKER_RPC_CALL_MAX_RSP_LEN)) {
lua_newtable(vm);
lua_push_str_table_entry(vm, "broker_rsp", rsp);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
} else {
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
}
#endif /* defined(NTOPNG_PRO) */
/* **************************************************************** */
/* @brief Queries a Modbus/TCP device for its identification information. Lua: ntop.readModbusDeviceInfo(host, port) → table */
static int read_modbus_device_info(lua_State* vm) {
char* device_ip;
int timeout = 5;
bool rc;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
else
device_ip = (char*)lua_tostring(vm, 1);
if (lua_type(vm, 2) == LUA_TNUMBER) timeout = (u_int16_t)lua_tonumber(vm, 2);
rc = Utils::readModbusDeviceInfo(device_ip, timeout, vm);
if (rc == false) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
} else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Queries an EtherNet/IP device for its identification information. Lua: ntop.readEthernetIPDeviceInfo(host, port) → table */
static int read_ether_ip_device_info(lua_State* vm) {
char* device_ip;
int timeout = 5;
bool rc;
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_PARAM_ERROR));
else
device_ip = (char*)lua_tostring(vm, 1);
if (lua_type(vm, 2) == LUA_TNUMBER) timeout = (u_int16_t)lua_tonumber(vm, 2);
rc = Utils::readEthernetIPDeviceInfo(device_ip, timeout, vm);
if (rc == false) {
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
} else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Reloads server configuration from Redis (DNS, NTP, DHCP server settings). Lua: ntop.reloadServersConfiguration() → nil */
static int reload_servers_configuration(lua_State* vm) {
ntop->getPrefs()->reloadServersConfiguration();
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Reloads custom ASN-to-name mappings from Redis configuration. Lua: ntop.reloadASNConfiguration() → nil */
static int reload_asn_configuration(lua_State* vm) {
ntop->reloadASNConfiguration();
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
#ifdef NTOPNG_PRO
/* @brief Reloads networks policy configuration from Redis (Pro only). Lua: ntop.reloadNetworksPolicyConfiguration() → nil */
static int reload_networks_policy_configuration(lua_State* vm) {
if (ntop->getPrefs()->reloadNetworksPolicyConfiguration()) {
lua_pushboolean(vm, 1);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
lua_pushboolean(vm, 0);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
}
#endif
/* **************************************************************** */
/* @brief Retrieves a value from the in-process Lua cache shared across all VMs. Lua: ntop.getLuaCache(key) → any */
static int ntop_get_lua_cache(lua_State* vm) {
std::string ret;
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
ret = ntop->getLuaCache(std::string((char*)lua_tostring(vm, 1)));
lua_pushstring(vm, ret.c_str());
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Stores a value in the in-process Lua cache with optional TTL seconds. Lua: ntop.setLuaCache(key, value[, ttl_secs]) → nil */
static int ntop_set_lua_cache(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
if (ntop_lua_check(vm, __FUNCTION__, 1, LUA_TSTRING) != CONST_LUA_OK)
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
if (lua_type(vm, 2) == LUA_TSTRING)
ntop->setLuaCache(std::string((char*)lua_tostring(vm, 1)),
std::string((char*)lua_tostring(vm, 2)));
else if (lua_type(vm, 2) == LUA_TNUMBER)
ntop->setLuaCache(std::string((char*)lua_tostring(vm, 1)),
std::to_string(lua_tonumber(vm, 2)));
else
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_ERROR));
lua_pushnil(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
/* @brief Returns all entries in the in-process Lua cache (debug/inspection). Lua: ntop.dumpLuaCache() → table */
static int ntop_dump_lua_cache(lua_State* vm) {
ntop->getTrace()->traceEvent(TRACE_DEBUG, "%s() called", __FUNCTION__);
ntop->dumpLuaCache(vm);
return (ntop_lua_return_value(vm, __FUNCTION__, CONST_LUA_OK));
}
/* **************************************************************** */
static luaL_Reg _ntop_reg[] = {
{"getDirs", ntop_get_dirs},
{"getInfo", ntop_get_info},
{"getUptime", ntop_get_uptime},
{"dumpFile", ntop_dump_file},
{"dumpBinaryFile", ntop_dump_binary_file},
{"checkLicense", ntop_check_license},
{"systemHostStat", ntop_system_host_stat},
{"threadsInfo", ntop_threads_info},
{"getSystemAlertsStats", ntop_get_system_alerts_stats},
{"refreshCPULoad", ntop_refresh_cpu_load},
{"getCookieAttributes", ntop_get_cookie_attributes},
{"isAllowedInterface", ntop_is_allowed_interface},
{"isAllowedNetwork", ntop_is_allowed_network},
{"isLocalInterfaceAddress", ntop_is_local_interface_address},
{"isLocalAddress", ntop_is_local_address},
{"md5", ntop_md5},
{"hasRadiusSupport", ntop_has_radius_support},
{"logRadius", ntop_log_radius},
{"hasLdapSupport", ntop_has_ldap_support},
{"resetStats", ntop_reset_stats},
{"getCurrentScriptsDir", ntop_get_current_scripts_dir},
{"getDropPoolInfo", ntop_get_drop_pool_info},
{"isOffline", ntop_is_offline},
{"isForcedOffline", ntop_is_forced_offline},
{"setOffline", ntop_set_offline},
{"setOnline", ntop_set_online},
{"isShuttingDown", ntop_is_shutting_down},
{"limitResourcesUsage", ntop_limit_resources_usage},
{"getAllPaths", ntop_get_all_paths},
/* Assets Inventory */
{"enableAssetsLog", ntop_enable_assets_log},
{"assetsEnabled", ntop_assets_enabled},
/* Execute commands */
{"execCmd", ntop_exec_cmd},
{"execCmdAsync", ntop_exec_cmd_async},
{"readResultCmdAsync", ntop_read_result_cmd_async},
/* Redis */
{"getCacheStatus", ntop_info_redis},
{"getCache", ntop_get_redis},
{"setCache", ntop_set_redis},
{"setnxCache", ntop_setnx_redis},
{"incrCache", ntop_incr_redis},
{"getCacheStats", ntop_get_redis_stats},
{"delCache", ntop_delete_redis_key},
{"renameCache", ntop_rename_redis_key},
{"flushCache", ntop_flush_redis},
{"listIndexCache", ntop_list_index_redis},
{"lpushCache", ntop_lpush_redis},
{"rpushCache", ntop_rpush_redis},
{"lpopCache", ntop_lpop_redis},
{"rpopCache", ntop_rpop_redis},
{"lremCache", ntop_lrem_redis},
{"ltrimCache", ntop_ltrim_redis},
{"lrangeCache", ntop_lrange_redis},
{"llenCache", ntop_llen_redis},
{"setMembersCache", ntop_add_set_member_redis},
{"delMembersCache", ntop_del_set_member_redis},
{"getMembersCache", ntop_get_set_members_redis},
{"getHashCache", ntop_get_hash_redis},
{"setHashCache", ntop_set_hash_redis},
{"delHashCache", ntop_delete_hash_redis_key},
{"getHashKeysCache", ntop_get_hash_keys_redis},
{"getHashAllCache", ntop_get_hash_all_redis},
{"getKeysCache", ntop_get_keys_redis},
{"hasDumpCache", ntop_redis_has_dump},
{"dumpCache", ntop_redis_dump},
{"restoreCache", ntop_redis_restore},
{"addLocalNetwork", ntop_add_local_network},
{"setResolvedAddress", ntop_set_resolved_address},
/* Redis Preferences */
{"setPref", ntop_set_preference},
{"getPref", ntop_get_redis},
{"isdir", ntop_is_dir},
{"mkdir", ntop_mkdir_tree},
{"notEmptyFile", ntop_is_not_empty_file},
{"exists", ntop_get_file_dir_exists},
{"listReports", ntop_list_reports},
{"fileLastChange", ntop_get_file_last_change},
{"readdir", ntop_list_dir_files},
{"rmdir", ntop_remove_dir_recursively},
{"unlink", ntop_unlink_file},
{"isNProbeIPSConfigured", ntop_check_nprobe_ips_configured},
#ifndef HAVE_NEDGE
#ifdef HAVE_ZMQ
{"zmq_connect", ntop_zmq_connect},
{"zmq_disconnect", ntop_zmq_disconnect},
{"zmq_receive", ntop_zmq_receive},
#endif
/* IPS */
{"broadcastIPSMessage", ntop_brodcast_ips_message},
{"timeToRefreshIPSRules", ntop_time_to_refresh_ips_rules},
{"askToRefreshIPSRules", ntop_ask_to_refresh_ips_rules},
#endif
{"reloadPreferences", ntop_reload_preferences},
{"setDefaultFilePermissions", ntop_set_default_file_permissions},
#ifdef NTOPNG_PRO
#ifndef HAVE_NEDGE
{"checkSubInterfaceSyntax", ntop_check_sub_interface_syntax},
{"reloadProfiles", ntop_reload_traffic_profiles},
#endif
{"checkFilterSyntax", ntop_check_filter_syntax},
#endif
{"isForcedCommunity", ntop_is_forced_community},
{"isPro", ntop_is_pro},
{"isEnterprise", ntop_is_enterprise_m},
{"isEnterpriseM", ntop_is_enterprise_m},
{"isEnterpriseL", ntop_is_enterprise_l},
{"isEnterpriseXL", ntop_is_enterprise_xl},
{"isEnterpriseXXL", ntop_is_enterprise_xxl},
{"isnEdge", ntop_is_nedge},
{"isnEdgeEnterprise", ntop_is_nedge_enterprise},
{"isPackage", ntop_is_package},
{"isAppliance", ntop_is_appliance},
{"isIoTBridge", ntop_is_iot_bridge},
/* Historical database */
{"insertMinuteSampling", ntop_stats_insert_minute_sampling},
{"insertHourSampling", ntop_stats_insert_hour_sampling},
{"insertDaySampling", ntop_stats_insert_day_sampling},
{"getMinuteSampling", ntop_stats_get_minute_sampling},
{"deleteMinuteStatsOlderThan", ntop_stats_delete_minute_older_than},
{"deleteHourStatsOlderThan", ntop_stats_delete_hour_older_than},
{"deleteDayStatsOlderThan", ntop_stats_delete_day_older_than},
{"getMinuteSamplingsFromEpoch",
ntop_stats_get_samplings_of_minutes_from_epoch},
{"getHourSamplingsFromEpoch", ntop_stats_get_samplings_of_hours_from_epoch},
{"getDaySamplingsFromEpoch", ntop_stats_get_samplings_of_days_from_epoch},
{"getMinuteSamplingsInterval", ntop_stats_get_minute_samplings_interval},
{"deleteOldRRDs", ntop_delete_old_rrd_files},
/* Time */
{"gettimemsec", ntop_gettimemsec},
{"tzset", ntop_tzset},
{"roundTime", ntop_round_time},
/* Ticks */
{"getticks", ntop_getticks},
{"gettickspersec", ntop_gettickspersec},
/* UDP */
{"send_udp_data", ntop_send_udp_data},
/* TCP */
{"send_tcp_data", ntop_send_tcp_data},
/* IP */
{"ipToNumber", ntop_ip_to_number},
{"inet_ntoa", ntop_inet_ntoa},
{"networkPrefix", ntop_network_prefix},
/* RRD */
{"rrd_create", ntop_rrd_create},
{"rrd_update", ntop_rrd_update},
{"rrd_fetch", ntop_rrd_fetch},
{"rrd_fetch_columns", ntop_rrd_fetch_columns},
{"rrd_lastupdate", ntop_rrd_lastupdate},
{"rrd_tune", ntop_rrd_tune},
{"rrd_inc_num_drops", ntop_rrd_inc_num_drops},
/* Prefs */
{"getPrefs", ntop_get_prefs},
/* Ping */
{"isPingAvailable", ntop_is_ping_available},
{"isPingIfaceAvailable", ntop_is_ping_iface_available},
{"pingHost", ntop_ping_host},
{"collectPingResults", ntop_collect_ping_results},
{"getPingIfNames", ntop_get_ping_interface_names},
/* HTTP utils */
{"httpRedirect", ntop_http_redirect},
{"getHttpPrefix", ntop_http_get_prefix},
{"getStartupEpoch", ntop_http_get_startup_epoch},
{"getStaticFileEpoch", ntop_http_get_static_file_epoch},
{"httpPurifyParam", ntop_http_purify_param},
/* Admin */
{"getNologinUser", ntop_get_nologin_username},
{"getUsers", ntop_get_users},
{"isAdministrator", ntop_is_administrator},
{"isPcapDownloadAllowed", ntop_is_pcap_download_allowed},
{"getAllowedNetworks", ntop_get_allowed_networks},
{"resetUserPassword", ntop_reset_user_password},
{"changeUserRole", ntop_change_user_role},
{"changeAllowedNets", ntop_change_allowed_nets},
{"changeAllowedIfname", ntop_change_allowed_ifname},
{"changeUserHostPool", ntop_change_user_host_pool},
{"changeAllowedHostPools", ntop_change_user_allowed_host_pools},
{"getAllowedHostPools", ntop_get_allowed_host_pools},
{"changeUserFullName", ntop_change_user_full_name},
{"changeUserLanguage", ntop_change_user_language},
{"changePcapDownloadPermission", ntop_change_user_pcap_download_permission},
{"changeHistoricalFlowPermission",
ntop_change_user_historical_flow_permission},
{"changeAlertsPermission", ntop_change_user_alerts_permission},
{"addUser", ntop_add_user},
{"deleteUser", ntop_delete_user},
{"createUserSession", ntop_create_user_session},
{"createUserAPIToken", ntop_create_user_api_token},
{"getUserAPIToken", ntop_get_user_api_token},
{"isLoginDisabled", ntop_is_login_disabled},
{"isLoginBlacklisted", ntop_is_login_blacklisted},
/* MFA/TOTP */
{"generateTOTPSecret", ntop_generate_totp_secret},
{"setUserTOTPSecret", ntop_set_user_totp_secret},
{"getUserTOTPSecret", ntop_get_user_totp_secret},
{"isTOTPEnabled", ntop_is_totp_enabled},
{"setUserTOTPEnabled", ntop_set_user_totp_enabled},
{"validateTOTP", ntop_validate_totp},
{"getTOTPProvisioningUri", ntop_get_totp_provisioning_uri},
{"getNetworkNameById", ntop_network_name_by_id},
{"getNetworkIdByName", ntop_network_id_by_name},
{"getNetworks", ntop_get_networks},
{"getAddressNetwork", ntop_get_address_network},
{"isGuiAccessRestricted", ntop_is_gui_access_restricted},
{"serviceRestart", ntop_service_restart},
{"getUserObservationPointId", ntop_get_user_observation_point_id},
{"updateRadiusLoginInfo", ntop_update_radius_login_info},
/* Security */
{"getRandomCSRFValue", ntop_get_csrf_value},
/* HTTP */
{"httpGet", ntop_http_get},
{"httpGetAuthToken", ntop_http_get_auth_token},
{"httpPost", ntop_http_post},
{"httpPostAuthToken", ntop_http_post_auth_token},
{"httpPutAuthToken", ntop_http_put_auth_token},
{"httpPatchAuthToken", ntop_http_patch_auth_token},
{"httpFetch", ntop_http_fetch},
{"postHTTPJsonData", ntop_post_http_json_data},
{"postHTTPTextFile", ntop_post_http_text_file},
#ifdef HAVE_CURL_SMTP
/* SMTP */
{"sendMail", ntop_send_mail},
#endif
/* Address Resolution */
{"resolveName",
ntop_resolve_address}, /* Note: you should use resolveAddress() to call
from Lua */
{"getResolvedName",
ntop_get_resolved_address}, /* Note: you should use getResolvedAddress() to
call from Lua */
{"resolveHost", ntop_resolve_host},
/* Logging */
#ifndef WIN32
{"syslog", ntop_syslog},
#endif
{"setLoggingLevel", ntop_set_logging_level},
{"traceEvent", ntop_trace_event},
{"verboseTrace", ntop_verbose_trace},
/* SNMP */
{"snmpSetFatMibPollingMode", ntop_snmp_set_fat_mib_polling_mode},
{"snmpv3available", ntop_is_libsnmp_available},
{"snmpsetavailable", ntop_is_libsnmp_available},
{"snmpgetbulkavailable", ntop_is_libsnmp_available},
{"snmpMaxNumEngines", ntop_snmp_max_num_engines},
{"snmpSetBulkMaxNumRepetitions", ntop_snmp_set_bulk_max_repetitions},
{"snmpToggleTrapCollection", ntop_snmp_toggle_trap_collection},
/* Synchronous */
{"snmpget", ntop_snmpget},
{"snmpgetnext", ntop_snmpgetnext},
{"snmpgetnextbulk", ntop_snmpgetnextbulk},
{"snmpset", ntop_snmpset},
/* Asynchronous */
{"snmpallocasnyncengine", ntop_allocasnyncengine},
{"snmpfreeasnycengine", ntop_freeasnyncengine},
{"snmpgetasync", ntop_snmpgetasync},
{"snmpgetnextasync", ntop_snmpgetnextasync},
{"snmpgetnextbulkasync", ntop_snmpgetnextbulkasync},
{"snmpreadasyncrsp", ntop_snmpreadasyncrsp},
/* Batch */
{"snmpGetBatch", ntop_snmp_batch_get}, /* v1/v2c/v3 */
{"snmpReadResponses", ntop_snmp_read_responses},
#if defined(NTOPNG_PRO)
/* SNMP Interfaces */
{"snmpSetInterfaceRole", ntop_snmp_set_interface_role},
{"activateSnmpInterfaceRoles", ntop_activate_snmp_interface_roles},
#endif
/* Runtime */
{"hasGeoIP", ntop_has_geoip},
{"isWindows", ntop_is_windows},
{"isFreeBSD", ntop_is_freebsd},
{"isLinux", ntop_is_linux},
{"elasticsearchConnection", ntop_elasticsearch_connection},
{"getInstanceName", ntop_get_instance_name},
/* Custom Categories, Malicious fingerprints
* Note: only inteded to be called from housekeeping.lua */
{"initnDPIReload", ntop_initnDPIReload},
{"finalizenDPIReload", ntop_finalizenDPIReload},
{"loadCustomCategoryIp", ntop_loadCustomCategoryIp},
{"loadCustomCategoryHost", ntop_loadCustomCategoryHost},
{"loadCustomCategoryFile", ntop_loadCustomCategoryFile},
{"setDomainMask", ntop_setDomainMask},
{"addTrustedIssuerDN", ntop_addTrustedIssuerDN},
/* Privileges */
{"gainWriteCapabilities", ntop_gainWriteCapabilities},
{"dropWriteCapabilities", ntop_dropWriteCapabilities},
/* Misc */
{"getservbyport", ntop_getservbyport},
{"msleep", ntop_msleep},
{"tcpProbe", ntop_tcp_probe},
{"getMacManufacturer", ntop_get_mac_manufacturer},
{"getHostInformation", ntop_get_host_information},
{"isShuttingDown", ntop_is_shuttingdown},
{"listInterfaces", ntop_list_interfaces},
{"ipCmp", ntop_ip_cmp},
{"matchCustomCategory", ntop_match_custom_category},
{"getTLSVersionName", ntop_get_tls_version_name},
{"isIPv6", ntop_is_ipv6},
{"getMac64", ntop_get_mac_64},
{"decodeMac64", ntop_decode_mac_64},
{"reloadFlowChecks", ntop_reload_flow_checks},
{"reloadHostChecks", ntop_reload_host_checks},
{"reloadAlertExclusions", ntop_reload_alert_exclusions},
{"getFlowChecksStats", ntop_get_flow_checks_stats},
{"getFlowAlertScore", ntop_get_flow_alert_score},
{"getFlowAlertRisk", ntop_get_flow_alert_risk},
{"getFlowRiskAlerts", ntop_get_flow_risk_alerts},
{"getFlowCheckInfo", ntop_get_flow_check_info},
{"getHostCheckInfo", ntop_get_host_check_info},
{"shouldResolveHost", ntop_should_resolve_host},
{"setIEC104AllowedTypeIDs", ntop_set_iec104_allowed_typeids},
{"isFlowDedupEnabled", ntop_is_flow_deduplication_enabled},
#ifdef NTOPNG_PRO
{"setModbusAllowedFunctionCodes", ntop_set_modbus_allowed_function_codes},
#endif
{"getLocalNetworkAlias", ntop_check_local_network_alias},
{"getLocalNetworkID", ntop_get_local_network_id},
{"getRiskStr", ntop_get_risk_str},
{"getRiskList", ntop_get_risk_list},
{"checkNetworkPolicy", ntop_check_network_policy},
/* ASN */
{"getASName", ntop_get_asn_name},
{"getASNameFromASN", ntop_get_as_name_from_asn},
{"getHostGeolocation", ntop_get_host_geolocation},
/* Mac */
{"setMacDeviceType", ntop_set_mac_device_type},
/* Host pools */
{"reloadHostPools", ntop_reload_host_pools},
/* Device Protocols */
{"reloadDeviceProtocols", ntop_reload_device_protocols},
/* Traffic Recording/Extraction */
{"runExtraction", ntop_run_extraction},
{"stopExtraction", ntop_stop_extraction},
{"isExtractionRunning", ntop_is_extraction_running},
{"getExtractionStatus", ntop_get_extraction_status},
{"runLiveExtraction", ntop_run_live_extraction},
/* Bitmap functions */
{"bitmapIsSet", ntop_bitmap_is_set},
{"bitmapSet", ntop_bitmap_set},
{"bitmapClear", ntop_bitmap_clear},
/* Score */
{"mapScoreToSeverity", ntop_map_score_to_severity},
{"mapSeverityToScore", ntop_map_severity_to_score},
/* Alerts */
{"alert_store_query", ntop_alert_store_query},
/* Alerts queues */
{"popInternalAlerts", ntop_pop_internal_alerts},
/* Recipient queues */
{"recipient_enqueue", ntop_recipient_enqueue},
{"recipient_dequeue", ntop_recipient_dequeue},
{"recipient_stats", ntop_recipient_stats},
{"recipient_inc_stats", ntop_recipient_inc_stats},
{"recipient_last_use", ntop_recipient_last_use},
{"recipient_delete", ntop_recipient_delete},
{"recipient_register", ntop_recipient_register},
/* nDPI */
{"getnDPIProtoCategory", ntop_get_ndpi_protocol_category},
{"setnDPIProtoCategory", ntop_set_ndpi_protocol_category},
{"isCustomApplication", ndpi_is_custom_application},
/* nEdge */
#ifdef HAVE_NEDGE
{"setHTTPBindAddr", ntop_set_http_bind_addr},
{"setHTTPSBindAddr", ntop_set_https_bind_addr},
{"setRoutingMode", ntop_set_routing_mode},
{"isRoutingMode", ntop_is_routing_mode},
{"addLanInterface", ntop_add_lan_interface},
{"addWanInterface", ntop_add_wan_interface},
{"refreshDeviceProtocolsPoliciesConf",
ntop_refresh_device_protocols_policies_pref},
#endif
/* Appliance */
{"overrideInterface", ntop_override_interface},
/* nEdge and Appliance */
{"shutdown", ntop_shutdown},
/* Periodic scripts (ThreadedActivity.cpp) */
{"isDeadlineApproaching", ntop_script_is_deadline_approaching},
{"getDeadline", ntop_script_get_deadline},
/* Speedtest */
{"hasSpeedtestSupport", ntop_has_speedtest_support},
{"speedtest", ntop_speedtest},
/* Blacklists */
{"getBlacklistStats", ntop_get_bl_stats},
{"resetBlacklistStats", ntop_reset_bl_stats},
/* ClickHouse */
{"isClickHouseEnabled", ntop_clickhouse_enabled},
/* Data Binning */
{"addBin", ntop_add_bin},
{"findSimilarities", ntop_find_bin_similarities},
/* Pools Lock/Unlock */
{"poolsLock", ntop_pools_lock},
{"poolsUnlock", ntop_pools_unlock},
/* Register Runtime Interface (PCAP or DB) */
{"registerRuntimeInterface", ntop_register_runtime_interface},
#if defined(NTOPNG_PRO) && defined(HAVE_KAFKA)
/* Kafka */
{"sendKafkaMessage", ntop_send_kafka_message},
#endif
/* Debug */
{"toggleNewDeleteTrace", ntop_toggle_new_delete_trace},
/* License */
{"getLicenseLimits", ntop_get_license_limits},
/* InfluxDB */
{"getInfluxDBInternalDBName", ntop_get_influxdb_internal_db_name},
{"setInfluxDBInternalDBName", ntop_set_influxdb_internal_db_name},
{"isInfluxDBInternalAvailable", ntop_get_influxdb_internal_available},
{"setInfluxDBInternalAvailable", ntop_set_influxdb_internal_available},
#if defined(NTOPNG_PRO)
/* TODO: move to message_broker engine */
{"publish", m_broker_publish},
{"rpcCall", m_broker_rpc_call},
#endif
/* Modbus */
{"readModbusDeviceInfo", read_modbus_device_info},
{"readEthernetIPDeviceInfo", read_ether_ip_device_info},
{"reloadServersConfiguration", reload_servers_configuration},
{"reloadASNConfiguration", reload_asn_configuration},
#if defined(NTOPNG_PRO)
{"reloadNetworksPolicyConfiguration", reload_networks_policy_configuration},
#endif
/* In Memory cache */
{"getLuaCache", ntop_get_lua_cache},
{"setLuaCache", ntop_set_lua_cache},
{"dumpLuaCache", ntop_dump_lua_cache},
{NULL, NULL}};
luaL_Reg* ntop_reg = _ntop_reg;