Save at most MAX_NUM_ASSET_SERVER_PORTS (128) server ports per L4
protocol of a local host, keeping the lowest ports, in the server ports
bitmap saved to redis and in the asset info. A warning (once per host)
reports the number of ports and the host IP when the limit is exceeded.
A host whose Operating System is known is now tagged with it, with one
of five new built-in tags: Windows, macOS/iOS/iPadOS, Android, Linux and
FreeBSD (tags 31 to 27). As the other tags they are shown as badges, can
be used as filters and, on the assets, can have a TTL.
Unlike the other tags, a host (and its asset) has at most one of them:
when a different OS is detected the new tag replaces the previous one.
With a TTL, the tag is removed from the asset when the OS is not
observed again in time; the OS reported for the asset is not changed.
The assets already in the inventory are tagged, at the first start, with
the OS they are stored with.
Implementation:
* The tag is not stored in the host: it is computed from its OS, as the
tags of the services are, so there is one at most and it always
matches the OS the host reports. It is not transferred to the flows.
* When the OS of a host is set or changes, the new tag is reported to
the asset as refreshed and the previous one as removed; when the same
OS is observed again the tag is refreshed, for the TTL.
* What refreshes the tag: TCP fingerprint / nDPI hint (once per TCP
flow), OS hint from nProbe, HTTP User-Agent (when it tells the OS the
host has; when it tells another one it is ignored, as before), network
discovery. DHCP sets the OS.
* The asset side (one OS tag per asset, "replaced" as reason of the
removal, tagging of the existing assets) is in the pro repository:
without it an OS change is logged as a tag removed by the user.
View interfaces behave the same.
User documentation (tags page) and developer documentation updated.
With a view interface, a host could be marked with a service or a tag
that belongs to its peer. The visible case is DNS: a DNS client was
marked as a DNS server (host service "DNS", "DNS Server" tag, and from
there the matching asset) when the first packet seen on its flow is a
reply, i.e. when the query has not been captured (capture started in the
middle of the exchange, packet lost, asymmetric traffic).
When the first packet of a flow is sent by the server, the flow is
recorded "reversed" (the server looks like the client) and a swap of its
peers is requested. Until the swap is performed, the services and the
tags have to be set on the peers as they will be after the swap.
On a regular interface this is what happens, as the hosts of the flow
are taken honouring the swap request. The flows of a viewed interface
have no hosts: services and tags are stored in the IP addresses of the
flow and moved to the hosts of the view later on. There the swap request
was ignored, so they ended up on the other peer.
Fix: take the IP addresses of the flow honouring the swap request, exactly as
it is done with the hosts, when a service or a tag is set on a peer of a
flow with no hosts.
Impact:
* View interfaces only. Nothing changes on the other interfaces, where
flows have hosts.
* Only flows with a pending swap request, that is flows seen "reversed":
they are uncommon. With DNS it takes a flow starting with a reply.
* It applies to all the services and tags set on the peers of a flow,
not only to DNS, as the change is in the common code. Only the DNS
case has been tested.
* This is unrelated to the DNS replies with no records fixed in #11079:
that issue never showed up on view interfaces.
On a view interface the Operating System of a host was most of the times
not learnt from the TCP fingerprint (nor from the OS hint of nDPI/nProbe)
of its flows.
The flows of a viewed interface have no hosts. The host of the view is
bound to a flow the first time the view walks it, later on, whereas the
OS is passed to the host just once, when the protocol of the flow is
detected: if the view has not walked the flow yet (the common case, as
detection takes a few packets), there is no host and the OS is dropped.
It was working only for the flows whose detection ends after the first
pass of the view.
Fix:
* A viewed flow keeps the OS of its client (from TCP fingerprint and
from the OS hint), and the view sets it on its host when it walks the
flow, once per flow.
* A view does not walk its flows in time order: the host keeps the time
of the flow its OS hint comes from, and a hint from an older flow is
ignored. This rule is applied on all interfaces.
Test: a pcap where the same host opens a TCP connection with the fingerprint
of Windows and, later, one with the fingerprint of Linux and a Windows
User-Agent
* Without a view: Linux, learnt via TCP fingerprint (before
and after).
* With a view: Windows via User-Agent before, Linux via TCP
fingerprint now.
This commit needs the matching one in the pro repository
(the call in the walker of the view).
Issue
-----
A user-defined tag bound to an application or to a flow risk is set on
the client of a flow once, when the protocol of the flow is detected:
that is the only time the flow refreshes the tag. When the tag has a
TTL, it expires on the asset if it is not refreshed.
So, with a flow living longer than the TTL of the tag (e.g. an agent
keeping one connection open for days), the tag was removed from the
asset while the traffic it comes from was still there, and it came back
only with the next flow of that kind. The host kept the tag in the
meantime.
This happened on regular interfaces only. On view interfaces the tags of
a flow are copied to the host of the view at every pass on the flows, so
they are refreshed for as long as the flow is alive.
Fix
---
On regular interfaces, once per tags refresh interval (6 hours; 1 minute
in test mode), a flow marks as refreshed on its client its own
user-defined tags that have a TTL. This is done in the periodic update
of the flow, when the current update and the previous one are not in the
same interval, so no per-flow timestamp is needed.
Impact
------
* Only the user-defined tags set by the flows (application/risk based)
that have a TTL. Nothing is done when no tag has a TTL.
* The built-in tags are not refreshed this way: regular and view
interfaces still differ for those set before the end of a flow (Non-PQC
Compliant, DHCP Server). On all interfaces, a service set at the end of
a flow (DNS, HTTP, SSH, ...) is not refreshed before the flow ends.
* Tags assigned by hand are not involved: no flow sets them.
* View interfaces are not changed.
Issue
-----
A host that only sends DNS queries could be marked as a DNS server (host
service "DNS", "DNS Server" tag, and from there the matching asset),
while it is just a client.
It happens when the only reply seen on a DNS flow carries no records at
all, i.e. zero records in the answer, authority and additional sections
(e.g. NXDomain, ServFail or an empty NOERROR reply, without SOA and
without EDNS). nDPI keeps waiting for a reply with some records, so the
dissection of the flow is not completed by a packet: it is ended later
on by ntopng, when the flow is idle/deleted or after a few seconds.
To detect the flows that are seen "reversed" (the first packet is a
reply), the DNS swap check compares the type (query/reply) of the last
dissected DNS packet with a packet direction. When the dissection is
ended without a packet, that direction is a fixed value and not the
direction of the packet the type refers to: the last dissected packet is
a reply, in the server to client direction, and it was handled as if it
were sent by the client. A swap of the flow peers was then wrongly
requested, and the DNS service ended up on the client instead of on the
server.
Fix
---
Store the direction of the last DNS packet that has been dissected, and
use it in the swap check instead of the direction received as parameter.
Impact
------
* Packet interfaces only, both live capture and pcap files. Flows
collected from probes (ZMQ) are not affected: the swap check is not
performed there.
* View interfaces are not affected, neither before nor after this
change: there the service is assigned to the server address of the
flow, regardless of the swap request.
* Replies with at least one record in any section (the vast majority,
as NXDomain/NODATA replies usually carry a SOA record and/or an EDNS
OPT record) were already handled properly, and they still are.
* Besides the wrong tag on the client, the real DNS server was not
marked (or refreshed) by these flows.
Memory
------
The new field does not increase the memory used by a flow: it takes one
of the 4 padding bytes at the end of the DNS information, which is still
48 bytes; the union of the per-protocol information is still 72 bytes
and sizeof(Flow) is still 1752 bytes (x86_64).
Each tag can now have a TTL, in days: a tag is removed from an asset when
nothing has confirmed it for longer than its TTL. With a TTL of 0 (the
default) the tag never expires, as before.
Example: a host answering DNS queries gets the "DNS Server" tag; with a
TTL of 30 days the tag is removed from the asset when no DNS traffic has
been seen for 30 days. A tag is refreshed every time it is observed
(service seen again, Non-PQC flow, application/flow risk bound to the
tag) or assigned by hand. Tags coming from the configured server lists
(DNS, NTP, DHCP...) never expire for the listed addresses. The TTL applies
to all the 64 tags. Deleting a user-defined tag removes it from the
assets.
The expiration of the tags requires Enterprise L (or above): without it
the tags of an asset are the tags of its host, as before.
Implementation overview (ntopng and pro repositories):
- The asset owns its tags: for each tag it holds, an asset stores when
the tag was set, when it was last refreshed and where it comes from
(observed in the traffic, set by hand, configuration).
- A host no longer tells what its tags are, but what happened to them
since its last asset dump.
- LocalHost has three more bitmaps: tags observed (refreshed), tags set
by hand (assigned), tags unset by hand (removed). A tag or a service
is recorded as refreshed every time it is observed, also when the host
already has it.
- A host with pending refreshes of tags with a TTL is dumped to the
assets (i.e. written to the Redis queue) every
CONST_ASSETS_TAGS_REFRESH_INTERVAL (6 hours) even when nothing else
changes. New tags are dumped "immediately" (as before). When no tag
has a TTL there are no extra dumps.
- [Pro part] The existing 1-minute Lua callback drains the queue and
writes to the DB (SQLite or ClickHouse), applying the changes to the
tags of the stored asset.
- [Pro part] The same callback, every 6 hours, checks the DB for expired
tags and updates the assets. A tag expires when it has not been
refreshed for longer than its TTL plus 6 hours (the time a host can
take to tell about a refresh). The tags a host has because of the
configured server lists are skipped.
- [Pro part] A user-defined tag removed from an asset, because expired
or deleted, is removed from the host too.
- [Pro part] View interfaces: the tags of the viewed flows are refreshed
on the hosts of the view at every pass of the flows walker.
- Without Enterprise L the host dumps only its current tags, that are
copied to the asset as before, and nothing expires.
- Test mode (Redis key ntopng.prefs.tags_ttl_test_mode, read at
startup): TTL in minutes and one-minute intervals.
See doc/developers/README.asset_tags_ttl.md for the design, the test
mode, what has been verified and the known limitations.
User documentation (Tags page): new "Asset Tag Expiration (TTL)" section,
the UnsafeMail example extended with a TTL of 7 days, SSH and RDP servers
that can be set by the Network Configuration, new screenshot of the tag
edit dialog.
Host::addTag(tag_idx) now handles any tag:
- bits 0-31 (ntop-reserved) are set in computed_tags_bitmap: they are
computed at runtime and are not persisted. The asset is marked as
updated so that the new tag is dumped to the Assets Inventory.
- bits 32-63 are user-defined tags, set with Host::addUserTags.
Host::isTagSet(tag_idx) is the matching check.
Flow::setCliTag/setSrvTag use them in place of isUserTagSet/addUserTags,
that silently discarded the reserved tags: as a side effect, flow risks
bound to a built-in tag are now effective.
The Non-PQC tag is still a computed tag: it is not stored in Redis and it
is learnt again from the traffic when the host is created again.
Note: with collected flows (ZMQ) the tag is set only when the exporter
provides both the flow risk and the flow risk info.
Host::setUserTags now replaces the user-defined tags instead of OR-ing
them, so that tags unset from the host configuration page are removed
from online hosts too. Add Host::addUserTags for the tags set
automatically from flows.
when used in view interfaces with no lock around it.
When two threads both run array_container_grow() on the same container,
they realloc the same block twice or write past the new size. This was
the issue.
A viewed interface never allocates its own hosts_hash (Host tracking is
centralized on the owning ViewInterface, to avoid duplicate Host objects
across sub-interfaces), so `cli_host`/`srv_host` always came back NULL from
Flow::get_actual_peers() for flows on such interfaces - `Flow::postDetectionCallback()`
silently skipped tagging entirely, even though the real Host object existed
and was local.
Mirror the existing `services_bitmap` mechanism already used for this same
case: `Flow::setCliTag()`/`setSrvTag()` set the tag on the resolved Host
when one exists, otherwise stash it on the flow's own `IpAddress` (new
`IpAddress::tags_bitmap`/`setTag()`/`providesTag()`).
`ViewInterface::viewed_flows_walker()` then promotes any pending IP-level
tags onto the real, persistent Host object once it resolves one, exactly
like it already does for services.
`Ntop::checkShutdownWhenDone()` ran the e2e runtime/post test scripts as soon as
`recipients_are_empty()`, which is only one stage of the flow/host alert
pipeline:
checks -> `flowAlertsQueue/hostAlertsQueue` (per-interface)
-> `flowAlertsDequeueLoop`/`hostAlertsDequeueLoop` -> recipients FIFO
-> `recipients.process_notifications` (Lua) -> alert store
Right after a pcap file finishes, flow-end checks have just pushed a whole
batch of alerts into the per-interface queues, which the dequeue loops haven't
moved into the recipients yet - `recipients_are_empty()` is transiently true, so
the runtime script fired before most alerts were persisted.
- `SPSCQueue`: add `isEmpty()` (and constify `isNotEmpty()`).
- `NetworkInterface::alertsQueuesDrained()`: true when the per-interface flow and
host alert queues are both empty.
- `Ntop::alerts_pipeline_drained()`: `alertsQueuesDrained()` on every interface,
plus the internal C->Lua alerts queue, plus `recipients_are_empty()`.
- `checkShutdownWhenDone()`'s guard and `waitRecipientsQueuesDrained()` now poll
`alerts_pipeline_drained()` instead of `recipients_are_empty()` alone, requiring
two consecutive drained reads before running the runtime/post scripts.
- `src/NetworkInterface.cpp`: `sortHosts()` and `sortMacs()` stored a pointer to
a local stack variable (`macAddr`, `map_search_lc`) into the caller-owned
`flowHostRetriever` struct via `retriever->mac` / `retriever->map_search`.
Both buffers went out of scope as soon as the function returned, leaving
retriever with a dangling pointer. This wasn't triggering an active bug
today because `walker()` consumes those fields synchronously before
return and nothing reads them afterwards, but it was fragile UB waiting
for the calling pattern to change. Fixed by backing `mac/map_search` with
fixed-size buffers owned by the flowHostRetriever struct itself
(`mac_buf[6]`, `map_search_buf[128]`), so the pointers stay valid for as
long as the struct does.
- `include/Ntop.h`: removed the `Ntop::elastic_search` and
`Ntop::syslog` members. Verified they are never assigned or read
anywhere in the code.
- `Makefile.in`: added --suppress=uninitMemberVar to CPPCHECK_SUPPRESS.
This was the noisiest category (~25 of ~40 non-third-party findings).
Spot-checked several instances (`Prefs::ntop`, `HostPoolStats::totalStats`,
NetworkInterface's pMap/sMap/acl_flow/alertsQueue) and confirmed they
are false positives - the members are in fact set inside very large,
heavily #ifdef'd constructors, which cppcheck's flow analysis loses
track of (also seen with the `new (std::nothrow) T()` idiom). The
remainder reflect a deliberate construct-then-load two-phase init
pattern already pervasive in this codebase (e.g. `Prefs`). Consistent
with the existing suppressions for useInitializationList/
noCopyConstructor/noOperatorEq, already justified the same way.
1. Makefile.in - extend the suppression list
Moved the --suppress flags into a CPPCHECK_SUPPRESS variable (the recipe
line was getting unreadable) and added, with a comment block explaining
each:
postfixOperator 22x `it++` on non-primitive iterators. No
measurable cost for the iterator types used
here; "fixing" is 22 churn-only edits.
memsetClassFloat 13x `memset(&x, 0, sizeof(x))` on a struct that
contains a float/double. All-zero bytes is a
valid 0.0 / 0.0f on every platform ntopng
targets (IEEE-754); this is the idiomatic way
the codebase zeroes POD-ish structs.
virtualCallInConstructor 7x cleanup()/allocateStats()/toggleRxOnlyHost()
virtualCallInDestructor /walker() are deliberately called from a
ctor/dtor where the *base* implementation is the
intended one. Refactoring is invasive and risky.
nullPointer (path-scoped to src/LuaEngineInterface.cpp,
src/LuaEngineNetwork.cpp, src/LuaEngineNtop.cpp, src/SNMP.cpp)
14x false positives from
#define getLuaVMContext(a) (a ? getUserdata(a) : NULL)
and getLuaVMUserdata(): cppcheck treats the
": NULL" branch as reachable, but the lua_State*
is never NULL inside a Lua C function. Scoped by
file so a real null deref elsewhere still shows.
2. Real bugs fixed
src/Utils.cpp Utils::splitAddressAndVlan()
The no-'@vlan' branch did `vlan_id = 0;` - assigning the *local pointer*
parameter instead of `*vlan_id = 0;`. Result: when the address had no
"@<vlan>" suffix, the caller's vlan_id was left uninitialised (garbage)
instead of being set to 0. Fixed to `*vlan_id = 0;`.
(cppcheck: uselessAssignmentPtrArg)
src/Utils.cpp Utils::parsetime()
`sscanf(&str[4], "%d%s", &v, what)` with `char what[64]` - unbounded %s,
stack buffer overflow for a long time spec (these strings come from REST
parameters such as epoch_begin=now+...). Bounded to "%d%63s".
(cppcheck: invalidscanf)
src/Utils.cpp Utils::tokenizer()
`strchr(arg, c)` was called before the function's own `if (arg)` guard a
few lines down - inconsistent, and a crash if a caller ever passes NULL
(which the later guard shows was considered possible). Added an
arg == NULL early return (sets *data = NULL, returns NULL) at the top.
(cppcheck: nullPointerRedundantCheck)
src/IpAddress.cpp IpAddress::isLocalInterfaceAddress() (broadcast calc)
`~((1 << (32 - nmask_bits)) - 1)` with nmask_bits in 1..30 -> the shift
count reaches 31, i.e. `1 << 31` on a signed int = shift into the sign
bit, which is implementation-defined / UB. Changed the literal to
`(u_int32_t)1`. `nmask` is already u_int32_t.
(cppcheck: shiftTooManyBitsSigned)
src/HTTPserver.cpp (x2), src/Ntop.cpp (x5), src/LuaEngineNtop.cpp (x1)
`mg_md5(buf, a, b, NULL)` - mg_md5() is variadic and stops at a NULL
string pointer, but a bare `NULL` may be passed as `int 0` (only
well-defined when NULL is a pointer constant of the right width). Passing
`(char *) NULL` makes the sentinel explicitly pointer-typed. No
behavioural change on LP64 Linux/macOS; removes the UB.
(cppcheck: varFuncNullUB)
include/Flow.h Flow::setAddressFamilyProtocol()
`ndpiAddressFamilyProtocol = strdup(proto);` with no free of the previous
value and no NULL check on `proto`. The setter can be called more than
once per flow as detection progresses -> each subsequent call leaked the
previous strdup() (the destructor only frees the last one). Now frees the
old buffer first and guards `proto == NULL`.
(cppcheck: publicAllocationError)
src/ParsedFlowCore.cpp both constructors
Neither the default ctor nor the copy ctor initialised next_hop,
mapped_next_hop and mapped_exporter_device_ip (struct ndpi_in6_addr, used
for collected/SNMP-mapped next-hop and exporter addresses). Default ctor
now memset()s them; copy ctor now memcpy()s them from the source.
(cppcheck: uninitMemberVar / missingMemberCopy)
src/GenericTrafficElement.cpp bytes_thpt_diff
`float bytes_thpt_diff` was never initialised in resetStats() (called by
the default ctor) nor copied by the copy ctor. Initialised to 0 in
resetStats() and copied in the copy ctor. (This member currently has no
other reader in the tree, so the effect is limited, but the copy ctor was
literally reading an uninitialised float.)
(cppcheck: uninitMemberVar / missingMemberCopy)
src/Host.cpp Host::triggerAlert()
`u_int64_t alert_rowid = alert->getRowID();` ran *before*
`if (alert == NULL) return false;` - the null check right after it is
pointless if the deref already happened. Moved the assignment below the
check.
(cppcheck: nullPointerRedundantCheck)
src/Redis.cpp Redis::lrpop()
After `*buf = strdup(reply->str);` the code did `if (buf) rc = 0; else
rc = -2;` - `buf` is the `char **` parameter and is always non-NULL, so
the strdup-failure branch (rc = -2) was dead. Changed to `if (*buf)`.
(cppcheck: nullPointerRedundantCheck)
src/Ntop.cpp Ntop::changeAllowedIfname()
`strstr(allowed_ifname, ":__")` at the top of the function, while the
body a few lines later checks `allowed_ifname != NULL && allowed_ifname[0]`
- inconsistent, and a crash if allowed_ifname is NULL. Reordered so the
username guard runs first, then the strstr is done only when
allowed_ifname is non-NULL.
(cppcheck: nullPointerRedundantCheck)
Rework the `cppcheck:` recipe so it is usable in practice:
- `--enable=all` -> `--enable=warning,performance,portability`
(drops the `style`/`information`/`unusedFunction` groups, which produced
hundreds of opinion-level hits)
- drop `--force` (was re-analyzing every file once per #ifdef combination;
single files took 40+ min). Analyzes the default build config only.
- add `-j $(shell nproc)` + `--cppcheck-build-dir=.cppcheck-build` for
parallelism and incremental caching; `mkdir -p` the cache dir in the recipe
- suppress checks that are noise for this codebase:
* useInitializationList - micro perf, POD members
* duplInheritedMember - intentional non-virtual name shadowing
(operator[], swap, enqueue, incUses, lua, ...)
* noCopyConstructor / noOperatorEq - the flagged classes
(NetworkInterface, Ntop, Flow, ...) are non-copyable by design and
always held by pointer; the fix cppcheck suggests (add operator=)
is meaningless for them
- .gitignore: ignore the new .cppcheck-build/ cache directory
FlowAlertsLoader::registerRisk (src/FlowAlertsLoader.cpp)
Missing `else`: `alert_to_risk[alert_type.id] = risk` was executed even when
`alert_type.id >= MAX_DEFINED_FLOW_ALERT_TYPE` -> out-of-bounds array write.
The sibling registerAlert() already had the `else`.
Uninitialized ndpi_protocol structs (src/NetworkInterface.cpp x6,
src/LuaEngineInterface.cpp x1)
Local `ndpi_protocol` values were only partially initialized (proto.* set,
but breed/fpc/state/category/custom_category_userdata left indeterminate)
and then passed by value to get_ndpi_full_proto_name() /
get_ndpi_proto_category(). Added `memset(&x, 0, sizeof(x))` at each
declaration, matching the existing convention elsewhere in the tree.
Uninitialized locals
- src/ParserInterface.cpp: `src2dst_direction` was read on the
`flow == NULL` path (getFlow() not called). Initialize to a defined value;
the value is not otherwise observable on that path.
- include/Bitmap.h (toHexString): if `buf_len <= 0` the first loop never
runs and `strlen(buf)` reads uninitialized memory; also `strlen(buf) - 2`
underflows (unsigned) when the string is shorter than 2 bytes. Null-
terminate up front and hoist strlen into a `size_t`, iterate with
`pos + 2 < len`.
src/NetworkInterface.cpp incNumHosts()/decNumHosts()
`if (isShuttingDown() || (!host->isUnicastHost())) return;` - the second
term is always false, the function already returned on `!isUnicastHost()`
a few lines above. Dropped it.
include/NetworkInterface.h getActiveFlowsStats()
Declaration and definition disagreed on the first two parameter *names*
(`stats, status_stats` vs `ndpi_stats, stats`); types matched. Renamed the
header params to match the implementation.
No behavioural change; each argument was already non-negative.
- Interface id (`get_id()` returns int; kept int because 3 call sites test
`== -1`) formatted with %u in redis-key macros -> cast the argument
`(u_int)` at the call site:
include/AutonomousSystem.h, include/Country.h,
include/ObservationPoint.h, include/VLAN.h,
src/BroadcastDomains.cpp (x2), src/HostPools.cpp, src/LocalHost.cpp,
src/LuaEngineInterface.cpp (x3), src/NetworkInterface.cpp (x2),
src/SyslogParserInterface.cpp
- src/HTTPserver.cpp: `%d` with get_http_port()/get_https_port() (u_int)
-> `%u`; the scanf-width builder `"%%%u[^|]..."` fed `int` macros -> `%d`
- src/Flow.cpp: `"%u.%u.%u.%u"` with `int` octets from a `%d` sscanf -> `%d`;
`%u` (arg 13) with get_protocol_category() enum -> cast `(u_int)`
- src/MacManufacturers.cpp: `int _mac[3]` scanned with `%02x`
(wants `unsigned int*`) -> declare `u_int _mac[3]`
- src/StatsManager.cpp: `%lu` with `static_cast<long int>(key)` epoch values
-> `%ld` (respects the explicit signed cast)
- src/Trace.cpp: `"%s.%u"` with loop `int i` / `i + 1` -> `%d`
- src/Prefs.cpp: `%u` in usage() help text fed CONST_DEFAULT_* /
MAX_NUM_* / CLICKHOUSE_MAX_* int macros -> cast `(u_int)`
std::string / std::vector parameters taken by value, changed to `const &`
(declaration and definition kept in sync; none are virtual or overrides, so
callers are source-compatible):
- AggregatedFlowsStats::setInfoKey
- Flow::setL7JSON
- CustomFlowLuaScriptAlert::setAlertMessage
- CustomHostLuaScriptAlert::setAlertMessage, ctor (_msg)
- ScanRealtimeAlert ctor (_alerts, std::vector)
- CustomHostLuaScript::allocAlert (_msg)
- OtherAlertableEntity::getAlertCachedValue / setAlertCacheValue /
triggerAlert / releaseAlert (key, value)
- HostAlert::init and HostAlert(HostCheckID, ...) ctor (_check_name)
- Ntop::luaFlowCheckInfo / luaHostCheckInfo (check_name)
- Ntop::incBlacklisHits (listname)
- Ntop::setLuaCache (key, val)