You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hostname resolution already exists and covers most of the obvious protocols — this issue is about closing the remaining gaps and, more importantly, connecting hostname data we already extract but throw away.
HostnameResolverService runs one read-only tshark pass and resolves IP → hostname from DHCP, mDNS, NBNS, and reverse DNS (PTR), with a priority model resolving conflicts:
SOURCE_PRIORITY = Map.of(MANUAL, 0, DHCP, 1, MDNS, 2, NBNS, 3, REVERSE_DNS, 4);
// Lower value = more authoritative for a host's own identity; the lowest wins per IP.
It's already surfaced (HostnameSourceBadge in NodeDetails and TopHostsTable) and already usable as a node label (buildNodeLines, case 'hostname'). So the feature exists; the ask is to extend it.
Gap 1 — nDPI already extracts Hostname/SNI per conversation, and it never reaches the resolver
NdpiService parses a hostname/SNI field out of every flow:
/** Matches the hostname/SNI field, e.g. [Hostname/SNI: zoom.us] → group(1) = "zoom.us". */privatestaticfinalPatternHOSTNAME = ...
if (data.hostname() != null) conv.setHostname(data.hostname()); // NdpiService:129
That lands on ConversationEntity.hostname and is used only for the web-server detail panel (NetworkIntelligenceService:606 reads it as sniNames). It is never offered to HostnameResolverService.
This is the single biggest win available: the data is already extracted, already persisted, and already per-IP-addressable — it just isn't wired into hostname resolution. No new tshark pass, no new parsing.
Important caveat — direction matters. TLS SNI and HTTP Host are what a client asked for, i.e. the name of the destination. They are not the host's own identity the way DHCP/NBNS/mDNS names are. Naively mapping conv.hostname → srcIp would be badly wrong. It must attach to dstIp, and even then it's the requested name (possibly a CDN, a vhost, or one of many names on one IP) rather than the machine's name. This is exactly why the existing SOURCE_PRIORITY model matters: these deserve a low-priority source, below DHCP/mDNS/NBNS, so they only fill gaps and never override a self-declared identity.
Gap 2 — protocols not currently covered
HTTP Host header — cleartext HTTP only, same directional caveat as SNI. WebServerLogExtractor already runs an HTTP tshark pass and already reads http.server; adding http.host there is cheap.
TLS SNI directly from tshark (tls.handshake.extensions_server_name) — an alternative to relying on nDPI's parse; also gives the ClientHello side explicitly.
TLS certificate CN/SAN — ConversationEntity.tlsSubject is already persisted and contains the server's certificate subject. That's a server-asserted identity for the destination IP, and arguably higher quality than SNI (the server proves it, rather than the client requesting it). Also already extracted and unused for naming.
LLMNR — the natural companion to NBNS/mDNS on Windows networks; conspicuously absent from the current filter.
resolve(File pcapFile) runs per capture. A host that DHCP-named itself in snapshot 1 but is silent in snapshot 5 has no name in snapshot 5's diagram, even though we learned it. Monitor mode has ordered snapshots and IpMacObservationEntity already links IP↔MAC across files — a hostname learned once could carry forward, ideally keyed by MAC rather than IP (IPs churn under DHCP; see #510).
Acceptance Criteria
Hostnames already extracted by nDPI (ConversationEntity.hostname) contribute to IP → hostname resolution, attached to the correct (destination) IP.
Client-requested names (SNI / HTTP Host) rank below self-declared names (DHCP/mDNS/NBNS) in SOURCE_PRIORITY, so they only fill gaps.
TLS certificate subject (CN/SAN) is evaluated as a naming source for server IPs.
LLMNR is added to the resolver's tshark filter alongside mDNS/NBNS.
Each new source has its own SOURCE_* constant and HostnameSourceBadge treatment, so users can see how a name was derived and judge it.
A host with multiple candidate names resolves deterministically via the existing priority model.
No regression to the single-pass design — HostnameResolverService must stay one tshark pass and never throw.
Design questions
Is a requested name an acceptable label at all? Labelling 104.16.x.x as zoom.us is useful for triage but is not that machine's identity — one IP may serve hundreds of names. Do we label the node, or only list candidate names in NodeDetails? This is the core judgement call; getting it wrong makes the diagram confidently misleading, which is worse than a blank label.
One name or many?hostname is a single column today. SNI naturally yields many names per server IP (NetworkIntelligenceService already collects sniNames as a list). Does the model need IP → set of names with sources, with one chosen for display?
Where does SNI-derived naming belong — extend HostnameResolverService (needs conversation data it doesn't currently see; it takes a File), or a post-pass in AnalysisService after nDPI has run? The latter is likely simpler: deviceOverrides/hostnames are already threaded together there (AnalysisService:145-163).
Public vs. private. For external IPs, an SNI/cert name is often the most useful label (api.stripe.com beats 34.x.x.x). For internal hosts it's usually noise. Should the source priority differ by whether the IP is private?
Trust. A malicious host can DHCP-declare any name it likes. Do we surface conflicts (two IPs claiming the same name; a name that contradicts the cert) as a finding rather than silently picking a winner? That's arguably a security signal, not just a labelling detail.
Notes
Suggested sequencing:
Wire nDPI's existing hostname into resolution as a low-priority, destination-attached source — highest value per line of code; data is already there.
TLS cert subject as a naming source — also already persisted (tlsSubject).
LLMNR + http.host — small additions to existing tshark passes.
Worth noting for triage value: the existing priority model is well-designed and already does the hard part (conflict resolution with explicit authority ordering). Most of this issue is feeding it more inputs, not rebuilding it.
Related: #510 (MAC-grouped identity across snapshots — the natural key for hostname carry-forward), #501 (unknown protocols — hostname presence/absence is a triage signal), #509 (diagram rendering — hostnames are the label that makes a diagram readable), #499 (conflicting classification axes — hostname conflicts are a similar "sources disagree" problem).
Description
Hostname resolution already exists and covers most of the obvious protocols — this issue is about closing the remaining gaps and, more importantly, connecting hostname data we already extract but throw away.
HostnameResolverServiceruns one read-only tshark pass and resolves IP → hostname from DHCP, mDNS, NBNS, and reverse DNS (PTR), with a priority model resolving conflicts:It's already surfaced (
HostnameSourceBadgein NodeDetails and TopHostsTable) and already usable as a node label (buildNodeLines,case 'hostname'). So the feature exists; the ask is to extend it.Gap 1 — nDPI already extracts Hostname/SNI per conversation, and it never reaches the resolver
NdpiServiceparses a hostname/SNI field out of every flow:That lands on
ConversationEntity.hostnameand is used only for the web-server detail panel (NetworkIntelligenceService:606reads it assniNames). It is never offered toHostnameResolverService.This is the single biggest win available: the data is already extracted, already persisted, and already per-IP-addressable — it just isn't wired into hostname resolution. No new tshark pass, no new parsing.
Important caveat — direction matters. TLS SNI and HTTP
Hostare what a client asked for, i.e. the name of the destination. They are not the host's own identity the way DHCP/NBNS/mDNS names are. Naively mappingconv.hostname→srcIpwould be badly wrong. It must attach todstIp, and even then it's the requested name (possibly a CDN, a vhost, or one of many names on one IP) rather than the machine's name. This is exactly why the existingSOURCE_PRIORITYmodel matters: these deserve a low-priority source, below DHCP/mDNS/NBNS, so they only fill gaps and never override a self-declared identity.Gap 2 — protocols not currently covered
Hostheader — cleartext HTTP only, same directional caveat as SNI.WebServerLogExtractoralready runs an HTTP tshark pass and already readshttp.server; addinghttp.hostthere is cheap.tls.handshake.extensions_server_name) — an alternative to relying on nDPI's parse; also gives the ClientHello side explicitly.ConversationEntity.tlsSubjectis already persisted and contains the server's certificate subject. That's a server-asserted identity for the destination IP, and arguably higher quality than SNI (the server proves it, rather than the client requesting it). Also already extracted and unused for naming.Gap 3 — resolution is per-file
resolve(File pcapFile)runs per capture. A host that DHCP-named itself in snapshot 1 but is silent in snapshot 5 has no name in snapshot 5's diagram, even though we learned it. Monitor mode has ordered snapshots andIpMacObservationEntityalready links IP↔MAC across files — a hostname learned once could carry forward, ideally keyed by MAC rather than IP (IPs churn under DHCP; see #510).Acceptance Criteria
ConversationEntity.hostname) contribute to IP → hostname resolution, attached to the correct (destination) IP.SOURCE_PRIORITY, so they only fill gaps.SOURCE_*constant andHostnameSourceBadgetreatment, so users can see how a name was derived and judge it.HostnameResolverServicemust stay one tshark pass and never throw.Design questions
104.16.x.xaszoom.usis useful for triage but is not that machine's identity — one IP may serve hundreds of names. Do we label the node, or only list candidate names in NodeDetails? This is the core judgement call; getting it wrong makes the diagram confidently misleading, which is worse than a blank label.hostnameis a single column today. SNI naturally yields many names per server IP (NetworkIntelligenceServicealready collectssniNamesas a list). Does the model need IP → set of names with sources, with one chosen for display?HostnameResolverService(needs conversation data it doesn't currently see; it takes aFile), or a post-pass inAnalysisServiceafter nDPI has run? The latter is likely simpler:deviceOverrides/hostnamesare already threaded together there (AnalysisService:145-163).api.stripe.combeats34.x.x.x). For internal hosts it's usually noise. Should the source priority differ by whether the IP is private?Notes
Suggested sequencing:
tlsSubject).http.host— small additions to existing tshark passes.Worth noting for triage value: the existing priority model is well-designed and already does the hard part (conflict resolution with explicit authority ordering). Most of this issue is feeding it more inputs, not rebuilding it.
Related: #510 (MAC-grouped identity across snapshots — the natural key for hostname carry-forward), #501 (unknown protocols — hostname presence/absence is a triage signal), #509 (diagram rendering — hostnames are the label that makes a diagram readable), #499 (conflicting classification axes — hostname conflicts are a similar "sources disagree" problem).
Relevant files:
backend/src/main/java/com/tracepcap/analysis/service/HostnameResolverService.java:37-99(sources, priority, tshark filter)backend/src/main/java/com/tracepcap/analysis/service/NdpiService.java:69-70, 129(Hostname/SNI already extracted)backend/src/main/java/com/tracepcap/analysis/entity/ConversationEntity.java:80-96(hostname,tlsSubject,tlsIssuer)backend/src/main/java/com/tracepcap/analysis/service/AnalysisService.java:145-163(where hostnames are threaded into classification)backend/src/main/java/com/tracepcap/hostlog/service/WebServerLogExtractor.java(existing HTTP pass —http.hostcould join it)frontend/src/components/common/HostnameSourceBadge/HostnameSourceBadge.tsx