nft config per rendere disponibile un server FTP locale con NAT
Tutto sarà su una rete isolata, la sicurezza non è un problema.
eth0 è connesso alla rete "pubblica". Indirizzo assegnato da DHCP.
eth1 è connesso a un server di "rete privata" che fornisce ssh, telnet, "altri" e ftp.
Questo server avrà un IP fisso (192.168.1.2) in questo esempio.
Il gateway esegue Debian Buster e il kernel Linux 4.19.94
nft è utilizzato con NAT
Questa è la mia configurazione nft "gateway" fino ad ora:
table ip my_nat {
chain my_prerouting { type nat hook prerouting priority 0;
tcp dport { 2222 } dnat to :22 # 2222 backdoor for ssh to the gateway
tcp dport { 1-1023 } dnat to 192.168.1.2
}
chain my_postrouting {
type nat hook postrouting priority 100;
ip daddr 192.168.1.2 masquerade
}
}
Cosa devo aggiungere per far funzionare FTP
Risposte
TL; DR
# nft add ct helper ip my_nat ftp-incoming '{ type "ftp" protocol tcp; }'
# nft add chain ip my_nat my_helpers '{ type filter hook prerouting priority 10; }'
# nft add rule ip my_nat my_helpers iif eth0 ip daddr 192.168.1.2 tcp dport 21 ct helper set ftp-incoming
# modprobe nf_nat_ftp
con maggiori dettagli di seguito ...
Moduli di supporto del protocollo per protocolli problematici
FTP è un vecchio protocollo e non è molto adatto ai firewall: i comandi sul canale dei comandi FTP (21 / TCP) negoziano una porta temporanea da utilizzare per il successivo comando di trasferimento. Per questo motivo, un firewall con stato deve curiosare quei comandi e le risposte per consentire temporaneamente di pre-consentire l'utilizzo della porta adeguata.
Su Linux questo è fornito da moduli helper specifici del protocollo che sono plug-in per conntrack , il sottosistema Netfilter che traccia le connessioni per NAT e firewalling stateful. Con FTP, quando una negoziazione della porta (principalmente PORT, EPRT, PASV o EPSV) per il trasferimento successivo è stata vista sulla porta dei comandi FTP, l'helper aggiunge una voce di breve durata in una speciale tabella conntrack (la tabella delle aspettative attendere la successiva connessione dati correlata e prevista.
La mia risposta utilizza la moderna gestione "sicura" descritta in questo blog su iptables per le generalità e nel wiki di nftables e man nft
per la gestione in nftables che differisce da iptables .
Uso sicuro di regole helper e nftables
Il kernel Linux 4.7+ (quindi incluso 4.19) utilizza un approccio sicuro per impostazione predefinita: avere il modulo helper (qui FTP) caricato non farà più snoop tutti i pacchetti con una porta di origine o destinazione TCP 21, fino a quando non specifici nftables (o iptables ) le istruzioni dicono in quale caso (limitato) dovrebbe ficcare il naso. Ciò evita un utilizzo non necessario della CPU e consente di modificare in qualsiasi momento le porte FTP da curiosare semplicemente modificando alcune regole (o set).
La prima parte è dichiarare i flussi che possono innescare lo snooping. È gestito in modo diverso in nftables rispetto a iptables . Qui è dichiarato usando un ct helper
oggetto stateful e i filtri per attivarlo devono essere eseguiti dopo conntrack (mentre iptables richiede azioni fatte prima). man nft
dice:
A differenza di iptables, l'assegnazione dell'helper deve essere eseguita dopo che la ricerca di conntrack è stata completata, ad esempio con la priorità 0 hook predefinita.
nft add ct helper ip my_nat ftp-incoming '{ type "ftp" protocol tcp; }'
nft add chain ip my_nat my_helpers '{ type filter hook prerouting priority 10; }'
nft add rule ip my_nat my_helpers iif eth0 ip daddr 192.168.1.2 tcp dport 21 ct helper set ftp-incoming
Ho scelto la stessa tabella, ma questa avrebbe potuto essere creata in un'altra tabella, purché la dichiarazione di oggetto con stato e la regola che fa riferimento ad essa siano nella stessa tabella.
Naturalmente si possono scegliere regole meno restrittive. La sostituzione dell'ultima regola con la seguente regola avrebbe lo stesso effetto della modalità legacy:
nft add rule ip my_nat my_helpers tcp dport 21 ct helper set ftp-incoming
Solo per riferimento, la modalità legacy, che non dovrebbe più essere utilizzata, non richiede le regole precedenti ma solo questo interruttore (e il caricamento manuale del relativo modulo del kernel):
sysctl -w net.netfilter.nf_conntrack_helper=1
Garantire nf_nat_ftp
è caricato
Il modulo del kernel nf_conntrack_ftp
viene caricato automaticamente con la dipendenza creata da ct helper ... type "ftp"
. Non è questo il caso nf_nat_ftp
, ma è necessario abilitare anche la manipolazione dei pacchetti nella porta di comando quando NAT viene eseguito sulle porte del flusso di dati.
Ad esempio, per nf_nat_ftp
estrarre il modulo ogni volta che nf_conntrack_ftp
viene caricato, il file /etc/modprobe.d/local-nat-ftp.conf
potrebbe essere aggiunto con questo contenuto:
install nf_conntrack_ftp /sbin/modprobe --ignore-install nf_conntrack_ftp; /sbin/modprobe --ignore-install nf_nat_ftp
o invece, aggiungi semplicemente ad esempio /etc/modules-load.d/local-nat-ftp.conf
con:
nf_nat_ftp
Comunque in questo momento questo comando dovrebbe essere fatto per assicurarti che sia caricato:
modprobe nf_nat_ftp
Informazioni sul firewall
Ecco una nota aggiuntiva per il firewall. Possono esserci anche regole di firewall con alcune restrizioni invece di consentire qualsiasi nuovo flusso contrassegnato come correlato da conntrack .
Ad esempio, sebbene il modulo helper FTP gestisca sia la modalità passiva che quella attiva, se per qualche motivo si desidera consentire solo la modalità passiva (con connessione dati da client a server) e non ftp "attiva" (connessione dati dalla porta sorgente del server 20 a client) si potrebbero usare ad esempio queste regole nella parte firewall del set di regole, invece del solito ct state established,related accept
:
ct state established accept
ct state related ct helper "ftp" iif eth0 oif eth1 tcp sport 1024-65535 accept
ct state related ct helper "ftp" drop
ct state related accept
Altri tipi di flussi correlati non correlati all'FTP vengono mantenuti accettati (o potrebbero essere ulteriormente suddivisi separatamente)
Esempio di manipolazione da parte dell'assistente
Qui (in un ambiente simulato) ci sono due elenchi di eventi conntrack misurati sulla tabella delle aspettative e la tabella conntrack con le regole dell'OP + le regole aggiuntive sopra con un client Internet 203.0.113.101 che fa FTP in modalità passiva con l'indirizzo IP pubblico del router 192.0. 2.2 e utilizzando un comando LIST dopo aver effettuato l'accesso:
# conntrack -E expect
[NEW] 300 proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157 mask-src=0.0.0.0 mask-dst=0.0.0.0 sport=0 dport=65535 master-src=203.0.113.101 master-dst=192.0.2.2 sport=50774 dport=21 class=0 helper=ftp
[DESTROY] 300 proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157 mask-src=0.0.0.0 mask-dst=0.0.0.0 sport=0 dport=65535 master-src=203.0.113.101 master-dst=192.0.2.2 sport=50774 dport=21 class=0 helper=ftp
contemporaneamente:
# conntrack -E
[NEW] tcp 6 120 SYN_SENT src=203.0.113.101 dst=192.0.2.2 sport=50774 dport=21 [UNREPLIED] src=192.168.1.2 dst=192.168.1.1 sport=21 dport=50774 helper=ftp
[UPDATE] tcp 6 60 SYN_RECV src=203.0.113.101 dst=192.0.2.2 sport=50774 dport=21 src=192.168.1.2 dst=192.168.1.1 sport=21 dport=50774 helper=ftp
[UPDATE] tcp 6 432000 ESTABLISHED src=203.0.113.101 dst=192.0.2.2 sport=50774 dport=21 src=192.168.1.2 dst=192.168.1.1 sport=21 dport=50774 [ASSURED] helper=ftp
[NEW] tcp 6 120 SYN_SENT src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 [UNREPLIED] src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835
[UPDATE] tcp 6 60 SYN_RECV src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835
[UPDATE] tcp 6 432000 ESTABLISHED src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
[UPDATE] tcp 6 120 FIN_WAIT src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
[UPDATE] tcp 6 30 LAST_ACK src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
[UPDATE] tcp 6 120 TIME_WAIT src=203.0.113.101 dst=192.0.2.2 sport=55835 dport=37157 src=192.168.1.2 dst=192.168.1.1 sport=37157 dport=55835 [ASSURED]
L'inizio dell'aspettativa proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157
indica che la successiva connessione TCP da 203.0.113.101:* a 192.0.2.2:37157 sarà associata ( correlata allo stato ) alla connessione FTP. Non visibile direttamente, ma poiché viene caricato anche il modulo helper NAT FTP, i dati effettivi inviati dal server in risposta al comando PASV / EPSV sono stati intercettati e tradotti in modo che il client si connetta a 192.0.2.2 invece di 192.168.1.2 che avrebbe ovviamente fallito sul client.
Nonostante il secondo flusso (seconda NUOVA riga) non abbia una regola esplicita in my_prerouting , è stato correttamente DNAT trasmesso al server dietro il router.
Appunti
se la porta di controllo FTP è crittografata (
AUTH TLS
...), il modulo di supporto non può più ficcare il naso nella porta negoziata e questo non può funzionare. È necessario ricorrere alla configurazione di un intervallo riservato di porte sia sulla configurazione del server FTP che sul router firewall / NAT e configurare il server in modo che invii l'indirizzo IP (pubblico) corretto durante la negoziazione anziché il proprio. E la modalità FTP attiva non può essere utilizzata se il server non ha percorsi per Internet (come sembra essere il caso qui).nitpicking: la priorità di prerouting di 10 assicura che anche per i kernel <4.18, NAT già sia accaduto per i nuovi flussi (OP ha scelto la priorità di prerouting dell'hook 0 invece del solito -100 poiché questo è raramente importante in nftables), quindi l'uso di
daddr 192.168.1.2
è possibile. Se la priorità fosse 0 (o inferiore a 0), è forse possibile (non verificata) la regola vedrebbe il primo pacchetto ancora non NAT con un indirizzo IP pubblico di destinazione, ma catturerebbe i seguenti pacchetti dello stesso flusso, poiché vengono gestiti direttamente da conntrack con priorità -200. Meglio stare al sicuro e usare 10. In realtà questo non è rilevante dal kernel 4.18 (vedere il riferimento al commit in questa patch in attesa) dove la priorità NAT è rilevante solo per il confronto tra più catene nat (e consente di mescolare NAT in iptables legacy lungo nftables).
Dopo alcuni tentativi ed errori, ho trovato il seguente nftables.conf. Funziona come previsto e supporta NAT in entrambe le direzioni, oltre ad esportare tutte le porte tranne una sul mio server nella rete "pubblica". La porta 2222 è ancora usata come "backdoor" per il gateway, da utilizzare se dovessi accedervi di nuovo :-)
table ip my_nat {
ct helper ftp-incoming {
type "ftp" protocol tcp
l3proto ip
}
chain my_prerouting {
type nat hook prerouting priority 0; policy accept;
iifname "eth0" tcp dport { 2222 } dnat to :ssh
iifname "eth0" tcp dport { 1-2221, 2223-65535 } dnat to 192.168.0.2
}
chain my_postrouting {
type nat hook postrouting priority 100; policy accept;
ip daddr 192.168.0.2 masquerade
oifname "eth0" masquerade
}
chain my_helpers {
type filter hook prerouting priority 10; policy accept;
iif "eth0" ip daddr 192.168.0.2 tcp dport ftp ct helper set "ftp-incoming"
}
}