Commit graph

28353 commits

Author SHA1 Message Date
Luca Deri
c89e4e72ac Fixes crash with views
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-31 07:35:05 +01:00
Luca Deri
866cc8bdc6 Implemented processing of ICMPv6 rputer advertisement
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-10-30 23:53:06 +01:00
Luca Deri
60d5a0a378 Improved network topology 2026-10-30 23:17:54 +01:00
GabrieleDeri
b58232919c
Host details added syslog href. Updated docs (#11168)
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
* Updated traffic rules documentation

* Update dist

* Host details added syslog href

* Update dist
2026-10-30 19:10:40 +01:00
Alfredo Cardigliano
6b7d049ab6 Fix BPF filter injection in live capture bypasses allowed networks
Discovered by Anthropic's OSS Scanner, as vulnerability ANT-2026-KE2X9SCD
2026-10-30 17:45:38 +00:00
Alfredo Cardigliano
a20471240a Fix heap buffer overflow in SyslogLuaEngine: pcall never pops Lua errors
Discovered by Anthropic's OSS Scanner, as vulnerability ANT-2026-5ROG6AEI
2026-10-30 16:36:21 +00:00
Luca Deri
2ece5f67cf In Utils::isNullAddress() added support for IPv4 in IPv6 addresses 2026-10-30 17:33:01 +01:00
Matteo Biscosi
d8a4543d61 Discovered by Anthropic's OSS Scanner, as vulnerability ANT-2026-OLPQJTIS 2026-10-30 16:54:43 +01:00
Matteo Biscosi
a2ecb2190a Discovered by Anthropic's OSS Scanner, as vulnerability ANT-2026-KZ5MKJJJ 2026-10-30 16:32:35 +01:00
Matteo Biscosi
36933daffa Added debug trace to Clickhouse TS exporter 2026-10-30 16:29:49 +01:00
Matteo Biscosi
46c9c25fcf Fixes timeseries not working for dynamic traffic interfaces 2026-10-30 15:55:09 +01:00
GabrieleDeri
a2e5ce2846
Added search input and filters on syslog events page (#11167)
* Added search input and filters on syslog events page

* Update dist
2026-10-30 15:41:01 +01:00
GabrieleDeri
a1876e1617
Discovered by Anthropic's OSS Scanner, as vulnerability ANT-2026-NYYQ0DQ5 (#11166) 2026-10-30 15:29:19 +01:00
Ivan Nardi
ad055ca9b5
recording_utils: restrict the n2disk config/ntopctl interface name (#11165)
Restrict the string to [A-Za-z0-9:_-] so an interface name cannot inject
shell commands

Discovered by Anthropic's OSS Scanner, as vulnerability ANT-2026-AU1COUX2
2026-10-30 14:26:25 +01:00
Ivan Nardi
d99a72834a
Flow: never let a collected master/app pair select two members of the Flow::protos union (#11164)
`Flow::protos` is a union whose active member is chosen by `isProto(p)`,
which matches either the master or the application protocol; every writer
and reader (`updateDNS`/`updateTLS`/`updateHTTP`, `Flow::lua`, the
destructor) relies on at most one member being selected.
nDPI never emits a pair spanning two members, but `ParserInterface::processFlow()`
stores the pair exactly as the exporter sent it (syslog/Suricata, ZMQ/nProbe),
so '5.91' makes `isDNS()` and `isTLS()` both true and DNS integers are later
read as TLS string pointers.
`Flow::setDetectedProtocol()` is the single place where an externally supplied
pair becomes the flow's protocol, so the invariant is restored there: a
new file-local `getProtosUnionMember()` maps a protocol id to the member it owns
(mirroring the `is<Proto>()` helpers and the destructor), and when master
and app own different members the application protocol is dropped (DNS.TLS
becomes DNS); for ICMP/ICMPv6 L4 flows, whose protos.icmp is written by
`setICMPTypeCode()` whatever the L7 pair says, any L7 protocol owning
another member is dropped.

setSIPCallId() is now called under flow->isSIP() after the

Discovered by Anthropic's OSS Scanner, as vulnerability ANT-2026-UC4ZSTCJ
2026-10-30 13:41:05 +01:00
Matteo Biscosi
0f6b0bbdd0 Fixes rrd paths with incorrect interface 2026-10-30 12:57:13 +01:00
uwezkhan
3c06a3d9ff
generate csrf and pending auth tokens from the csprng, not rand() (#11035)
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-10-30 11:02:51 +01:00
Ivan Nardi
0c57316ec9 Fix use-after-free and double free after a host data reset
A host data reset (GUI "Delete host data", REST
`rest/v2/delete/host/data.lua`, i.e. Lua `interface.deleteHostData()`) only
requests the reset: it is performed by `Host::checkDataReset()` ->
`LocalHost::deleteHostData()` -> `freeLocalHostData()`, in
`periodic_stats_update`, by the thread purging the idle hosts of the
interface.
The host keeps living after it, but
`freeLocalHostData()` freed tcp_fingerprint and deleted fingerprints
without resetting them:
- the HTTP server threads read the freed tcp_fingerprint when showing
  the host (host page, `rest/v2/get/host/data.lua`, ... -> `Host::lua` ->
  `lua_get_fingerprints`): heap-use-after-free
- the threads processing the flows kept updating the deleted
  fingerprints (`Flow::updateCliJA4/updateHASSH`) and compared the new TCP
  fingerprint with the freed one (`setTCPfingerprint`)
- the destructor (host purged or ntopng shutdown) freed both again:
  double free

Fix:
- tcp_fingerprint: freed and reset under `Host::m`, also read
  (`lua_get_fingerprints`) and set (`setTCPfingerprint`) under it;
  `tcp_fingerprint_host_os` is reset so that the fingerprint is learnt
  again from the next flows
- fingerprints: emptied (`Fingerprint::reset`, under its own lock) rather
  than deleted, as the threads processing the flows use it without
  locking; deleted by the destructor only
2026-10-30 10:51:58 +01:00
Ivan Nardi
ddef8aa75d Fix data races on the asset data of hosts and MACs
The asset info of a host is dumped by the housekeeping thread
(dumpAssetInfo) while the threads processing the flows and the Lua/REST
threads change it, with no synchronization:
- `asset_map`: now protected by `Host::m` (`add/removeDataFromAssets`, dump,
  load)
- `tags refreshed/removed/assigned` bitmaps: now atomic, so that a bit set
  while the asset is dumped is no longer lost
- `asset_map_updated`: now atomic and out of the LocalHost bitfield (a
  write rewrote the whole byte, losing the other flags written at the
  same time). Same for `Mac::asset_map_updated`
- `Mac::dhcpv4_fingerprint`: now protected by `Mac::m`, read through a
  copying getter, as it can be replaced (and freed) at any time

Rules to avoid deadlocks are documented on `Host::m` and `Mac::m`.
2026-10-30 10:51:58 +01:00
uwezkhan
b1ff349f6d
require the ssdp location authority to be the sender in analyzeSSDP (#11069)
string.starts is a plain prefix comparison with no authority boundary, so a Location: value only has to begin with "http://" plus the responder IP to pass while libcurl dials elsewhere: http://IP@attacker.example/x carries the IP as userinfo, http://IP@127.0.0.1:3001/ reaches ntopng itself, and http://IP.attacker.example/x and http://IP0/x are different hosts. Compare the authority that libcurl resolves instead, and reject one carrying userinfo.
2026-10-30 10:20:49 +01:00
uwezkhan
05d60d06bd
bound sscanf fields in ntop_loadCustomCategoryFile (#11142)
The hosts and ip_occurencies list formats split each line with a
width-less %s into 64-byte stack buffers (ignore and host), while the
line comes from a 256-byte fgets() buffer holding downloaded feed data.
A first token longer than 63 bytes overflowed the buffer.

Use %255s and size both buffers to 256 bytes, like the sibling host
buffer, so no token from a valid line is truncated.
2026-10-30 09:55:56 +01:00
Ivan Nardi
3066bd38c7
Close the pcap file handles of playlists and directories (#11160)
The pcap files read from a playlist or a directory were opened one after the
other and stored with set_pcap_handle(), which overwrote the previous handle:
all the files but the last one leaked their pcap_t, buffer and open file
(ASAN: "Direct leak" from pcap_open_offline_common at exit).

set_pcap_handle() now closes the previous handle. As the handle is then closed
by the packet thread while other threads may read it (GUI and view through
getNumDroppedPackets()), getNumDroppedPackets() returns 0 for pcap files
without reading the handle: libpcap has no statistics for them anyway.
2026-10-30 09:00:50 +01:00
Ivan Nardi
028f3d6465
Fix the nDPI confidence of historical flows (#11161)
- Dump `DPI_PARTIAL_CACHE` as `DPI` in `PROTOCOL_INFO_JSON`, using
  `isDPIDetectedFlow()` like the live flows do
- Show the confidence badge in the historical flow details: read it from
  `PROTOCOL_INFO_JSON`, `ALERT_JSON` has no proto block
2026-10-30 09:00:23 +01:00
GabrieleDeri
e49a4d5a75
Update dist (#11163)
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
* Update dist

* Update dist
2026-10-29 21:59:02 +01:00
GabrieleDeri
e5e1877875
Flow topology chart (#11162)
* Flow topology chart

* Update dist
2026-10-29 21:13:34 +01:00
Luca Deri
f5e7a5c964 Changes required for implementing flow-based topology 2026-10-29 20:30:51 +01:00
GabrieleDeri
2275953a21
Added syslog ingestion documentation (#11159)
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-29 18:55:08 +01:00
Alfredo Cardigliano
96df4b653e Fix path of default kea leases file (this is the one allowed by apparmor) 2026-10-29 17:45:24 +00:00
GabrieleDeri
2edf9216a4
Added syslog page (#11158)
* Added syslog page

* Update dist
2026-10-29 18:16:59 +01:00
Alfredo Cardigliano
f992937273 When Kea is in use, make sure the ISC DHCP server is disabled. When Kes is disabled, stop it only if it was enabled by nedge 2026-10-29 15:00:44 +00:00
Luca Deri
cc1811ffa9 Syslog changes 2026-10-29 15:08:13 +01:00
Ivan Nardi
57c35a8ed4
Decide the direction of UDP flows by the default ports of the protocol (#11157)
UDP flows whose direction is not told by their requests and replies (see
checkL7Direction(), e.g. SIP, QUIC) kept the sender of their first packet as
client: when captured from the server side, e.g. a QUIC server on port 443
(5,948 flows in a production capture), they stayed reversed.

checkTCPDirectionByProtocol() is renamed checkDirectionByProtocol() and also
handles UDP: once the protocol is detected, the side using one of its default
UDP ports (nDPI) is the server, when only one side uses one, as for TCP.
2026-10-29 13:06:33 +01:00
Matteo Biscosi
7da92aeffb Updated dist 2026-10-29 12:43:25 +01:00
Matteo Biscosi
3dd04c04b3 Moved alerts page to router SPA 2026-10-29 12:41:42 +01:00
Ivan Nardi
d456305064
Pack and unpack the categories of the custom lists without undefined behavior (#11156)
The custom category lists are loaded into nDPI with the list id and the
category packed in the category: `(list_id << 8) + category`. nDPI returns
that value as a `ndpi_protocol_category_t`, although it is not a valid one, and
it was read in several ways, some wrong:

* `IpAddress::reloadBlacklist()` read the custom category match into a
  u_int16_t through a ndpi_protocol_category_t pointer: nDPI writes 4 bytes,
  a stack buffer overflow (ASAN).
* `Flow::processPacket()` loaded the category of each packet into
  flow_category: undefined behavior (UBSAN: "load of value 1124, which is not
  a valid value for type 'ndpi_protocol_category_t'"), and flow_category held
  the packed value until the detection was completed.
* `ntop_match_custom_category()` loaded the match as an enum value too.
* `Flow::setExtraDissectionCompleted()` computed the list id after masking the
  category, so it was always 0.
* `Flow::updateProtocol()` unpacked only the Malware category of the list with
  id 4 (> 1024 check); other packed values reached flow_category.

The format is now defined in one place, `Utils:`
* `packCustomCategory()` packs the category and the list id (used by
  Ntop::nDPILoadIPCategory and Ntop::nDPILoadHostnameCategory). The packed
  value is kept as an integer until it is passed to nDPI, as reading a
  ndpi_protocol_category_t variable holding it is undefined behavior.
* `unpackCustomCategory()` reads the value returned by nDPI as an integer
  (memcpy, so the invalid value is never loaded as an enum) and returns the
  category, optionally the list id; categories not packed are returned as
  they are. It is used in all the places above.
2026-10-29 11:33:39 +01:00
Matteo Biscosi
178ffb4194 Updated dist 2026-10-29 11:26:36 +01:00
Matteo Biscosi
841404232a Updated alerts page to SPA Router 2026-10-29 11:20:50 +01:00
Ivan Nardi
2dd40c9f46 Update tests/e2e 2026-10-29 11:13:47 +01:00
Luca Deri
9c9f044952 Fixed table definition
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-29 11:03:37 +01:00
Matteo Biscosi
d7e1bbecd7 Added alerts overview to SPA router 2026-10-29 10:24:15 +01:00
Ivan Nardi
5143ad96a6 Update tests/e2e 2026-10-29 09:41:12 +01:00
Ivan Nardi
820b6dc730 Add documentation about flow swap/direction logic 2026-10-29 09:22:28 +01:00
Ivan Nardi
6d499f5718
Track the alerts dequeued by the recipients until they are processed (#11153)
The runtime script of the e2e tests runs, on shutdown-when-done, once the
alert pipeline is drained (Ntop::alerts_pipeline_drained()), which includes
the recipient queues being empty (Recipients::empty()).

The recipients are processed by Lua (process_notifications()): each endpoint
first dequeues a batch of notifications (ntop.recipient_dequeue(), which
deletes the C++ item) and only then processes it, e.g. alert_store_db writes
it to the alert store (SQLite). While the batch is being processed the
recipient queues are empty, so the pipeline looks drained although the
alerts are not in the alert store yet: under load or with slower builds
(e.g. ASAN) the runtime script saw only part of the alerts.

Fix: a recipient with notifications dequeued is not empty until the next
pass of process_notifications() over the recipients, which calls
ntop.recipient_last_use() for each recipient at its beginning: the
notifications dequeued in the previous pass have been processed by then.
2026-10-29 09:20:27 +01:00
Luca Deri
e9f9d981c7 Updated db schema (removed is_deleted)
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-28 22:41:27 +01:00
Ivan Nardi
95aca52621
Fix direction of SNMPv3 flows when not encrypted (#11154)
The direction of SNMPv3 flows was decided by the header only (the PDU is
usually encrypted): the reportable flag is set in the requests and in the
informs; otherwise the message was taken as a reply, unless sent to the trap
port (162). A trap sent to another port, e.g. 161, was then taken as a reply
and the flow was swapped, with the receiver of the trap as the client.

When the scoped PDU is not encrypted (privacy flag of the header clear, i.e.
noAuthNoPriv and authNoPriv) its PDU type is now read as for SNMPv1/v2c
(isSNMPReplyPDU()). The header is still used for the encrypted messages.
2026-10-28 21:45:15 +01:00
Ivan Nardi
9ceda19f6b Update tests/e2e 2026-10-28 20:32:37 +01:00
Ivan Nardi
b7c1d566e2
Decide the direction of TCP flows by the handshake (#11152)
The client and the server of TCP flows (packet interfaces) are now decided
once, by the first SYN (sent by the client) or SYN-ACK (sent by the server)
seen, whatever came before it. Before, any first packet
that was not a SYN marked the handshake as over and the SYN-ACK rules were
skipped: with the client port lower than the server port the flow stayed
reversed.

* `checkTCPDirection()` replaces the guess by the ports on the first packet,
  the SYN-ACK rules of `updateTcpFlags()` and the SSH/TLS swap of
  `updateTCPHostServices()`.
* Flows without a handshake are still guessed by the ports on their first
  packet. Once the protocol is detected, the default ports of the protocol
  (nDPI) correct the guess when only one side uses one,
  (`checkTCPDirectionByProtocol()`).
* The direction is final once the protocol is detected on a flow that has
  carried payload.
* `performPendingSwap()` no longer skips the flows already swapped once (`swap()`
  clears `swap_requested`, so the `swap_done` check was stale): a correction
  requested after the last packet of the flow is now performed.
* `l7_direction_checked` is renamed `direction_decided`, as it is now shared by
  the TCP and the L7 (UDP/ICMP) checks.
2026-10-28 20:11:39 +01:00
Luca Deri
a829a4f825 Syntax error fix 2026-10-28 19:21:16 +01:00
Ivan Nardi
7a5baa2ac0
Decide the direction of SNMPv3, NTP control/private and more DHCPv6 flows (#11150)
Flow::checkL7Direction() could not decide some flows, recorded with the
replier as client when their first packet is a reply:

* SNMPv3: the PDU is usually encrypted. isSNMPReply() (replacing
  getSNMPPDUType()) now reads the reportable flag of the header (msgFlags,
  never encrypted): it is set in the requests and in the informs; otherwise
  the message is a trap when sent to the trap port (162), a reply (Response,
  Report) when not. SNMPv1/v2c are still decided by the PDU type.
* NTP control (mode 6) and private (mode 7, e.g. monlist) messages: by their
  R (response) bit. Note: nDPI does not detect NTP control responses (their
  second byte is read as an invalid stratum), so a flow starting with one is
  still not decided.
* DHCPv6: LEASEQUERY, RECONFIGURE-REQUEST, DHCPV4-QUERY and ADDR-REG-INFORM
  are sent by the client, LEASEQUERY-REPLY, RECONFIGURE-REPLY, DHCPV4-RESPONSE
  and ADDR-REG-REPLY by the server. A leasequery requestor (port 547) also
  got the DHCP service, and the Unexpected DHCP server alert, when its query
  was the first packet.
2026-10-28 18:49:56 +01:00
GabrieleDeri
d2f007c0b7
Update dist (#11151) 2026-10-28 18:47:00 +01:00