Linux - 兩個子網、一個介面、一個網關 - NAT 附加子網
我們目前有幾台伺服器都使用同一個 LAN:
Host1: eth0 10.0.0.1/24 Host2: eth0 10.0.0.2/24 Host3: eth0 10.0.0.3/24 Gateway: 10.0.0.254
我們想在這些伺服器上執行一些虛擬機(VirtualBox)。我們可以將它們設置為橋接到主機的 eth0,但我們不能使用 10.0.0.0/24 範圍內的地址,因為它們將來可能會被分配。
所以我們認為我們會使用不同的子網:
Host1VM: eth0 192.168.0.1/24 (bridge to host eth0) Host2VM: eth0 192.168.0.2/24 (bridge to host eth0) Host3VM: eth0 192.168.0.3/24 (bridge to host eth0)
這很好,所有虛擬機都可以相互通信,因為它們位於使用相同物理介面的同一子網上。
我們面臨的問題是我們需要讓這些虛擬機通過 10.0.0.254 網關訪問網際網路。所以我們想為什麼不選擇其中一台主機並將其用作路由器/NAT?
Host1: eth0 10.0.0.1/24, eth0:0 192.168.0.254/24
現在我們可以給虛擬機一個網關 192.168.0.254。然後我們看到的問題是 Host1 似乎沒有正確地進行 NAT。
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j SNAT --to 10.0.0.1
我認為這會起作用,我們確實看到它匹配數據包。如果虛擬機 ping 網際網路,我們看到 ICMP 數據包進入主機 1(因為它是路由器),然後主機重新發送 ICMP,因為它是 NAT’ing,網際網路主機響應主機 - 但隨後它死在那裡。我希望主機隨後將數據包轉發回虛擬機,但事實並非如此。
我錯過了什麼,或者這個設置根本不可能?
編輯:澄清一下,我們在 iptables 中沒有拒絕規則,一切都是預設的接受。我們還啟用了 IP 轉發。
更新1-iptables
忽略 virbr0 - 這與 VirtualBox 虛擬機無關
# Completed on Fri Sep 20 16:50:45 2013 # Generated by iptables-save v1.4.12 on Fri Sep 20 16:50:45 2013 *nat :PREROUTING ACCEPT [171383:10358740] :INPUT ACCEPT [1923:115365] :OUTPUT ACCEPT [192:21531] :POSTROUTING ACCEPT [169544:10254463] -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j SNAT --to-source 10.0.0.1 COMMIT # Completed on Fri Sep 20 16:50:45 2013 # Generated by iptables-save v1.4.12 on Fri Sep 20 16:50:45 2013 *filter :INPUT ACCEPT [96628707:25146145432] :FORWARD ACCEPT [195035595:22524430122] :OUTPUT ACCEPT [44035412:304951330498] -A INPUT -i virbr0 -p udp -m udp --dport 53 -j ACCEPT -A INPUT -i virbr0 -p tcp -m tcp --dport 53 -j ACCEPT -A INPUT -i virbr0 -p udp -m udp --dport 67 -j ACCEPT -A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT -A FORWARD -d 192.168.122.0/24 -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT -A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT -A FORWARD -i virbr0 -o virbr0 -j ACCEPT -A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable -A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable COMMIT # Completed on Fri Sep 20 16:50:45 2013 # Generated by iptables-save v1.4.12 on Fri Sep 20 16:50:45 2013 *mangle :PREROUTING ACCEPT [291641356:47665886851] :INPUT ACCEPT [96628707:25146145432] :FORWARD ACCEPT [195035595:22524430122] :OUTPUT ACCEPT [44035838:304951365412] :POSTROUTING ACCEPT [239078922:327477732680] -A POSTROUTING -o virbr0 -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill -A POSTROUTING -o virbr0 -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill COMMIT # Completed on Fri Sep 20 16:50:45 2013
更新 2 - tcpdump
16:58:37.189758 IP 192.168.0.2 > 74.125.128.106: ICMP echo request, id 1, seq 2, length 40 16:58:37.189805 IP 10.0.0.1 > 74.125.128.106: ICMP echo request, id 1, seq 2, length 40 16:58:37.194607 IP 74.125.128.106 > 10.0.0.1: ICMP echo reply, id 1, seq 2, length 40 (no final reply back to the VM)
我將回答我自己的問題,因為這就是我解決它的方法。我很確定其他答案在正常情況下非常準確,但我相信由於使用介面別名的錯誤或警告,它們不起作用。
所以認為介面別名導致了這個問題,我尋找其他提供虛擬介面的方法,結果發現有一種稱為 MAC-VLAN 的虛擬介面類型,它本質上將自己作為虛擬介面附加到物理介面,其自己的 MAC 地址。
使用 NAT 第一次完美執行,所以我認為這僅僅是因為 MAC-VLAN 介面在核心中顯示為一個完全獨立的介面,而介面別名在某處引起了一些混亂。
作為參考,創建 MAC-VLAN 的命令很簡單:
ip link add dev macvlan0 link eth0 type macvlan
這是一個非常好的功能,我不敢相信我以前沒有聽說過。
這說明:
16:58:37.189758 IP 192.168.0.2 > 74.125.128.106: ICMP echo request, id 1, seq 2, length 40 16:58:37.189805 IP 10.0.0.1 > 74.125.128.106: ICMP echo request, id 1, seq 2, length 40 16:58:37.194607 IP 74.125.128.106 > 10.0.0.1: ICMP echo reply, id 1, seq 2, length 40
上游路由器 (
10.0.0.254
) 將回復發送回 Host1,因此您的路由和 SNAT 正常工作。問題是 Host1 沒有將該回复傳遞回192.168.0.0/24
網路。您是否載入了適當的連接跟踪核心模組?
確保流量進入連接跟踪表:
grep src=192.168.0.2 /proc/1/net/nf_conntrack
前幾天我看到一個與 TCP 數據包類似的問題,結果證明是由於
rp_filter
核心造成的。我看不出這會是什麼問題,但它非常相似。您可以從 Host1 發布路由表 (ip route show
) 並檢查您的 rp_filter 設置嗎?(cat /proc/sys/net/ipv4/conf/default/rp_filter
)