Skip to main content

Fingerprint Architecture

ServiceRadar netprobe uses a license-clean passive fingerprint stack. The goal is to identify likely OS, device, and protocol families from traffic already crossing the agent host without active probes and without shipping commercially-restricted fingerprint algorithms.

Signal Stack

The current stack is:

  • p0f canonical TCP SYN signatures, encoded in the eBPF path and matched in userspace against the bundled p0f corpus.
  • ServiceRadar p0f additions for signatures we curate from legacy gear and field observations.
  • MuonFP TCP SYN canonical signatures as a parallel TCP-axis signal.
  • JA4 base for TLS ClientHello fingerprints.
  • HASSH and HASSH-Server for SSH KEXINIT fingerprints, using Corelight's maintained fork of the original Salesforce work.
  • Recog banner fingerprints for HTTP, SSH, FTP, Telnet, SMB, SNMP, SIP, RDP, and DNS version strings observed by existing dissectors or banner probes.
  • Satori XML fingerprints for TCP, DHCP/DHCPv6, DNS, ICMP, NTP, SIP, SMB, SSH, SSL/TLS, HTTP server, and HTTP user-agent observations.

The TCP-axis signals are primary because SYN metadata is available for most managed hosts and can be extracted once per connection. JA4 base, HASSH, Recog, and Satori are confidence boosters when the same device exposes matching TLS, SSH, banner, DHCP, DNS, ICMP, NTP, SIP, SMB, or HTTP evidence.

Data Flow

  1. eBPF programs observe TCP connection setup and encode the canonical p0f signature string and the MuonFP/Satori TCP fields derived from the same SYN.
  2. Netprobe userspace consumes the p0f_signatures ring buffer and matches TCP signatures with rust/netprobe/src/p0f_matcher.rs, rust/netprobe/src/muonfp.rs, and the Satori TCP matcher.
  3. DPI dissectors produce JA4 base, HASSH, Recog, and Satori observations when protocol payloads are available under the active visibility profile.
  4. rust/netprobe/src/os_matcher.rs fuses agreeing observations into a LicenseCleanFingerprint event. Disagreements are preserved as metadata so operators can curate new signatures instead of hiding uncertainty.
  5. The agent reports all corpus and spec revisions in netprobe status: p0f, ServiceRadar p0f additions, JA4 base, MuonFP, Recog, Satori, and ServiceRadar Recog additions.

Coverage Matrix

SignalObservation axisSourceLicense boundaryPackaging
p0fTCP SYNp0f.fpLGPL-2.1 data fileCompiled matcher; source corpus remains replaceable
ServiceRadar p0f additionsTCP SYNserviceradar-additions.fpCC0-1.0 ServiceRadar dataCompiled matcher; separate from upstream p0f
MuonFPTCP SYNFormat reference, no upstream label corpusMIT reference encoder; CC BY 4.0 spec textServiceRadar-owned matcher rules
JA4 baseTLS ClientHelloFoxIO JA4 base specBSD-3-Clause JA4 base onlyCode only; no JA4+ algorithms
HASSHSSH KEXINITCorelight maintained forkBSD-3-ClauseCode only
RecogService bannersRapid7 XML corpusBSD-2-ClauseCompile-time regex DFA generation
ServiceRadar Recog additionsService bannersserviceradar-recog-additions.xmlCC0-1.0 ServiceRadar dataCompile-time regex DFA generation
SatoriTCP, DHCP, DNS, ICMP, NTP, SIP, SMB, SSH, SSL/TLS, HTTPxnih Satori XMLGPLv2 data files onlyRuntime-loaded replaceable XML corpus

The ensemble weights agreement across independent axes more heavily than multiple signatures from the same axis. A p0f-only match is useful but low confidence. A device that produces agreeing TCP, HTTP banner, TLS, SSH, and DHCP evidence reaches the highest confidence tier. Disagreement is emitted as metadata so operators can curate additions or investigate middleboxes.

Licensing Boundaries

The upstream p0f.fp corpus remains a separate LGPL-2.1 data file under rust/netprobe/p0f-corpus/p0f.fp. ServiceRadar does not relicense it. Operators can replace or inspect it independently of the Apache-2.0 ServiceRadar code.

ServiceRadar-owned additions live in rust/netprobe/p0f-corpus/serviceradar-additions.fp and default to CC0-1.0. The curation workflow is documented in rust/netprobe/p0f-corpus/CONTRIBUTING.md.

MuonFP is included as an audited format/reference input. The pinned upstream tree does not contain a standalone signature corpus, so ServiceRadar does not ship an upstream MuonFP label database. ServiceRadar-owned MuonFP rules can be added separately when curated.

JA4 base is included because FoxIO publishes a separate BSD-3-Clause license for the TLS ClientHello algorithm at https://github.com/FoxIO-LLC/ja4/blob/main/LICENSE-JA4. The broader JA4+ license at https://github.com/FoxIO-LLC/ja4/blob/main/LICENSE covers JA4T, JA4H, JA4S, JA4SSH, JA4X, and related algorithms under terms that do not fit ServiceRadar's commercial redistribution model. Netprobe therefore does not implement those algorithms.

HASSH is included from Corelight's maintained BSD-3-Clause fork: https://github.com/corelight/hassh. The original Salesforce notice is preserved in rust/netprobe/LICENSE-HASSH.

Recog is included from Rapid7's BSD-2-Clause XML corpus under rust/netprobe/recog-corpus/xml/. ServiceRadar additions live in rust/netprobe/recog-corpus/serviceradar-recog-additions.xml, default to CC0-1.0, and are reviewed with make lint-recog-additions.

Satori is included only as GPLv2 XML data under rust/netprobe/satori-corpus/xml/. The Python runtime, pcap integration, and SSL / JA4 implementation are not copied. Netprobe runtime-loads the XML files from a replaceable corpus directory and must not embed them with include_str!, include_bytes!, generated Rust constants, or translated code.

Operational Guardrails

  • Do not add huginn-net, ja4t, ja4h, ja4s, ja4ssh, ja4x, or a FoxIO-1.1-licensed crate to netprobe.
  • Do not edit rust/netprobe/p0f-corpus/p0f.fp for local signatures. Use serviceradar-additions.fp.
  • Do not edit Rapid7 Recog XML files for local signatures. Use serviceradar-recog-additions.xml.
  • Do not edit Satori XML files for ServiceRadar-owned additions. Keep any local additions in ServiceRadar-owned files with a separate license.
  • Run make lint-p0f-additions before merging p0f addition changes.
  • Run make lint-recog-additions before merging Recog addition changes.
  • Run bash scripts/check-netprobe-fingerprint-licenses.sh after changing any fingerprint corpus or dependency.
  • Keep P0F_CORPUS_REVISION, SERVICERADAR_ADDITIONS_REVISION, JA4_BASE_SPEC_REVISION, MUONFP_CORPUS_REVISION, RECOG_CORPUS_REVISION, SATORI_CORPUS_REVISION, and SERVICERADAR_RECOG_ADDITIONS_REVISION in rust/netprobe/src/fingerprint.rs synchronized with corpus and spec changes.
  • Use AshPaperTrail-backed visibility profile audit logs for operator changes that enable invasive capture surfaces.