Netruon 理解(11):使用 NAT 將 Linux network namespace 連接外網


學習 Neutron 系列文章:

(1)Neutron 所實現的虛擬化網絡

(2)Neutron OpenvSwitch + VLAN 虛擬網絡

(3)Neutron OpenvSwitch + GRE/VxLAN 虛擬網絡

(4)Neutron OVS OpenFlow 流表 和 L2 Population

(5)Neutron DHCP Agent

(6)Neutron L3 Agent  

(7)Neutron LBaas

(8)Neutron Security Group

(9)Neutron FWaas 和 Nova Security Group

(10)Neutron VPNaas

(11)Neutron DVR

(12)Neutron VRRP

(13)High Availability (HA)

(14)使用 NAT 將 Linux network namespace 連接外網

(15)使用 Linux bridge 將 Linux network namespace 連接外網

 

Linux network namespace 連接外網從大類上來講主要有兩種方法:網絡地址轉換(NAT) 和 橋接(bridging),而橋接根據使用的網橋又可以分為使用 linux bridge 和 Open vSwitch 網絡等。本文將說明 NAT 具體配置過程以及原理。

1. 環境及配置

我們可以把一個 linux network namespace 看作另一個計算機,這樣看起來會更加直觀:

節點 host1 的 IP 地址為 192.168.1.32. 實驗使用的另一個機器 host2 的 IP 為 192.168.1.15.

為了能從在 host1 上的 netns myspace 上能 ping 通 host2 ,你需要做的配置及說明:

步驟# 命令 說明
1 ip netns add myspace 創建名稱為 ‘myspace’ 的 linux network namespace
2 ip link add veth1 type veth peer name veth2 創建一個 veth 設備,一頭為 veth1,另一頭為 veth2
3 ip link set veth2 netns myspace 將 veth2 加入 myspace 作為其一個 network interface
4 ifconfig veth1 192.168.45.2 netmask 255.255.255.0 up 配置 veth1 的 IP 地址
5 ip netns exec myspace ifconfig veth2 192.168.45.3 netmask 255.255.255.0 up 配置 veth2 的 IP 地址,它和 veth1 需要在同一個網段上
6 ip netns exec myspace route add default gw 192.168.45.2 將 myspace 的默認路由設為 veth1 的 IP 地址
7 echo 1 > /proc/sys/net/ipv4/ip_forward    開啟 linux kernel ip forwarding
8 iptables -t nat -A POSTROUTING -s 192.168.45.0/24 -o eth0 -j MASQUERADE 配置 SNAT,將從 myspace 發出的網絡包的 soruce IP address 替換為 eth0 的 IP 地址
9

iptables -t filter -A FORWARD -i eth0 -o veth1 -j ACCEPT

iptables -t filter -A FORWARD -o eth0 -i veth1 -j ACCEPT

在默認 FORWARD 規則為 DROP 時顯式地允許 veth1 和 eth0 之間的 forwarding

這些配置之后,host 上的 route 表中自動添加了一條路由規則:

root@compute2:/home/s1# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.1     0.0.0.0         UG    0      0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0
192.168.45.0    0.0.0.0         255.255.255.0   U     0      0        0 veth1

myspace 的路由表:

root@compute2:/home/s1# ip netns exec myspace route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.45.2    0.0.0.0         UG    0      0        0 veth2
192.168.45.0    0.0.0.0         255.255.255.0   U     0      0        0 veth2

其中第一條是顯式地被創建的,第二條是自動被創建的。

現在你就可以從 myspace 中 ping 外網的地址了。

2 原理

2.1 關於第八條 SNAT

如果沒有設置第八條 SNAT,那么 ICMP Request 能夠到達對方計算機,但是 echo reply 消息回不來,因為其目的地址為一個內部地址。

root@compute1:/home/s1# tcpdump -eni bridge1 -p icmp -v
tcpdump: listening on bridge1, link-type EN10MB (Ethernet), capture size 65535 bytes
07:40:03.827852 08:00:27:4f:56:17 > 08:00:27:c7:cf:ca, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 63, id 54069, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.45.3 > 192.168.1.15: ICMP echo request, id 26569, seq 1, length 64
07:40:04.829779 08:00:27:4f:56:17 > 08:00:27:c7:cf:ca, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 63, id 54194, offset 0, flags [DF], proto ICMP (1), length 84)

加上第八條之后,ping 能成功,也就是 ICMP echo request 能發出,echo reply 能返回。

在 host2 的網卡 eth0 上,能看到 ICMP echo request 網絡包的源 IP 為 host1 的 IP:

07:44:19.360519 08:00:27:c7:cf:ca > 08:00:27:4f:56:17, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 54265, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.15 > 192.168.1.32: ICMP echo reply, id 28534, seq 7, length 64
07:44:20.358360 08:00:27:4f:56:17 > 08:00:27:c7:cf:ca, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 63, id 21278, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.32 > 192.168.1.15: ICMP echo request, id 28534, seq 8, length 64

在 host1 的網卡 eth0 上,能看到來回網絡包使用的是 host1 和 host2 的 IP 地址:

