182 lines
4.7 KiB
Markdown
182 lines
4.7 KiB
Markdown
# DNS Leak Detector - Implementation Guide (v0.4)
|
|
|
|
This document explains how to implement the DNS leak detector as a new subcrate in WTFnet.
|
|
|
|
## 1) New crate: `wtfnet-dnsleak`
|
|
|
|
### 1.1 Module layout
|
|
|
|
crates/wtfnet-dnsleak/src/
|
|
- lib.rs
|
|
- policy.rs # safe path constraints + presets
|
|
- sensor.rs # passive capture -> normalized TrafficEvent stream
|
|
- classify.rs # transport classification + confidence
|
|
- route.rs # interface/route classification (tunnel/physical/loopback)
|
|
- rules.rs # Leak-A/B/C/D evaluation
|
|
- report.rs # LeakEvent + SummaryReport builders
|
|
- privacy.rs # full/redacted/minimal redaction logic
|
|
|
|
## 2) Core data types
|
|
|
|
### 2.1 TrafficEvent (raw from sensor)
|
|
Fields:
|
|
- ts: timestamp
|
|
- proto: udp/tcp
|
|
- src_ip, src_port
|
|
- dst_ip, dst_port
|
|
- iface_name (capture interface if known)
|
|
- payload: optional bytes (only for plaintext DNS parsing)
|
|
|
|
### 2.2 ClassifiedEvent
|
|
Adds:
|
|
- transport: udp53/tcp53/dot/doh/unknown
|
|
- doh_confidence: HIGH/MEDIUM/LOW (only if doh)
|
|
- qname/qtype: nullable
|
|
|
|
### 2.3 EnrichedEvent
|
|
Adds:
|
|
- route_class: loopback/tunnel/physical/unknown
|
|
- process info: pid/ppid/name (nullable)
|
|
- attribution_confidence: HIGH/MEDIUM/LOW/NONE
|
|
- attrib_failure_reason: optional string
|
|
|
|
### 2.4 LeakEvent (final output)
|
|
Adds:
|
|
- leak_type: A/B/C/D
|
|
- severity: P0..P3
|
|
- policy_rule_id
|
|
- evidence: minimal structured evidence
|
|
|
|
## 3) Platform integration: Process Attribution Engine (PAE)
|
|
|
|
### 3.1 Trait addition (wtfnet-platform)
|
|
|
|
Add:
|
|
trait FlowOwnerProvider {
|
|
fn owner_of(
|
|
&self,
|
|
proto: Proto,
|
|
src_ip: IpAddr,
|
|
src_port: u16,
|
|
dst_ip: IpAddr,
|
|
dst_port: u16,
|
|
) -> FlowOwnerResult;
|
|
}
|
|
|
|
FlowOwnerResult:
|
|
- pid, ppid, process_name (optional)
|
|
- confidence: HIGH/MEDIUM/LOW/NONE
|
|
- failure_reason: optional string
|
|
|
|
Design rule: attribution is best-effort and never blocks leak detection.
|
|
|
|
## 4) Transport classification logic
|
|
|
|
### 4.1 Plain DNS
|
|
Match:
|
|
- UDP dst port 53 OR TCP dst port 53
|
|
Parse QNAME/QTYPE from payload.
|
|
|
|
### 4.2 DoT
|
|
Match:
|
|
- TCP dst port 853
|
|
|
|
### 4.3 DoH (heuristic)
|
|
Match candidates:
|
|
- TCP dst port 443 AND (one of):
|
|
- dst IP in configured DoH resolver list
|
|
- dst SNI matches known DoH provider list (if available)
|
|
- frequent small HTTPS bursts pattern (weak)
|
|
|
|
Attach confidence:
|
|
- MEDIUM: known endpoint match
|
|
- LOW: traffic-shape heuristic only
|
|
|
|
## 5) Policy model
|
|
|
|
Policy defines "safe DNS path" constraints:
|
|
- allowed interfaces
|
|
- allowed destinations (IP/CIDR)
|
|
- allowed processes
|
|
- allowed ports
|
|
|
|
A DNS event is a leak if it violates safe-path constraints.
|
|
|
|
### 5.1 Built-in profiles
|
|
|
|
full-tunnel:
|
|
- allow DNS only via tunnel iface or loopback stub
|
|
- any UDP/TCP 53 on physical iface => Leak-A
|
|
|
|
proxy-stub (default):
|
|
- allow DNS only to loopback stub
|
|
- allow stub upstream only to proxy destinations
|
|
- flag direct DoH/DoT outside proxy path => Leak-C
|
|
|
|
split:
|
|
- allow plaintext DNS only for allowlist
|
|
- enforce unknown => proxy resolve (Leak-B)
|
|
|
|
## 6) Leak rules (A/B/C/D)
|
|
|
|
Leak-A (plaintext escape):
|
|
- transport udp53/tcp53
|
|
- route_class != allowed
|
|
- dst not in allowed destination set
|
|
|
|
Leak-B (split policy intent leak):
|
|
- qname matches proxy-required set or "unknown"
|
|
- query observed going to ISP/domicile resolver or non-tunnel iface
|
|
|
|
Leak-C (encrypted bypass):
|
|
- DoT or DoH flow exists
|
|
- not via approved egress path (iface/destination)
|
|
|
|
Leak-D (mismatch indicator):
|
|
- correlate qname to later TCP/TLS flows (optional v0.4 NICE)
|
|
|
|
## 7) Privacy modes
|
|
|
|
Because domains and cmdlines are sensitive, support:
|
|
- Full: store full qname and cmdline
|
|
- Redacted (default): hash qname or keep eTLD+1 only; truncate cmdline
|
|
- Minimal: no domains/cmdline; keep leak counts + resolver IPs + process name
|
|
|
|
Privacy mode applies in report builder, not in sensor.
|
|
|
|
## 8) CLI integration
|
|
|
|
Add under `dns` command group:
|
|
|
|
- `dns leak status`
|
|
- `dns leak watch`
|
|
- `dns leak report`
|
|
|
|
`watch` returns:
|
|
- summary report (human) by default
|
|
- `--json` returns structured report with events list
|
|
|
|
`--follow` keeps the watch running by resolving the duration to a large
|
|
placeholder (one year in milliseconds) and then racing the watch against
|
|
`tokio::signal::ctrl_c()`; Ctrl-C returns early with a clean exit code so the
|
|
outer loop stops.
|
|
|
|
## 9) Recommended incremental build plan
|
|
|
|
Phase 1 (core passive detection):
|
|
- sensor: udp/tcp capture
|
|
- classify: udp53/tcp53/dot
|
|
- parse plaintext qname/qtype
|
|
- policy: allowlist + allowed interfaces/dests
|
|
- leak rules: Leak-A + Leak-C (DoT)
|
|
- report: events + summary
|
|
|
|
Phase 2 (process attribution + DoH heuristics):
|
|
- platform FlowOwnerProvider impls
|
|
- DoH heuristic classification + confidence
|
|
- privacy modes
|
|
|
|
Phase 3 (optional correlation / Leak-D):
|
|
- flow tracker correlating DNS -> TCP/TLS connect events
|
|
- mismatch indicator output
|