-
Notifications
You must be signed in to change notification settings - Fork 0
DNS Tunnel Suspicion
Added in: v1.30.0 Mode: Advisory-only (never bans or blocks) Default: Disabled
The DNS Tunnel Suspicion Module monitors DNS query logs for patterns that indicate DNS tunneling activity. It scores source IPs using 5 configurable signals and reports suspicion levels, but never takes enforcement action.
DNS tunneling tools (iodine, dnscat2, dns2tcp) encode data in DNS queries using high-entropy subdomain labels, excessive TXT records, and deep subdomain nesting. This module detects these patterns.
# Enable monitoring
sudo nftban tunnel enable
# Check status
nftban tunnel status
# Run immediate scan
sudo nftban tunnel scan
# View top suspects
nftban tunnel top
# Get signal breakdown for an IP
nftban tunnel explain 192.168.1.100DNS Logs (BIND/Unbound/dnsmasq/resolved)
│
▼
┌─────────────────────┐
│ DNS Log Parsers │ Auto-detect resolver, parse to normalized format
│ (4 parsers) │ Output: SOURCE_IP|QNAME|QTYPE|RCODE
└────────┬────────────┘
│
▼
┌─────────────────────┐
│ Signal Computation │ Per-IP: entropy, TXT ratio, depth, volume, NXDOMAIN
│ (single-pass awk) │ Output: signal values (colon-separated)
└────────┬────────────┘
│
▼
┌─────────────────────┐
│ Scoring Engine │ Normalize signals → weighted sum → composite score
│ (0-100 score) │ Levels: NONE / LOW / MEDIUM / HIGH
└────────┬────────────┘
│
▼
┌─────────────────────┐
│ State Management │ Per-IP state files in /var/lib/nftban/tunnel/
│ + Alerting │ Email alerts on HIGH (configurable cooldown)
└─────────────────────┘
| # | Signal | Default Weight | Default Threshold | Description |
|---|---|---|---|---|
| 1 | Label Entropy | 25% | 3.5 bits/char | Shannon entropy of subdomain labels. Encoded/encrypted data has entropy >4.0. Normal domains: 2.0-3.0. |
| 2 | TXT Frequency | 20% | 0.15 (15%) | Ratio of TXT queries to total. DNS tunnels use TXT for downstream data. Normal: <5%. |
| 3 | Subdomain Depth | 20% | 4 labels | Maximum nesting depth. Tunnels encode data in deeply nested labels (e.g., aGVsbG8.ZGF0YQ.tunnel.example.com). |
| 4 | Query Volume | 20% | 100 queries/interval | Total DNS queries per source IP per scan interval (5 min). Tunnels generate sustained high volume. |
| 5 | NXDOMAIN Ratio | 15% | 0.20 (20%) | Ratio of NXDOMAIN responses. Some tunnel tools generate queries for non-existent subdomains. |
Each signal is normalized to 0-100 using the formula:
normalized = min(100, (value / threshold) * 50)
At the threshold value, the normalized score is 50. At 2x the threshold, it reaches 100.
The composite score is:
score = (s1 * w1 + s2 * w2 + s3 * w3 + s4 * w4 + s5 * w5) / (w1 + w2 + w3 + w4 + w5)
| Level | Score Range | Meaning |
|---|---|---|
| NONE | 0-29 | No suspicious activity detected |
| LOW | 30-59 | Minor anomalies, likely benign |
| MEDIUM | 60-79 | Notable patterns, worth investigating |
| HIGH | 80-100 | Strong tunnel indicators, investigate immediately |
The module auto-detects the active DNS resolver and its log location.
| Resolver | Detection | Log Locations |
|---|---|---|
| BIND 9 |
named binary or named.service / bind9.service
|
/var/log/named/queries.log, /var/log/bind/query.log, extracted from named.conf
|
| Unbound |
unbound binary or unbound.service
|
/var/log/unbound/unbound.log, extracted from unbound.conf
|
| dnsmasq |
dnsmasq binary or dnsmasq.service
|
/var/log/dnsmasq.log, /var/log/syslog, /var/log/messages
|
| systemd-resolved | systemd-resolved.service |
journalctl -u systemd-resolved |
Override auto-detection via config:
NFTBAN_TUNNEL_DNS_SOURCE="bind" # Force specific resolver
NFTBAN_TUNNEL_BIND_LOG="/custom/path.log" # Override log pathnftban tunnel status # Full status display
nftban tunnel status --brief # One-line: ENABLED (H:0 M:0 L:0) dns=bind
nftban tunnel status --json # JSON outputsudo nftban tunnel enable # Persists to main.conf.local, starts timer
sudo nftban tunnel disable # Persists to main.conf.local, stops timersudo nftban tunnel scan # Interactive scan with output
sudo nftban tunnel scan --quiet # Timer mode (minimal output, logs to file)nftban tunnel top # Top 10 suspects
nftban tunnel top --limit 20 # Top 20
nftban tunnel top --json # JSON arraynftban tunnel explain 192.168.1.1 # Signal breakdown table
nftban tunnel explain 192.168.1.1 --json # JSON with per-signal detailsnftban tunnel config # Show all configuration
nftban tunnel config --json # JSON outputFile: /etc/nftban/conf.d/tunnel/main.conf
Override: /etc/nftban/conf.d/tunnel/main.conf.local
# Master switch (default: NO)
NFTBAN_TUNNEL_ENABLED="NO"
# Scan interval in minutes (default: 5)
NFTBAN_TUNNEL_SCAN_INTERVAL="5"
# DNS source: auto, bind, unbound, dnsmasq, resolved
NFTBAN_TUNNEL_DNS_SOURCE="auto"
# Suspicion level thresholds
NFTBAN_TUNNEL_THRESHOLD_LOW="30"
NFTBAN_TUNNEL_THRESHOLD_MEDIUM="60"
NFTBAN_TUNNEL_THRESHOLD_HIGH="80"
# Signal weights (must sum to 100)
NFTBAN_TUNNEL_WEIGHT_ENTROPY="25"
NFTBAN_TUNNEL_WEIGHT_TXT_FREQ="20"
NFTBAN_TUNNEL_WEIGHT_SUBDOMAIN_DEPTH="20"
NFTBAN_TUNNEL_WEIGHT_QUERY_VOLUME="20"
NFTBAN_TUNNEL_WEIGHT_NXDOMAIN_RATIO="15"
# Signal thresholds (midpoint of normalization)
NFTBAN_TUNNEL_ENTROPY_THRESHOLD="3.5"
NFTBAN_TUNNEL_TXT_RATIO_THRESHOLD="0.15"
NFTBAN_TUNNEL_SUBDOMAIN_DEPTH_THRESHOLD="4"
NFTBAN_TUNNEL_QUERY_VOLUME_THRESHOLD="100"
NFTBAN_TUNNEL_NXDOMAIN_RATIO_THRESHOLD="0.20"
# State management
NFTBAN_TUNNEL_STATE_TTL="24" # Hours before state expires
NFTBAN_TUNNEL_MAX_TRACKED_IPS="1000" # Max IPs to track
# Alerting
NFTBAN_TUNNEL_ALERT_ON_HIGH="YES"
NFTBAN_TUNNEL_ALERT_EMAIL="" # Falls back to NFTBAN_ALERT_EMAIL
NFTBAN_TUNNEL_ALERT_COOLDOWN="3600" # Seconds between alerts
# Exclusions
NFTBAN_TUNNEL_EXCLUDE_DOMAINS="" # Comma-separated, glob patterns
NFTBAN_TUNNEL_EXCLUDE_IPS="" # Comma-separated, exact match| Unit | Type | Description |
|---|---|---|
nftban-tunnel.timer |
Timer | Triggers scan every 5 minutes (30s jitter) |
nftban-tunnel.service |
Oneshot | Runs nftban tunnel scan --quiet
|
The service runs as root with security hardening: NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp, MemoryMax=256M.
State is stored per-IP in /var/lib/nftban/tunnel/:
/var/lib/nftban/tunnel/
192.168.1.100.state # IPv4
2001_db8__1.state # IPv6 (colons replaced with underscores)
.last_alert # Alert cooldown timestamp
Each .state file contains: TIMESTAMP|SCORE|LEVEL|SIGNALS
State files expire after NFTBAN_TUNNEL_STATE_TTL hours (default: 24).
Location: /var/log/nftban/tunnel.log
Rotation: Managed by logrotate (weekly, 4 copies, compress)
Log format:
2026-03-21 14:30:00|HIGH|ip=192.168.1.100 score=87 signals=4.21:0.35:6:450:0.12
2026-03-21 14:30:00|INFO|Scan complete — 1523 queries, 12 IPs scored, HIGH=1 MED=2 LOW=3
- No timestamp filtering in BIND/Unbound/dnsmasq parsers — entire log file is parsed each scan. With logrotate this is acceptable. Full filtering planned for v1.31+.
- IP exclusions are exact match only — CIDR notation not yet supported.
- systemd-resolved parser is best-effort — resolved logging format is not standardized.
- Advisory-only — no enforcement mode. Planned for future release.
- CLI Commands Reference — Full command reference
- Security Operations Guide — Security hardening and monitoring
- Timer Schedule — Systemd timer architecture
- Health Check Architecture — Health check integration
NFTBan Wiki
Getting Started
Architecture
Modules
- BotGuard (HTTP L7)
- DDoS Protection (L3/L4)
- Portscan Detection
- Login Monitoring
- Blacklist & Threat Intelligence
- Suricata IDS Integration
- DNS Tunnel Suspicion
Operator Reference
- CLI Commands Reference
- Configuration Reference
- Systemd Units & Timers
- Optimization & Tuning
- Security Operations Guide
- GeoIP Database Guide
- FHS Compliance
- Troubleshooting: Smoke & Selftest
Verification & Trust
- Glossary & Vocabulary
- Known Limitations
- Metrics & Evidence Model
- Binary Verification (SLSA)
- Security Architecture
Reference
Legal