nmap-option-conflicts
05 — Nmap Option Conflicts
1. BLUF (Bottom Line Up Front)
Nmap's specific timing options (--scan-delay, --max-retries, --max-rtt-timeout, etc.) always override their corresponding -T template values, regardless of command-line argument order. This was verified by source code analysis (nmap.cc:470-498) and confirmed empirically with 16/16 tests passing (nmap 7.97, Docker lab, 2026-02-24). Using -T alongside specific options is not redundant — -T still sets all timing parameters you don't explicitly override.
2. Architecture
graph TB
subgraph "Phase 1: Argument Parsing"
CLI["nmap -T2 --scan-delay 5s --max-retries 1 -p 22,80"]
T["-T2 template applied
scan-delay=400ms
max-retries=10
RTT timeouts=conservative"]
D1["delayed_options stored
scan-delay=5000ms"]
D2["delayed_options stored
max-retries=1"]
end
subgraph "Phase 2: delayed_options Override"
Final["Final timing config:
scan-delay=5000ms ✅ (from --scan-delay)
max-retries=1 ✅ (from --max-retries)
RTT timeouts=conservative ✅ (from -T2)"]
end
CLI --> T
CLI --> D1
CLI --> D2
T --> Final
D1 -->|"overrides scan-delay"| Final
D2 -->|"overrides max-retries"| Final
style D1 fill:#ccffcc
style D2 fill:#ccffcc
style T fill:#ffe1e1Source reference: nmap.cc:470-498 — comment reads: "these always take precedence over the templates"
3. Tools, Techniques, Procedures (TTPs)
| TTP | Description |
|---|---|
| Two-phase parsing | nmap applies -T immediately, then overwrites with delayed_options post-parse |
| Stealth tuning | Use -T1 or -T2 for RTT/retry baseline + explicit --scan-delay for probe rate |
| Verification | Run nmap -d and read the timing report block to confirm active values |
| scan-delay nullification | --scan-delay silently kills --max-parallelism and --min-parallelism |
4. Walkthrough Summary
- Hypothesis: The common belief that
-Toverrides--scan-delay(or vice versa based on argument order) is wrong. - Method: Read nmap source, identified the
delayed_optionsmechanism, built a Docker lab, ran 16 controlled tests across 8 option groups. - Result: All 16 tests confirmed specific options always win. Argument order is irrelevant.
-Tand specific options are complementary, not conflicting.
5. Detailed Step-by-Step
-T0–-T5 Timing Templates
| Template | Name | Scan Delay | Max Parallelism | Max Retries |
|---|---|---|---|---|
-T0 | Paranoid | 5 min (300s) | 1 | 10 |
-T1 | Sneaky | 15s | 1 | 10 |
-T2 | Polite | 400ms | 1 | 10 |
-T3 | Normal | Default | Default | 10 |
-T4 | Aggressive | Fast RTT | Default | 6 |
-T5 | Insane | Fastest | Default | 2 |
The delayed_options Mechanism
- Phase 1:
-Tvalues are set immediately as each argument is parsed - Phase 2:
delayed_options(specific per-option overrides) are applied after all arguments are fully parsed — they always win
This means -T2 --scan-delay 5s and --scan-delay 5s -T2 behave identically.
Test Lab Setup
Two Docker containers on an isolated bridge network (internal: true):
scanner: Alpine Linux + nmap 7.97 (aarch64)target: Ubuntu 22.04 + socat listeners on ports 21, 22, 80, 443, 8080, 3306
All 6 ports confirmed open with near-zero latency (~0.000015s). Verification: nmap -d timing report as ground truth.
Test Results (16/16 PASS)
| Group | Test | Command | Expected | Result |
|---|---|---|---|---|
| A | scan-delay vs -T2 (T first) | -T2 --scan-delay 5s -p 22,80 | --scan-delay | ✅ PASS |
| A | scan-delay vs -T2 (specific first) | --scan-delay 5s -T2 -p 22,80 | --scan-delay | ✅ PASS |
| A | scan-delay 1s vs -T1 (15s) | -T1 --scan-delay 1s -p 22 | --scan-delay | ✅ PASS |
| A | scan-delay 1s vs -T0 (300s) | -T0 --scan-delay 1s -p 22 | --scan-delay | ✅ PASS |
| B | max-scan-delay 500ms vs -T4 | -T4 --max-scan-delay 500ms | --max-scan-delay | ✅ PASS |
| B | max-scan-delay 50ms vs -T5 | -T5 --max-scan-delay 50ms | --max-scan-delay | ✅ PASS |
| C | max-retries 1 vs -T4 | -T4 --max-retries 1 | --max-retries | ✅ PASS |
| C | max-retries 10 vs -T1 | -T1 --max-retries 10 | --max-retries | ✅ PASS |
| D | host-timeout 30s vs -T5 | -T5 --host-timeout 30s | --host-timeout | ✅ PASS |
| E | rtt-timeout vs -T4 | -T4 --max-rtt-timeout 2000ms | --rtt-timeout | ✅ PASS |
| E | initial-rtt-timeout vs -T1 | -T1 --initial-rtt-timeout 500ms | --initial-rtt-timeout | ✅ PASS |
| F | max-parallelism 1 vs -T4 | -T4 --max-parallelism 1 | --max-parallelism | ✅ PASS |
| G | scan-delay nullifies max-parallel | --scan-delay 1s --max-parallelism 10 | WARNING | ✅ PASS |
| G | scan-delay nullifies min-parallel | --min-parallelism 5 --scan-delay 500ms | WARNING | ✅ PASS |
| H | min-rate with -T1 | -T1 --min-rate 100 | coexist | ✅ PASS |
| H | max-rate with -T4 | -T4 --max-rate 10 | coexist | ✅ PASS |
Run: 2026-02-24, nmap 7.97 (Alpine Linux aarch64), Docker isolated bridge network.
Why Use -T and --scan-delay Together?
--scan-delay only overrides the delay component. -T still sets:
What -T still controls | Example with -T1 |
|---|---|
--max-rtt-timeout | 15,000 ms (conservative) |
--initial-rtt-timeout | 15,000 ms |
--max-parallelism | 1 (serial probing) |
So -T1 --scan-delay 60s means: "Use T1's conservative RTT/parallelism baseline, but slow the probe rate to 60s." Removing -T1 would default to -T3 (Normal), which has more aggressive RTT timeouts — less stealthy.
6. Commands Used
# Docker lab setup
docker exec scanner nmap -T2 --scan-delay 5s -p 22,80 target
docker exec scanner nmap --scan-delay 5s -T2 -p 22,80 target
docker exec scanner nmap -T1 --scan-delay 1s -p 22 target
docker exec scanner nmap -T0 --scan-delay 1s -p 22 target
docker exec scanner nmap -T4 --max-scan-delay 500ms -p 22,80 target
docker exec scanner nmap -T5 --max-scan-delay 50ms -p 22,80 target
docker exec scanner nmap -T4 --max-retries 1 -p 22,80 target
docker exec scanner nmap -T1 --max-retries 10 -p 22,80 target
docker exec scanner nmap -T5 --host-timeout 30s -p 22,80 target
docker exec scanner nmap -T4 --min-rtt-timeout 200ms --max-rtt-timeout 2000ms target
docker exec scanner nmap -T1 --initial-rtt-timeout 500ms -p 22,80 target
docker exec scanner nmap -T4 --max-parallelism 1 -p 22,80,21,443 target
docker exec scanner nmap --scan-delay 1s --max-parallelism 10 -p 22,80 target
docker exec scanner nmap --min-parallelism 5 --scan-delay 500ms -p 22,80 target
docker exec scanner nmap -T1 --min-rate 100 -p 22,80 target
docker exec scanner nmap -T4 --max-rate 10 -p 22,80 target
# Verify timing values with debug output
docker exec scanner nmap -d -T2 --scan-delay 5s -p 22,80 target
7. Issues, Fixes, and Troubleshooting
| Issue | Resolution |
|---|---|
--scan-delay with --max-parallelism | Parallelism is silently dropped — nmap prints a warning but still scans. Do not combine expecting both to apply. |
| Verifying which values actually took effect | Use nmap -d and read the timing report block — this is ground truth, more reliable than observing elapsed time. |
--min-rate / --max-rate confusion | These are NOT delayed_options — they coexist with -T without conflict. They control packet rate, not probe delay. |
| Thinking argument order matters | It never matters for delayed_options. -T2 --scan-delay 5s ≡ --scan-delay 5s -T2. |
8. Final Notes
Option Override Reference
| Option | Controls | Overrides -T? |
|---|---|---|
--scan-delay | Minimum time between probes (ms) | YES |
--max-scan-delay | Maximum adaptive scan delay | YES |
--max-parallelism | Maximum parallel outstanding probes | YES |
--max-retries | Maximum probe retransmissions | YES |
--host-timeout | Total time budget per host | YES |
--min-rtt-timeout | Minimum RTT estimate | YES |
--max-rtt-timeout | Maximum RTT estimate | YES |
--initial-rtt-timeout | Initial RTT estimate | YES |
--min-rate | Minimum packets per second | NO (independent) |
--max-rate | Maximum packets per second | NO (independent) |
Common Mistakes
- ❌ "I put
-T4last so it'll override--max-retries" — FALSE. Order never matters. - ❌ Combining
--scan-delaywith--max-parallelism— parallelism is silently dropped. - ❌ Thinking
--min-ratebehaves like--scan-delay— they're independent systems. - ❌ Using
-T0for stealth without knowing its defaults — T0 = 300s delay + 1 parallel. Use--scan-delaydirectly for explicit control. - ✅ Safe stealth pattern:
-T1 --scan-delay 60s --max-retries 0 --max-rate 1— T1's conservative RTT baseline + explicit probe rate control.
OPSEC Quick Reference
-T2 --scan-delay 5s→ safe,--scan-delaycontrols probe rate,-T2sets RTT/parallelism-T4 --scan-delay 500ms→ keeps T4's fast RTT/retry + slower probe rate for IDS evasion- ARP ping also respects
--scan-delay— budget for extra probes in elapsed time - Always verify with
nmap -dbefore long stealth scans