Raggiungere una /24 remota attraverso un tunnel: NETMAP, DNAT o route?
Mappare un intero prefisso con NETMAP, aggiungere regole DNAT per host o instradare l'intervallo reale, e decidere in base a ciò che il lato remoto deve vedere e a chi può avviare il traffico.
Puoi raggiungere una sottorete dietro un endpoint del tunnel in tre modi, e un minuto di raccolta di fatti di solito ne esclude due. I fatti sono se i server dall'altra parte devono distinguere gli utenti, se qualcuno là farà mai una connessione verso il tuo intervallo, e chi può modificare il router remoto. Rispondi a queste tre domande e il progetto si sceglie da solo. Il resto presuppone che tu gestisca l'endpoint e possa modificarne il firewall.
Tre opzioni, e cosa cambia davvero ciascuna
La mappatura dei prefissi, il DNAT per host e un prefisso instradato spostano tutti i pacchetti tra gli stessi due intervalli, ma cambiano cose diverse. La mappatura inventa un intervallo alias e riscrive gli indirizzi aritmeticamente in volo. Anche le regole per host riscrivono, solo che ogni destinazione è indicata a mano. Un prefisso instradato non riscrive nulla: i pacchetti mantengono gli indirizzi reali ed entrambe le estremità concordano su dove vivono quegli indirizzi.
| What the far side needs | Prefix mapping | Per-host DNAT | Routed prefix |
|---|---|---|---|
| Users visible to its logs | Only without source NAT | Same condition | Yes, unchanged |
| To start a connection toward you | No, alias is local | No, same reason | Yes, both ends route |
| To absorb a new host | Yes, arithmetic only | No, one rule per address | Yes, it simply routes |
| To require no config change | Yes, with source NAT | Yes, same condition | No, it needs a route back |
Inizia l'eliminazione dal lato remoto, dove i vincoli sono più difficili da cambiare. Se un server laggiù scrive gli indirizzi dei client nei log, li verifica rispetto a una allowlist o li passa a un altro sistema, tradurre la sorgente distrugge il suo unico identificatore. Se il lato remoto deve anche connettersi in entrata, la traduzione è del tutto esclusa, perché laggiù nessuno sa che l'alias esiste. Solo quando il lato remoto si limita a rispondere alle richieste le opzioni più economiche diventano sicure.
Coppie di prefissi, e perché le dimensioni devono combaciare
NETMAP è un target della tabella nat che lavora su una coppia di prefissi di lunghezza identica. Non ha una tabella per indirizzo al suo interno: rimuove il prefisso, conserva i bit host e li riattacca al nuovo prefisso, ed è per questo che una /24 si mappa su una /24 e mai su una /25. La posizione decide la direzione: una corrispondenza di destinazione in PREROUTING riscrive dove sta andando un pacchetto, e una corrispondenza di sorgente in POSTROUTING riscrive da dove è arrivato.
Un host su 192.168.2.17 appare ai tuoi client come 10.50.1.17, e l'ultimo ottetto non è decorativo — è lo stesso numero su entrambi i lati. Aggiungi domani un host su 192.168.2.40 e il suo alias è 10.50.1.40, senza nessuna regola da modificare.
I client hanno comunque bisogno di una route per l'intervallo alias che punti al tuo apparato, a meno che l'alias non cada in una sottorete già raggiungibile. Il gateway non ha bisogno di una route per l'alias, perché la traduzione di destinazione avviene in PREROUTING, prima della ricerca della route. Anche l'inoltro deve essere attivo, altrimenti il kernel scarta il pacchetto dopo la riscrittura. I tre comandi qui sotto sono l'intera configurazione su un gateway in stile Debian con i client su br0, l'alias su 10.50.1.0/24 e il tunnel su tun0.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -i br0 -d 10.50.1.0/24 -j NETMAP --to 192.168.2.0/24
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADELa risposta deve trovare da sola la via di ritorno
Riscrivere la destinazione decide solo dove un pacchetto viene consegnato. Il server remoto deve comunque rispondere a un indirizzo che riesce a raggiungere, e ci sono due modi per organizzarlo. Traduci la sorgente in modo che le risposte tornino al tuo apparato, oppure lascia stare la sorgente e dai al lato remoto una route per l'intervallo dei client.
Il masquerading in uscita è la strada più breve: una regola in POSTROUTING e il lato remoto vede il tuo indirizzo del tunnel, quindi non ha bisogno di una route propria. Il costo è che ogni utente collassa in un solo indirizzo, e i log per utente smettono di significare qualcosa. Lasciare intatta la sorgente conserva quell'informazione, ma il sito remoto deve allora rimandare le risposte per l'intervallo dei client attraverso il tunnel. Su un OpenVPN server è un push "route 10.50.9.0 255.255.255.0", più una riga route 192.168.2.0 255.255.255.0.
Il guasto costoso è fare metà di ciascuno. Se mascheri una parte del traffico mentre il lato remoto porta anche una route di ritorno per altro traffico, le risposte arrivano su un'interfaccia dove la voce di connection tracking non è mai stata vista. Il client segnala un timeout per una richiesta che il server ha registrato come servita. Entrambe le direzioni di un flusso devono attraversare la stessa istanza netfilter: un solo gateway che traduce, non due firewall in serie.
conntrack -L -d 10.50.1.17
iptables -t nat -L PREROUTING -v -nLeggi la voce in entrambe le direzioni: la tupla originale mantiene il tuo alias sulla destinazione, mentre la tupla di risposta porta l'indirizzo reale. Se la tupla di risposta manca, il problema è il percorso di ritorno, non la regola. Se i contatori di PREROUTING non si sono mai mossi, il pacchetto non ha mai raggiunto quel hook.
Collisioni e la ricerca che avviene prima
Due intervalli diversi possono entrare in collisione, ed entrambi i guasti sembrano un tunnel rotto piuttosto che una regola sbagliata. L'alias che inventi deve essere inutilizzato lungo tutto il percorso, e l'intervallo remoto reale non deve già esistere sulla tua rete. Un duplicato produce traffico intermittente verso l'host sbagliato, più difficile da diagnosticare di una connessione rifiutata. Chiedi alla tabella di routing prima di aggiungere una regola.
Sul gateway, ip route get 192.168.2.17 dovrebbe indicare il dispositivo del tunnel; un bridge locale significa che l'intervallo remoto è oscurato e nessuna regola nat lo riparerà. Se la tua rete usa già 192.168.2.0/24, rinumera il sito remoto invece di impilare una mappatura sulla collisione.
Provarlo da un client reale, poi conservarlo
Prova da una macchina che userà davvero l'alias, non dal gateway, perché il traffico generato localmente non attraversa mai PREROUTING allo stesso modo. Apri una connessione verso un host con alias e osserva i contatori e la voce conntrack comparire insieme, poi chiudila e conferma che la voce scompaia. Una voce obsoleta indica una connessione semiaperta, il che di solito significa che la risposta non è mai tornata.
curl -sv http://10.50.1.17/ -o /dev/null
ss -tn dst 10.50.1.17
conntrack -L -d 10.50.1.17Due o tre connessioni riuscite dimostrano l'aritmetica, ma non dicono nulla sulla persistenza o sul prossimo tecnico. Salva le regole dove il processo di avvio le legge, che su Debian e Ubuntu significa iptables-save > /etc/iptables/rules.v4 con netfilter-persistent abilitato. Una mappatura che svanisce al riavvio è peggio di nessuna, perché l'interruzione arriva senza alcun cambiamento recente da incolpare.
Lascia una nota accanto alle regole: l'intervallo alias, l'intervallo reale, il motivo della coppia e quale lato può iniziare. Quella nota separa un progetto da un mucchio di regole che nessuno osa cancellare. Risolve anche la domanda successiva, quando il sito remoto aggiunge un host e un indirizzo che nessuno ha configurato risponde già. Se la nota dice che il lato remoto ha bisogno di una route di ritorno, la persona successiva sa che rimuovere la regola di masquerade rompe la connettività. Qui la documentazione costa poco; riscoprire una dipendenza NAT alle tre del mattino no.