使用 NetCat 在本地測試 iptables DNAT 規則
我的一般問題是:在命令行上本地驗證 iptables NAT 規則在單個主機上(即沒有網路連接)的最佳方法(最簡單、最簡單、最快、最不容易出錯等)是什麼?
以下是使用 NetCat 檢查簡單 DNAT 規則的特定(失敗)嘗試的詳細資訊。我希望在這種情況下解決我的具體問題,但也希望能回答我的一般問題。
我正在使用執行 Debian 8 (Jessie) 的 VirtualBox 虛擬機。我想使用 netcat 對簡單的 DNAT 規則進行基本測試。
對於我的測試,我要做的就是將一些數據發送到一個本地地址(例如
192.168.0.1
)並讓它到達另一個本地地址(例如192.168.0.2
)。到目前為止,我已經嘗試了幾種不同的方法:
- 虛擬介面和 PREROUTING 鏈
- 虛擬介面和 PREROUTING 鏈
- 使用 OUTPUT 鏈代替 PREROUTING
虛擬介面和 PREROUTING 鏈
我的第一次嘗試是向 PREROUTING 鏈添加 DNAT 規則,並添加兩個具有適當地址的虛擬介面。
這是我的規則:
sudo iptables \ -t nat \ -A PREROUTING \ -d 192.168.0.1 \ -j DNAT --to-destination 192.168.0.2
我的防火牆中沒有其他 netfilter 規則。但可以肯定的是,這裡是來自的輸出
iptables-save
:# 由 iptables-save v1.4.21 生成 *nat :PREROUTING 接受 [0:0] :輸入接受 [0:0] :輸出接受 [0:0] :POSTROUTING 接受 [0:0] -A PREROUTING -d 192.168.0.1/32 -j DNAT --to-destination 192.168.0.2 犯罪 *篩選 :輸入接受 [0:0] : 轉發接受 [0:0] :輸出接受 [0:0] 犯罪
重申一下,我要做的就是將一些數據發送到該
192.168.0.1
地址並讓它到達該192.168.0.2
地址。值得一提的
192.168.0.0/24
是,我的 VM 上未使用子網。首先,我添加了幾個虛擬介面:sudo ip link add dummy1 type dummy sudo ip link add dummy2 type dummy
接下來,我將 IP 地址分配給所需子網範圍內的虛擬介面:
sudo ip addr add 192.168.0.1/24 dev dummy1 sudo ip addr add 192.168.0.2/24 dev dummy2
然後我打開介面:
sudo ip link set dummy1 up sudo ip link set dummy2 up
這是我的路由表現在的樣子:
預設通過 10.0.2.2 dev eth0 10.0.2.0/24 dev eth0 proto 核心範圍連結 src 10.0.2.15 192.168.0.0/24 dev dummy1 原型核心範圍連結 src 192.168.0.1 192.168.0.0/24 dev dummy2 proto 核心範圍連結 src 192.168.0.2 192.168.56.0/24 dev eth1 proto 核心範圍連結 src 192.168.56.100
現在我使用 netcat 監聽第一個(源)地址:
nc -l -p 1234 -s 192.168.0.1
我使用 netcat 客戶端(在單獨的終端視窗中)連接到 netcat 伺服器:
nc 192.168.0.1 1234
在一個視窗中輸入的文本出現在另一個視窗中 - 正如預期的那樣。
我對第二個地址也做同樣的事情:
nc -l -p 1234 -s 192.168.0.2 nc 192.168.0.2 1234
同樣,在一個視窗中輸入的文本會出現在另一個視窗中 - 正如預期的那樣。
最後,我嘗試監聽目標(DNAT)地址並通過源(DNAT)地址進行連接:
nc -l -p 1234 -s 192.168.0.2 nc 192.168.0.1 1234
不幸的是,連接失敗並出現以下錯誤:
(未知)[192.168.0.1] 1234 (?):連接被拒絕
我還嘗試使用
ping -c 1 -R 192.168.0.1
查看 DNAT 是否生效,但看起來並非如此:PING 192.168.0.1 (192.168.0.1) 56(124) 字節數據。 來自 192.168.0.1 的 64 個字節:icmp_seq=1 ttl=64 time=0.047 ms RR: 192.168.0.1 192.168.0.1 192.168.0.1 192.168.0.1 --- 192.168.0.1 ping 統計 --- 1個包發送,1個接收,0%丟包,時間0ms rtt 最小值/平均值/最大值/mdev = 0.047/0.047/0.047/0.000 毫秒
為什麼這不起作用?我究竟做錯了什麼?
使用 tcpdump 進行診斷
為了診斷這個問題,我嘗試使用
tcpdump
監聽虛擬介面上的流量。我嘗試監聽所有介面(並過濾掉 SSH 和 DNS):。sudo tcpdump -i any -e port not 22 and port not 53
然後我ping了
dummy1
界面:ping -n -c 1 -I dummy1 192.168.0.1
這產生了以下結果:
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes In 00:00:00:00:00:00 (oui Ethernet) ethertype IPv4 (0x0800), length 100: 192.168.0.1 > 192.168.0.1: ICMP echo request, id 8071, seq 1, length 64 In 00:00:00:00:00:00 (oui Ethernet) ethertype IPv4 (0x0800), length 100: 192.168.0.1 > 192.168.0.1: ICMP echo reply, id 8071, seq 1, length 64
所以看起來虛擬介面附加到環回介面。這可能意味著完全規避了 iptables 規則。
虛擬介面和 PREROUTING 鏈
作為第二次嘗試,我嘗試使用所謂的虛擬 IP 地址而不是虛擬介面。
以下是我將“虛擬”IP 地址添加到 eth0 和 eth1 介面的方法:
sudo ip addr add 192.168.0.100/24 dev eth0 sudo ip addr add 192.168.0.101/24 dev eth1
**注意:**我為這些使用了不同的 IP 地址,而不是為虛擬介面使用的 IP 地址。
然後我刷新並更新了 iptables NAT 規則:
sudo iptables -F -t nat sudo iptables \ -t nat \ -A PREROUTING \ -d 192.168.0.100 \ -j DNAT --to-destination 192.168.0.101
我重試了ping測試:
ping -n -c 1 -R 192.168.0.100
不說:
PING 192.168.0.100 (192.168.0.100) 56(124) 個字節的數據。 來自 192.168.0.100 的 64 個字節:icmp_seq=1 ttl=64 time=0.023 ms RR: 192.168.0.100 192.168.0.100 192.168.0.100 192.168.0.100 --- 192.168.0.100 ping 統計 --- 1個包發送,1個接收,0%丟包,時間0ms rtt 最小值/平均值/最大值/mdev = 0.023/0.023/0.023/0.000 毫秒
然後再次netcat測試。啟動伺服器:
nc -l -p 1234 -s 192.168.0.101
嘗試連接客戶端:
nc 192.168.0.100 1234
也不說:
(未知)[192.168.0.100] 1234(?):連接被拒絕
使用 OUTPUT 鏈代替 PREROUTING
然後我嘗試將兩條 DNAT 規則從 PREROUTING 鏈移到 OUTPUT 鏈:
sudo iptables -F -t nat sudo iptables \ -t nat \ -A OUTPUT \ -d 192.168.0.1 \ -j DNAT --to-destination 192.168.0.2 sudo iptables \ -t nat \ -A OUTPUT \ -d 192.168.0.100 \ -j DNAT --to-destination 192.168.0.101
現在我嘗試在虛擬介面和虛擬介面上 ping:
使用者@主機:~$ ping -c 1 -R 192.168.0.1 PING 192.168.0.1 (192.168.0.1) 56(124) 字節數據。 來自 192.168.0.1 的 64 個字節:icmp_seq=1 ttl=64 time=0.061 ms RR: 192.168.0.1 192.168.0.2 192.168.0.2 192.168.0.1 --- 192.168.0.1 ping 統計 --- 1個包發送,1個接收,0%丟包,時間0ms rtt 最小值/平均值/最大值/mdev = 0.061/0.061/0.061/0.000 毫秒 使用者@主機:~$ ping -c 1 -R 192.168.0.100 PING 192.168.0.100 (192.168.0.100) 56(124) 個字節的數據。 來自 192.168.0.100 的 64 個字節:icmp_seq=1 ttl=64 time=0.058 ms RR: 192.168.0.100 192.168.0.101 192.168.0.101 192.168.0.100 --- 192.168.0.100 ping 統計 --- 1個包發送,1個接收,0%丟包,時間0ms rtt 最小值/平均值/最大值/mdev = 0.058/0.058/0.058/0.000 毫秒
我還嘗試對每對 IP 地址進行 netcat 客戶端-伺服器測試:
nc -l -p 1234 -s 192.168.0.2 nc 192.168.0.1 1234
和:
nc -l -p 1234 -s 192.168.0.101 nc 192.168.0.100 1234
這個測試也成功了。
因此,當 DNAT 規則位於 OUTPUT 鏈而不是 PREROUTING 鏈中時,看起來虛擬介面和虛擬介面都可以工作。
似乎我的部分問題是我不清楚哪些數據包遍歷哪些鏈。
簡短說明:虛擬介面和虛擬 IP 地址通過環回介面發送數據包,不受 PREROUTING 鏈的影響。通過使用帶有 veth 介面的網路命名空間,我們可以將流量從一個 IP 地址發送到另一個 IP 地址,從而更準確地模擬多主機網路流量,並允許我們根據需要測試 PREROUTING 鏈上的 DNAT 規則。
下面對解決方案進行更詳細的描述。
這是一個配置一對網路介面並測試 DNAT 規則是否按預期執行的 Bash 腳本:
# Create a network namespace to represent a client sudo ip netns add 'client' # Create a network namespace to represent a server sudo ip netns add 'server' # Create a veth virtual-interface pair sudo ip link add 'client-eth0' type veth peer name 'server-eth0' # Assign the interfaces to the namespaces sudo ip link set 'client-eth0' netns 'client' sudo ip link set 'server-eth0' netns 'server' # Change the names of the interfaces (I prefer to use standard interface names) sudo ip netns exec 'client' ip link set 'client-eth0' name 'eth0' sudo ip netns exec 'server' ip link set 'server-eth0' name 'eth0' # Assign an address to each interface sudo ip netns exec 'client' ip addr add 192.168.1.1/24 dev eth0 sudo ip netns exec 'server' ip addr add 192.168.2.1/24 dev eth0 # Bring up the interfaces (the veth interfaces the loopback interfaces) sudo ip netns exec 'client' ip link set 'lo' up sudo ip netns exec 'client' ip link set 'eth0' up sudo ip netns exec 'server' ip link set 'lo' up sudo ip netns exec 'server' ip link set 'eth0' up # Configure routes sudo ip netns exec 'client' ip route add default via 192.168.1.1 dev eth0 sudo ip netns exec 'server' ip route add default via 192.168.2.1 dev eth0 # Test the connection (in both directions) sudo ip netns exec 'client' ping -c 1 192.168.2.1 sudo ip netns exec 'server' ping -c 1 192.168.1.1 # Add a DNAT rule to the server namespace sudo ip netns exec 'server' \ iptables \ -t nat \ -A PREROUTING \ -d 192.168.2.1 \ -j DNAT --to-destination 192.168.2.2 # Add a dummy interface to the server (we need a target for the destination address) sudo ip netns exec 'server' ip link add dummy type dummy sudo ip netns exec 'server' ip addr add 192.168.2.2/24 dev dummy sudo ip netns exec 'server' ip link set 'dummy' up # Test the DNAT rule using ping sudo ip netns exec 'client' ping -c 1 -R 192.168.2.1
ping 測試的輸出表明該規則正在執行:
PING 192.168.2.1 (192.168.2.1) 56(124) bytes of data. 64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=0.025 ms RR: 192.168.1.1 192.168.2.2 192.168.2.2 192.168.1.1 --- 192.168.2.1 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.025/0.025/0.025/0.000 ms
現在我也可以執行我的 NetCat 測試了。首先我在伺服器上收聽:
sudo ip netns exec 'server' nc -l -p 1234 -s 192.168.2.2
然後我通過客戶端連接(在單獨的終端視窗中):
sudo ip netns exec 'client' nc 192.168.2.1 1234
在一個終端視窗中輸入的文本出現在另一個終端視窗中 - 成功!