nft 設定使本機 NAT FTP 伺服器公開可用

nft 設定使本機 NAT FTP 伺服器公開可用

一切都將在隔離的網路上進行,安全性不是問題。
eth0 連接到「公共」網路。由 DHCP 指派的位址。
eth1 連接到提供 ssh、telnet、「其他」和 ftp 的「專用網路」伺服器。
在此範例中,該伺服器將具有固定 IP (192.168.1.2)。

網關正在運行 Debian buster 和 Linux 核心 4.19.94

nft 與 NAT 一起使用
這是到目前為止我的「網關」nft 配置:

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
  }
}

我需要添加什麼才能使 FTP 正常工作

答案1

長話短說

# 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

下面有更多詳細資訊...

針對有問題的協定的協定幫助模組

FTP 是一種舊協議,防火牆不太友善:FTP 命令通道 (21/TCP) 上的命令會協商一個臨時連接埠以用於下一個傳輸命令。因此,狀態防火牆必須監聽這些命令和回复,以暫時預先允許將要使用的足夠連接埠。

在 Linux 上,這是由特定於協定的幫助程式模組提供的,這些模組是連線,Netfilter 子系統追蹤 NAT 和狀態防火牆的連線。使用 FTP,當在 FTP 命令連接埠上發現下一次傳輸的連接埠協商(主要是 PORT、EPRT、PASV 或 EPSV)時,幫助程式會在特殊的目錄中新增一個短期條目。連線表(持續追蹤期望表),它將等待下一個相關的和預期的數據連接。

我的答案使用現代“安全”處理,如中所述這個部落格是關於iptables對於一般性和nftables維基百科man nft用於處理nftables這不同於iptables

安全使用 helper 和 nftables 規則

Linux 核心 4.7+(因此包括 4.19)預設使用安全方法:載入(此處為 FTP)幫助程式模組不會再監聽所有具有 TCP 來源或目標連接埠 21 的資料包,直到特定nftables(或者iptables) 語句告訴它在什麼(受限)情況下應該進行監聽。這避免了不必要的 CPU 使用,並且允許隨時透過更改一些規則(或集)來更改要監聽的 FTP 連接埠。

第一部分是聲明可以觸發監聽的串流。它的處理方式不同nftables比在iptables。這裡它是使用ct helper有狀態物件聲明的,並且啟動它的過濾器必須在之後完成連線(儘管iptables需要之前完成的操作)。man nft告訴:

與 iptables 不同,助手分配需要在 conntrack 查找完成後執行,例如使用預設的 0 掛鉤優先權。

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

我選擇了同一個表,但它可以在其他表中創建,只要有狀態物件聲明和引用它的規則位於同一個表中。

當然可以選擇限制性較小的規則。用以下規則取代最後一條規則將具有與舊模式相同的效果:

nft add rule ip my_nat my_helpers tcp dport 21 ct helper set ftp-incoming

僅供參考,舊模式不應再使用,不需要上述規則,只需此切換(以及手動載入相關核心模組):

sysctl -w net.netfilter.nf_conntrack_helper=1

確保nf_nat_ftp已加載

核心模組nf_conntrack_ftp會自動載入由 . 建立的依賴項ct helper ... type "ftp"。情況並非如此nf_nat_ftp,但當在資料流連接埠上完成 NAT 時,還需要在命令連接埠中啟用封包修改。

nf_nat_ftp例如,要在nf_conntrack_ftp載入時拉取模組,/etc/modprobe.d/local-nat-ftp.conf可以在檔案中加入以下內容:

install nf_conntrack_ftp /sbin/modprobe --ignore-install nf_conntrack_ftp; /sbin/modprobe --ignore-install nf_nat_ftp

或者,只需添加例如/etc/modules-load.d/local-nat-ftp.conf

nf_nat_ftp

無論如何,現在應該執行此命令以確保其已載入:

modprobe nf_nat_ftp

關於防火牆

這是防火牆的附加說明。還可以有一些限制的防火牆規則,而不是允許任何標記為的新流有關的經過連線

例如,雖然FTP 幫助程式模組同時處理被動和主動模式,但如果出於某種原因希望僅允許被動模式(從客戶端到伺服器的資料連接)而不是「主動」ftp(從伺服器來源連接埠20 到伺服器的資料連線)客戶端)可以在規則集的防火牆部分中使用例如這些規則,而不是通常的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 

其他種類的有關的與 FTP 無關的流保持接受(或可以進一步單獨拆分)


助手處理範例

這裡(在模擬環境)有兩個連線測量的事件列表期待表和連線包含 OP 規則的表 + 上面的附加規則,其中 Internet 用戶端 203.0.113.101 使用路由器的公共 IP 位址 192.0.2.2 以被動模式執行 FTP,並在登入後使用 LIST 命令:

# 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

同時地:

# 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]

期望的開始proto=6 src=203.0.113.101 dst=192.0.2.2 sport=0 dport=37157告訴我們將從 203.0.113.101:* 到 192.0.2.2:37157 的下一個 TCP 連線將被關聯(狀態有關的)與 FTP 連線。直接不可見,但由於也載入了 NAT FTP 幫助程式模組,伺服器回應 PASV/EPSV 命令發送的實際資料被攔截並轉換,因此客戶端連接到 192.0.2.2 而不是 192.168.1.2,後者會當然在客戶端失敗了。

儘管有第二個流程(第二新的行)沒有明確的規則我的預路由,它已成功DNATed到路由器後面的伺服器。


筆記

  • 如果 FTP 控制端口被加密(AUTH TLS...),那麼輔助模組將無法再監聽協商端口,這將無法工作。人們必須在 FTP 伺服器配置和防火牆/NAT 路由器上配置保留的連接埠範圍,並配置伺服器,以便在協商時發送正確的(公共)IP 位址而不是自己的 IP 位址。如果伺服器沒有到 Internet 的路由(就像此處的情況),則無法使用主動 FTP 模式。

  • daddr 192.168.1.2nitpicking:預路由優先權 10 確保即使對於 < 4.18 的內核,新流也已經發生 NAT(OP 選擇掛鉤預路由優先權 0 而不是通常的 -100,因為這在 nftables 中很少重要),因此可以使用。如果優先級為0(或低於0),則規則可能會看到第一個資料包仍未經過NAT 處理且具有公共IP 目標位址,但可能會捕獲同一流的後續資料包,因為它們已被處理直接由連線優先權-200。最好保持安全並使用 10。犯罪參考文獻待定補丁),其中 NAT 優先級僅與多個 nat 鏈之間的比較相關(並允許在 iptables 傳統中與 nftables 混合 NAT)。

答案2

經過一番嘗試和錯誤後,我想出了以下 nftables.conf ,它按預期工作,支援雙向 NAT,並將伺服器上除一個連接埠以外的所有連接埠匯出到「公共」網路。連接埠 2222 仍然用作網關的“後門”,如果我需要再次訪問它,則可以使用它:-)

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"
        }

}

相關內容