Networking

使用 NetCat 在本地測試 iptables DNAT 規則

  • November 20, 2017

我的一般問題是:在命令行上本地驗證 iptables NAT 規則在單個主機上(即沒有網路連接)的最佳方法(最簡單、最簡單、最快、最不容易出錯等)是什麼?

以下是使用 NetCat 檢查簡單 DNAT 規則的特定(失敗)嘗試的詳細資訊。我希望在這種情況下解決我的具體問題,但也希望能回答我的一般問題。


我正在使用執行 Debian 8 (Jessie) 的 VirtualBox 虛擬機。我想使用 netcat 對簡單的 DNAT 規則進行基本測試。

對於我的測試,我要做的就是將一些數據發送到一個本地地址(例如192.168.0.1)並讓它到達另一個本地地址(例如192.168.0.2)。

到目前為止,我已經嘗試了幾種不同的方法:

  1. 虛擬介面和 PREROUTING 鏈
  2. 虛擬介面和 PREROUTING 鏈
  3. 使用 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

在一個終端視窗中輸入的文本出現在另一個終端視窗中 - 成功!

引用自:https://unix.stackexchange.com/questions/404853