Commit graph

4570 commits

Author SHA1 Message Date
Ivan Nardi
39ad39a297 Limit the server ports of the assets to 64 2026-10-21 12:30:09 +02:00
Ivan Nardi
6e2a1de985
Limit the server ports of the assets saved to redis/DB (#11107)
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.
2026-10-21 11:46:23 +02:00
Matteo Biscosi
51173915c7 Fixes ThreadPool issues in windows 2026-10-21 11:09:09 +02:00
Ivan Nardi
4e2a5af7e4
Tags: add the Operating System of the host as built-in tags (#11102)
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.
2026-10-20 08:52:34 +02:00
Ivan Nardi
65c0b561c2
Fix host services/tags set on the wrong peer with view interfaces (#11095)
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.
2026-10-19 08:58:56 +02:00
Ivan Nardi
e8cd24d5ca
Fix host OS not learnt from TCP fingerprint on view interfaces (#11089)
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).
2026-10-16 10:28:41 +02:00
Ivan Nardi
6085f6cfba
Asset tags TTL: keep application/risk tags alive under long-lived flows (#11083)
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.
2026-10-16 10:28:11 +02:00
Luca Deri
68d21d8465 Added method to reseet configuration file
Some checks are pending
Build / build (push) Waiting to run
CIFuzz / Fuzzing (address) (push) Waiting to run
CIFuzz / Fuzzing (undefined) (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
CodeQL / Analyze-1 (push) Waiting to run
2026-10-14 23:09:41 +02:00
Alfredo Cardigliano
88cae2a453 Remove housekeeping_freq redis key (dead code)
Some checks are pending
Build / build (push) Waiting to run
CIFuzz / Fuzzing (address) (push) Waiting to run
CIFuzz / Fuzzing (undefined) (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
CodeQL / Analyze-1 (push) Waiting to run
2026-10-13 16:29:02 +02:00
Matteo Biscosi
d1545ef50e Removed RDP server and added Windows Domain Controller 2026-10-13 11:32:27 +02:00
Ivan Nardi
7fbfd4f6ee
Fix DNS Server service/tag wrongly assigned to DNS clients (#11079)
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).
2026-10-13 11:17:27 +02:00
Alfredo Cardigliano
cd16158e67 Collect stats_interval from nprobe stats 2026-10-13 09:33:15 +02:00
Ivan Nardi
839f135f8a
Asset tags: add TTL/expiration (host side, tag configuration, doc) (#11077)
Some checks are pending
Build / build (push) Waiting to run
CIFuzz / Fuzzing (address) (push) Waiting to run
CIFuzz / Fuzzing (undefined) (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
CodeQL / Analyze-1 (push) Waiting to run
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.
2026-10-11 20:41:23 +02:00
Alfredo Cardigliano
355832589f Parse cpu/memory stats from cento 2026-10-09 11:43:46 +02:00
Alfredo Cardigliano
523fd4cf59 Add missing service to tag mapping 2026-10-08 17:24:55 +02:00
Alfredo Cardigliano
e10c1c45e6 Replace N ServerConfiguration instances (N radix tree lookups, N methods, etc) to a single one. Other related code optimizations. 2026-10-08 17:10:59 +02:00
Matteo Biscosi
e132b5b7cb Added more server configurations (#11057) 2026-10-08 10:33:37 +02:00
Ivan Nardi
25e188a034 Add basic support for latest flow risk NDPI_NON_PQC_FLOW 2026-10-08 09:11:47 +02:00
Ivan Nardi
65da17d698 Set the Non-PQC host tag on view interfaces too (TODO: ZMQ)
Some checks are pending
Build / build (push) Waiting to run
CIFuzz / Fuzzing (address) (push) Waiting to run
CIFuzz / Fuzzing (undefined) (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
CodeQL / Analyze-1 (push) Waiting to run
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.
2026-10-07 17:25:06 +02:00
Alfredo Cardigliano
cf6c38db62 Fix SEGV calling pthread_getcpuclockid on a terminated thread 2026-10-07 10:51:18 +02:00
Ivan Nardi
33cb748609
Fix host user tags removal (#11054)
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.
2026-10-07 09:19:33 +02:00
Alfredo Cardigliano
1f771056b7 Add optional parameter to flush when pcap processing completes 2026-10-06 15:49:22 +02:00
Luca Deri
e6588196ae Added lock to avoid race conditions in Host::tcp_udp_contacted_ports_no_tx,
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.
2026-10-06 09:00:00 +02:00
Alfredo Cardigliano
aadd2352f7 Fix password change: invalidate other sessions (it only worked with scripts/lua/admin/password_reset.lua, now supported on all endpoints including rest/v2/edit/ntopng/user.lua) 2026-10-05 09:51:51 +02:00
Alfredo Cardigliano
720a23c9be Read instance name from nprobe stats. Rename all probe fields for consistency. 2026-10-02 18:13:10 +02:00
Alfredo Cardigliano
c4fd2fd0ad Remove unused parameters in getFlow. Always use zflow in processFlow for consistency and avoid unexpected bahavious. Fix type in ParsedFlowCore. 2026-10-02 16:21:25 +02:00
Luca Deri
c1d6b6eb0c Cpde cleanup
Some checks are pending
Build / build (push) Waiting to run
CIFuzz / Fuzzing (address) (push) Waiting to run
CIFuzz / Fuzzing (undefined) (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
CodeQL / Analyze-1 (push) Waiting to run
2026-09-29 19:36:15 +02:00
Matteo Biscosi
b58c57eb67 Added active flows and added all probes timeseries (#11001)
Some checks are pending
Build / build (push) Waiting to run
CIFuzz / Fuzzing (undefined) (push) Waiting to run
CIFuzz / Fuzzing (address) (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
CodeQL / Analyze-1 (push) Waiting to run
2026-09-29 16:20:24 +02:00
Ivan Nardi
76aded0f07 Tags: fix Application/Risk-Based Tagging on View interfaces
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.
2026-09-29 14:58:27 +02:00
Alfredo Cardigliano
750c89e7e5 Make setService parametric 2026-09-29 14:57:52 +02:00
Alfredo Cardigliano
d3f2a8bc33 Parsing collection port and ip from nprobe stats 2026-09-28 15:54:36 +02:00
Luca Deri
d0c22f0ee1 Runtime fixes
Flow domanin name now uses a buffer
2026-09-28 14:15:58 +02:00
Manuel Ceroni
c01a1f953b
Improved host tag filtering (#10996) 2026-09-25 10:18:35 +02:00
Alfredo Cardigliano
14d1933ba0 Fix exporter match in flow dedup
Some checks are pending
Build / build (push) Waiting to run
CIFuzz / Fuzzing (address) (push) Waiting to run
CIFuzz / Fuzzing (undefined) (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
CodeQL / Analyze-1 (push) Waiting to run
2026-09-24 16:56:24 +02:00
Ivan Nardi
c87c4a7ef0
Host Application Labelling: initial support for flow risks (#10994) 2026-09-24 15:14:44 +02:00
Luca Deri
3ef23ce6ce Reimplements Host::isValidHostName() that was "too generic" splitting into various validation fucntions for specific protocols 2026-09-23 22:37:18 +02:00
Alfredo Cardigliano
52578629f3 Keep clickhouse ts pref on failure when falling back to rrs. Add warning. 2026-09-22 09:21:18 +02:00
Alfredo Cardigliano
41bec0eac8 Fix requested server name to also include DNS and other cases. Rework code to use the same function used for the domain. 2026-09-21 16:07:27 +02:00
Ivan Nardi
82b75c05a1
Initial implementation of Host Application Labelling (#10960)
See: #10921
2026-09-18 13:37:49 +02:00
Alfredo Cardigliano
282e37ce68 Add Requested Server Name / SNI column (move the name from the json to the native column) 2026-09-14 17:03:47 +02:00
Ivan Nardi
52070fcb32
Fix alert-pipeline drain race before e2e shutdown-when-done test scripts (#10929)
`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.
2026-09-14 15:08:28 +02:00
Ivan Nardi
2346a233ad Another round of cppcheck fixes
- `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.
2026-09-12 19:20:23 +02:00
Alfredo Cardigliano
3c8edf3aa8 Fix reboot toast and change message with the reason. Expose active_monitoring_not_avail (set in case of pcap file). 2026-09-02 17:42:40 +02:00
Ivan Nardi
09e1786a53
cppcheck: second batch of fixes (#10882)
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)
2026-09-02 12:31:49 +02:00
Matteo Biscosi
b2bc2f748f Added startssl option to email endpoints (#10843) 2026-09-01 14:12:14 +00:00
Matteo Biscosi
f2b275a1ec Fixes max number of coroutines used 2026-09-01 08:09:53 +00:00
Ivan Nardi
8ee8b740ea
First batch of make cppcheck clean up (#10878)
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)
2026-09-01 08:36:01 +02:00
Alfredo Cardigliano
06abe4b827 Disable Continuous Ping when processing pcap dump (fix #10863) 2026-08-31 13:15:15 +02:00
Alfredo Cardigliano
62e0487868 Enable ZMQ encryption by default. Add public key pair to be used as default. Add toast to warn the user. Add --zmq-disable-encryption to disable encryption. 2026-08-31 11:15:02 +02:00
Ivan Nardi
fd011bb82f Flow: fix a memory leak with malformed HTTP_CONNECT traffic
```
Direct leak of 8 byte(s) in 1 object(s) allocated from:
    #0 0x5a5b12fcee74 in ___interceptor_malloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:67:3
    #1 0x5a5b13354ccd in Flow::dissectHTTP(bool, char*, unsigned short) ntopng/src/Flow.cpp:7040:27
    #2 0x5a5b130c3a44 in NetworkInterface::processPacket(int, unsigned int, int, bool*, timeval const*, unsigned long, ndpi_ethhdr*, unsigned short, ndpi_iphdr*, ndpi_ipv6hdr*, unsigned short, unsigned short, unsigned int, pcap_pkthdr const*, unsigned char const*, unsigned short*, Host**, Host**, Flow**, bool*, unsigned char*) ntopng/src/NetworkInterface.cpp:2632:17
    #3 0x5a5b130cb779 in NetworkInterface::dissectPacket(int, unsigned int, int, bool, unsigned char*, pcap_pkthdr const*, unsigned char const*, unsigned short*, Host**, Host**, Flow**) ntopng/src/NetworkInterface.cpp:3611:26
```
Found by oss-fuzz
See: https://issues.oss-fuzz.com/issues/552370101
2026-08-31 07:04:50 +00:00