root@compute2:/home/s1# tcpdump -envi eth0 -p icmp -v
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
06:31:27.285150 08:00:27:4f:56:17 > 08:00:27:c7:cf:ca, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 63, id 58781, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.32 > 192.168.1.15: ICMP echo request, id 29610, seq 158, length 64
06:31:27.285777 08:00:27:c7:cf:ca > 08:00:27:4f:56:17, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 23662, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.15 > 192.168.1.32: ICMP echo reply, id 29610, seq 158, length 64

在 host1 的 veth1 上,能看到發出的網絡包的源 IP 和收到的網絡包的目的 IP 皆為內部網段的 IP 地址:

root@compute2:/home/s1# tcpdump -envi veth1 -p icmp -v
tcpdump: listening on veth1, link-type EN10MB (Ethernet), capture size 65535 bytes
06:33:13.355956 b2:52:7e:b6:e9:4e > ee:53:ae:dd:6f:7f, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 6989, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.45.3 > 192.168.1.15: ICMP echo request, id 29610, seq 264, length 64
06:33:13.356391 ee:53:ae:dd:6f:7f > b2:52:7e:b6:e9:4e, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 63, id 36067, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.1.15 > 192.168.45.3: ICMP echo reply, id 29610, seq 264, length 64

那為什么在 forwarding 發生之前,在 iptables nat 表中並沒有顯式做 DNAT 的情況下 veth1 和 eth0 之間有了 DNAT 呢? 

原因是 ICMP 使用了 Query ID,而 NAT 會自動根據 ICMP Query ID 對 ICMP echo reply 做 DNAT。根據 https://tools.ietf.org/html/rfc5508 的 3.1. ICMP Query Mapping 章節,當內部的 host1 發一個 ICMP Query 給外部 host2 時,linux 內核的 NAT 模塊會針對 NAT 的外部地址分配一個匹配的 query ID(上面例子中的 id 29610);然后當收到 ICMP echo reply 時,NAT模塊會根據 ICMP Query ID 以及 ICMP header checksum 將外部 IP 轉化為內部 IP,然后再做 forwarding。也可以看出,ICMP Query ID 類似於 TCP 和 UDP 使用的端口號(port number),兩者的區別在於 NAT 為 ICMP 自動做了 DNAT,而 TCP 和 UDP 則需要顯式添加 DNAT 規則。

2.2 關於 IP forwarding

 (圖片來源

Linux 內核在從 veth1 上收到 myspace 發過來的 ICMP 包以后,

  1. 執行 PREROTING 規則,本例不需要此配置此規則。
  2. 執行 Routing decision。它會檢查網絡包的目的IP地址,發現它不在本機上,說明需要進行 routing (FORWARD)。因為 Linux 上默認的 IP forwarding 是關閉的,因此需要執行第七條命令來開啟它;然后再檢查 iptable 規則中的這種 forwarding (ICMP 包從veth1 出再進入 eth0)。通常為了安全起見,管理員會將 FORWARD 的默認規則設置為 DROP,此時則需要執行第九條命令顯式地允許(ACCEPT)所需要的 forwarding。
  3. 執行 ip forwarding。查找 host1 上的路由表,網絡包會被路由到 eth0。
  4. 執行 POSTROUTING 規則。因為此時的網絡包的源 IP 地址仍然為內部地址,為了避免 ICMP 網絡包有去無回,需要通過 SNAT 將內部地址轉換為外部地址。這就是第八條的作用。
  5. 從 eth0 發出

(3)關於 myspace 的默認路由

因為 myspace 只有一根網線(veth)連接到 veth1,因此,必須將默認的路由器地址設置為 veth1 的 IP 地址。

2.3 DNAT

  上面的配置只是為了能從 myspace 中訪問外網。要使得外面網絡能訪問 myspace 中的應用的話,則需要在 host1 上添加 DNAT 規則,比如將 8080 端口受到的 TCP 轉到內部 IP 上的 80 端口;同時還需要配置 forward 規則,允許從 eth0 出到 veth1 進。基本過程為:

對方計算機使用 host1 的 IP 地址和特定端口訪問 mysapce 中的 TCP 應用 (192.168.1.32:8080),

  1. Linux 內核在從 eth0 上收到發過來的TCP包(IP 為 192.168.1.32,端口為 8080)
  2. 執行 PREROTING 規則,將目的 IP 及端口修改為 192.168.45.3 和 80
  3. 執行 Routing decision。它會檢查網絡包的目的IP地址,發現它不在本機上,說明需要進行 routing (FORWARD)。檢查 Linux 的 IP forwarding 是否打開;然后再檢查 iptable 規則中的這種 forwarding (TCP 包從 eth0 出再進入 veth1)。通常為了安全起見,管理員會將 FORWARD 的默認規則設置為 DROP,此時則需要執行類似第九條命令顯式地允許(ACCEPT)所需要的 forwarding。
  4. 執行 ip forwarding。查找 host1 上的路由表,網絡包會被路由到 veth1。
  5. 執行 POSTROUTING 規則。盡管有第八條規則,但是它要求源地址在內部網段,因此不會執行。
  6. 從 veth1 發出的包通過 veth 設備進入 myspace 的 veth0 網卡。
  7. 被 80 端口上的應用接收到。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM