Ottimizzazione delle prestazioni, temporizzazione e scansione su larga scala

Template di Timing: Oltre il "Basta usare -T4"

I sei template di timing di Nmap (-T0 fino a -T5) sono spesso trattati come un cursore di velocità lineare, ma ciascuno modifica quattro variabili indipendenti con effetti non lineari. Comprendere la meccanica dietro questi preset è essenziale per l'ingegneria delle prestazioni.

| Template | Timeout RTT | Probe Paralleli | Ritardo Scansione | Tentativi Max | |----------|-------------|-----------------|-------------------|---------------| | -T0 (Paranoid) | 5 min | 1 alla volta | 5 min | 20 | | -T1 (Sneaky) | 15 sec | 1 alla volta | 15 sec | 20 | | -T2 (Polite) | 1 sec | 1 alla volta | 400 ms | 10 | | -T3 (Normal) | Dinamico | Dinamico | 0 | 10 | | -T4 (Aggressive) | Dinamico | Dinamico | 0 | 6 | | -T5 (Insane) | 75 ms | Dinamico | 0 | 2 |

La distinzione critica risiede nel fatto che -T0 fino a -T2 impongono trasmissione seriale dei probe (un probe attivo per host), mentre -T3 fino a -T5 abilitano il parallelismo. A -T4 e -T5, gli algoritmi adattivi di Nmap si attivano aggressivamente, ma -T5 limita il timeout RTT iniziale a 75 ms indipendentemente dalle condizioni di rete misurate—una ricetta per massicce ritrasmissioni su percorsi con latenza.

Cosa controlla effettivamente ciascuna variabile:

  • Timeout RTT: Attesa massima per la risposta del probe prima della ritrasmissione. Il calcolo dinamico utilizza smoothing esponenziale con timeout derivati dai tempi di andata e ritorno osservati.
  • Probe paralleli: Probe in sospeso per host, per fase di scansione. Valori più alti sfruttano il pipelining di rete ma aumentano la pressione sulla tabella di stato dell'host che esegue la scansione.
  • Ritardo scansione: usleep() esplicito tra batch di probe. Sconfigge il riconoscimento di pattern negli IDS ma limita linearmente il throughput.
  • Tentativi max: Limite massimo di ritrasmissione. Ogni tentativo raddoppia l'esposizione effettiva al timeout per quella porta.

Algoritmi di Timing Adattivo: La Congestion Window di Nmap

Nmap implementa un meccanismo simile alla congestion window per la gestione dei probe, concettualmente preso in prestito dal TCP ma adattato per tipi di scansione stateless e stateful. Il motore mantiene:

current_rate = min(slow_start_ceiling, network_capacity_estimate, user_max_rate)

L'algoritmo risponde a tre segnali di congestione:

  1. Tasso di arrivo delle risposte: ACK positivi aumentano la finestra dei probe moltiplicativamente (slow start) poi additivamente (congestion avoidance)
  2. Accumulo di timeout: Risposte mancanti attivano il backoff esponenziale dei valori di timeout per host
  3. ICMP source quench/admin prohibited: Feedback di rete esplicito riduce il tasso del 50% e registra l'evento

Per le scansioni SYN, Nmap traccia uno stato di timing separato per gruppo di host, non per singola destinazione. Questa aggregazione abilita un'efficiente parallelizzazione ma significa che un singolo rispondente lento in un gruppo limita l'intero batch. Il sorgente nmamng.h rivela la struttura dati fondamentale: struct timeout_info memorizza srtt (RTT smoothed), rttvar (varianza), e timeout (soglia di ritrasmissione calcolata).

L'insight critico: l'adattamento di Nmap è reattivo, non predittivo. Non può anticipare i cambiamenti della topologia di rete o i pattern di congestione legati all'orario. Per scansioni programmate su percorsi variabili, pre-inizializzare con --initial-rtt-timeout basato su misurazioni nping precedenti piuttosto che affidarsi all'apprendimento nella fase di discovery.

Dimensionamento dei Gruppi di Host e Interazione delle Fasi Parallele

Nmap organizza i target in gruppi di host processati attraverso fasi di scansione parallele. Il dimensionamento predefinito del gruppo segue questa progressione: inizia a 5 host, cresce fino a 1024 per set di target grandi. Il controllo manuale sovrascrive questo:

# Ottimizza per segmento datacenter omogeneo a bassa latenza
nmap --min-hostgroup 256 --max-hostgroup 512 -T4 10.0.0.0/20

# Serializza per WAN eterogenea con latenza mista
nmap --min-hostgroup 1 --max-hostgroup 8 -T3 --max-rtt-timeout 2s targets.txt

Il dimensionamento del gruppo interagisce criticamente con le fasi di scansione:

| Fase | Comportamento del Gruppo | Impatto del Tuning | |------|--------------------------|--------------------| | Host discovery (ping) | ICMP/TCP/ACK paralleli attraverso il gruppo | Gruppi grandi saturano l'uplink; gruppi piccoli sottoutilizzano la banda | | Port scanning | Macchine a stati per host, timing a livello di gruppo | Gruppi sovradimensionati ritardano la generazione dei report; gruppi sottodimensionati perdono parallelismo | | OS detection/version probe | Fallback sequenziale, risultati bufferizzati per gruppo | Il dimensionamento fisso qui può causare pressione di memoria con -O e -sV combinati | | Traceroute | Esecuzione individuale, effetto gruppo minimo | Impatto prestazionale trascurabile |

Il motore di scansione intreccia le fasi attraverso i gruppi piuttosto che completare tutte le fasi per gruppo sequenzialmente. Questo parallelismo a pipeline significa che i vincoli di --max-hostgroup durante la port scanning si propagano alla schedulazione del version detection anche se i probe di versione stessi beneficerebbero di un raggruppamento diverso.

Strategie di Timeout RTT: Il Tradeoff Statico-Dinamico

Il calcolo dinamico predefinito del timeout di Nmap utilizza:

timeout = srtt + (rttvar × 4)

Questo rispecchia il calcolo RTO del TCP ma con un moltiplicatore di varianza maggiore, appropriato per le caratteristiche di perdita più elevate del traffico di scansione.

I timeout statici (--initial-rtt-timeout, --max-rtt-timeout) sono necessari quando:

  • L'infrastruttura target applica rate-limiting con finestre fisse
  • Percorsi satellite o cellulari presentano distribuzioni di latenza bimodali
  • Scansione attraverso Tor o catene di proxy con pavimenti di latenza artificiale

Il pericolo di valori statici eccessivi si manifesta in questa stima della durata per una scansione TCP SYN completa:

Durata Stimata ≈ (hosts × ports × timeout × retry_factor) / parallel_probes

Dove retry_factor = 1 + (retry_probability × max_retries)

Per 65.536 host, 1.000 porte, timeout 2s, perdita 10%, 3 tentativi:

  • Dinamico (effettivo medio 150ms): ~36 ore
  • Timeout statico 5s: ~379 ore (16 giorni)

Approccio consigliato: Inizializzare con --initial-rtt-timeout 500ms --max-rtt-timeout 2s, permettendo adattamento verso il basso ma limitando l'esplosione verso l'alto.

Controllo del Tasso di Pacchetti e Interazione di Rete

--max-rate e --min-rate operano a livello globale di iniezione di pacchetti, attraverso tutti gli host e le fasi:

# Mantiene 1.000 pacchetti/secondo indipendentemente dalla reattività
nmap --min-rate 1000 --max-rate 1000 -p- target

# Limita per evitare il policing QoS upstream a 10 Mbps per probe da 64 byte
# 10.000.000 / (64 × 8) ≈ 19.531 pacchetti/sec massimo teorico
# Pratico: considera l'overhead Ethernet, usa 15.000
nmap --max-rate 15000 10.0.0.0/16

Interazione con elementi di rete:

| Controllo | Effetto QoS | Evasione IDS | |-----------|-------------|--------------| | --max-rate | Previene drop di coda a tassi policed | Crea pattern prevedibile (negativo) | | --min-rate | Sovrascrive segnali di congestione, causa perdita | Forza baseline di attività costante | | Tasso fisso combinato | Neutrale per QoS, rilevabile | Firma temporale banale |

Per l'evasione delle soglie IDS, il rate limiting variabile attraverso shaping del traffico esterno (Linux tc, BSD dummynet) supera i controlli nativi di Nmap. Il parametro --max-rate dovrebbe essere trattato come uno strumento di limitazione dei danni, non un meccanismo di evasione.

Sconfiggere i Rate Limit su Reti Pesantemente Filtrate

Firewall e stack OS implementano sempre più rate limiting delle risposte. Il net.ipv4.icmp_ratelimit di Linux e controlli simili generano silenzio ambiguo indistinguibile dalle porte filtrate. Nmap fornisce due switch di override:

| Switch | Meccanismo Target | Conseguenza | |--------|-------------------|-------------| | --defeat-rst-ratelimit | Generazione RST dello stack TCP OS | Assume SYN senza risposta = open/filtered, non closed | | --defeat-icmp-ratelimit | Generazione ICMP unreachable del firewall | Tratta il silenzio da rate limit ICMP come open/filtered |

Questi sono flag di riduzione dell'accuratezza, non ottimizzazioni delle prestazioni. Caso d'uso: scansione attraverso un firewall Palo Alto con limite predefinito di 100 ICMP/secondo verso 10.000 host. Senza il flag, il 99% delle porte appare filtered a causa di ICMP unreachables scartati; con il flag, i risultati si aggiornano a open|filtered, richiedendo follow-up con probe a livello applicazione.

Esempio di comando per egress datacenter con rate limit:

nmap -sS -Pn -p- --defeat-rst-ratelimit --defeat-icmp-ratelimit \
     --max-rate 5000 --max-retries 2 \
     --min-hostgroup 64 --max-hostgroup 256 \
     -T4 -oA mass_scan_dc1 10.64.0.0/14

L'Equilibrio dei Max-Retries

La strategia di ritrasmissione presenta un problema di ottimizzazione bimodale:

Costo Accuratezza(bassi retries) = tasso_perdita_porte_aperte × valore_target
Costo Tempo(alti retries) = target_filtrati × porte × timeout × somma(ritardi_retry)

Per una rete /8 (16,7M host) con densità host effettiva del 5% e tasso porte aperte del 2% per host rispondente:

| --max-retries | Tempo di Completamento | Porte Aperte Perse (perdita 1%) | |-----------------|------------------------|--------------------------------| | 0 | 4,2 ore | 50.400 | | 2 | 12,6 ore | 5.040 | | 6 | 29,4 ore | 504 | | 10 | 46,2 ore | 50 |

La formula rilevante per il business per la selezione dei retry:

optimal_retries = argmin_retries[
    (costo_falso_negativo × opportunita_perse(retries)) +
    (valore_tempo × durata(retries))
]

Per vulnerability management con finestre di scansione di 4 ore e costo incidente di $50K/ora: --max-retries 2. Per baseline di compliance con finestre di 72 ore e $2M per critico mancato: --max-retries 6 con --max-rtt-timeout 3s.

Scansione di Reti /8: Ingegneria per la Scala

La scansione di 16.777.216 indirizzi richiede decisioni architetturali oltre i parametri di Nmap:

Memoria per host (scansione SYN, default): ~220 byte
Memoria /8 a dimensionamento gruppo completo: 3,7 GB
Raccomandato: shard in chunk /16 con orchestrazione esterna

Esecuzione pratica /8:

# Fase 1: Host discovery con stato minimo
nmap -sn -T4 --min-parallelism 100 --max-parallelism 500 \
     --max-rtt-timeout 2s --max-retries 1 \
     --max-rate 100000 -oG alive.gnmap 10.0.0.0/8

# Fase 2: Estrai host rispondenti, port scan con piena accuratezza
grep "Up" alive.gnmap | awk '{print $2}' > alive.txt
nmap -sS -sV -O -p- -T4 --max-retries 3 \
     --max-rtt-timeout 5s --min-hostgroup 64 \
     -iL alive.txt -oA full_detail

Questo approccio a due fasi riduce la memoria di stato del 95%+ ed evita l'accumulo catastrofico di timeout dalla probe di 15,9M indirizzi non rispondenti.

Formule di Stima della Durata

Per la pianificazione delle finestre di scansione:

Durata Scansione SYN (secondi) ≈
    (N_hosts × N_ports × T_rtt) / (P_parallel × G_groups)
    + N_hosts × T_overhead_per_host

Dove:
    P_parallel = probe_in_volo_per_host (dipendente dal template)
    G_groups = gruppi_host_attivi (limitato da --max-hostgroup)
    T_overhead = DNS, ARP, generazione report ≈ 50-200ms/host

Per la scansione UDP, moltiplicare per retry_factor × 2 (timeout default più alto) e dividere P_parallel per 3-5 (più lento rate limiting del kernel su socket UDP non privilegiati).

La checklist completa dell'ingegnere delle prestazioni:

  1. Caratterizzare la distribuzione RTT del percorso con nping --tcp -p 80 --count 1000
  2. Impostare --initial-rtt-timeout al P90 della distribuzione misurata
  3. Dimensionare --max-hostgroup per corrispondere all'omogeneità della rete target
  4. Applicare --max-rate all'80% del throughput osservato senza drop
  5. Selezionare --max-retries basato sul modello di costo dei falsi negativi
  6. Per /16+, implementare discovery a due fasi prima della scansione approfondita