Networking

如何將訪客掛接到“tun”介面

  • October 23, 2021

我正在嘗試強制來自來賓(Windows 或 Linux)的所有流量通過主機(Linux)的 VPN。為了確保訪客無法訪問 VPN 之外的網際網路,我在主機系統上建立了連接,這會創建一個新介面tun0。VPN 隧道在主機上執行良好。

設置br0,沒有 VPN

為了在訪客中獲得沒有 VPN 的網際網路,我創建了一個橋接設備br0並附enp7s0加到它。這樣,網際網路就可以在客人中使用。

ip link add name br0 type bridge
ip link set br0 up
ip link set enp7s0 master br0

在主機上,vnet5已添加一個設備並橋接到br0. 但與此同時,從主機 ping 到遠端不再起作用。

## On the Host
sudo ip a
# ...
# 14: vnet5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UNKNOWN group default qlen 1000
# link/ether ab:ab:ab:ab:ab:ab brd ff:ff:ff:ff:ff:ff
# inet6 fe80::fc54:ff:fe92:5aa9/64 scope link
# valid_lft forever preferred_lft forever
ping www.google.com
# ping: www.google.com: Temporary failure in name resolution
ping 8.8.8.8
# From 192.168.1.100 icmp_seq=1 Destination Host Unreachable

然後我啟動虛擬機virt-manager並檢查連接。客人有網際網路:

## On the Guest
ip a
# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
# ...
# 2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
#     link/ether 52:54:00:92:5a:a9 brd ff:ff:ff:ff:ff:ff
#     inet 192.168.1.221/24 brd 192.168.1.255 scope global dynamic noprefixroute enp1s0
#        valid_lft 67432sec preferred_lft 67432sec
ping www.google.ch
# PING www.google.ch (172.217.168.35) 56(84) bytes of data.
# 64 bytes from zrh04s14-in-f3.1e100.net (172.217.168.35): icmp_seq=1 ttl=117 time=2.47 ms

我想除了設置之外,我還可以在和ip link set enp7s0 master br0之間創建路由規則。br0``enp7s0

使用 VPN 和tun0介面

當我建立 VPN 連接時,tun0會創建一個無法分配給網橋的介面。因此,無論如何我都需要創建路由規則。所以我猜情況與上述情況類似。首先,我enp7s0再次從br0.

ip link set enp7s0 nomaster
sudo openvpn my_vpn_tcp.ovpn
# ...
# Initialization Sequence Completed
sudo ip a
# ...
# 3: enp7s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
# link/ether ab:ab:ab:ab:ab:ab brd ff:ff:ff:ff:ff:ff permaddr ab:ab:ab:ab:ab:ab
# inet 192.168.1.100/24 brd 192.168.1.255 scope global dynamic noprefixroute enp7s0
# valid_lft 82702sec preferred_lft 82702sec
# ...
# 10: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 500
# link/none
# inet 10.7.7.5/24 scope global tun0
# valid_lft forever preferred_lft forever
# ...
# 12: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
# link/ether 72:eb:06:e5:1e:5a brd ff:ff:ff:ff:ff:ff
# inet6 fe80::70eb:6ff:fee5:1e5a/64 scope link
# valid_lft forever preferred_lft forever

無需進一步操作,在主機上使用 VPN 連接,就可以了。

ping www.google.com
# PING www.google.com (172.217.168.3) 56(84) bytes of data.
# 64 bytes from lala.net (172.217.168.3): icmp_seq=1 ttl=117 time=9.64 ms
# ...
ping www.google.com -I tun0
# PING www.google.com (172.217.168.3) from 10.7.7.5 tun0: 56(84) bytes of data.
# 64 bytes from lala.net (172.217.168.3): icmp_seq=2 ttl=117 time=10.0 ms
# ...
ping www.google.com -I enp7s0
# PING www.google.com (172.217.168.3) from 192.168.1.100 enp7s0: 56(84) bytes of data.
# 64 bytes from lala.net (172.217.168.3): icmp_seq=1 ttl=115 time=4.59 ms
# ...

但正如已經說過的,我不能添加tun0br0. 正因為如此,客人也沒有網際網路。

sudo ip link set tun0 master br0
# RTNETLINK answers: Invalid argument

我搜尋了解決方案,但找不到可行的方法,或者我的情況略有不同,這需要對我沒有的網路有更多的了解。例如這個(沒有完成工作)或這個(不完全適合我的情況)。

同一個問題有兩個問題,它們實際上並不相互依賴。我仍然會回答兩個。

此外,noprefixroute地址選項暗示部分網路配置由一些附加工具(如 NetworkManager)管理以添加路由。此答案不會嘗試處理網路工具中的集成。這包括處理 DHCP 配置,如果未正確重新配置,以後可能會覆蓋更改。當界面關閉或刪除時,許多設置都會消失並且必須再次完成,因此最好在各種負責的網路工具的各種掛鉤中完成。

設置br0,沒有 VPN

設置為橋接埠的介面放棄參與路由

一旦設置為橋接埠,與介面關聯的路由將被忽略。留下地址時可能仍然存在有害的副作用。詳細資訊可以在部落格中找到Linux 橋的適當隔離

  1. 將幀移交給特定於設備的接收處理程序(如果有),
  2. 將幀移交給全域或設備特定的協議處理程序(例如 IPv4、ARP、IPv6)

對於橋接介面,核心已經配置了一個設備特定的接收處理程序,br_handle_frame(). 除了 STP 和 LLDP 幀,或者如果啟用了“路由”,此函式將不允許在傳入介面的上下文中進行任何其他處理。因此,這種情況下永遠不會執行協議處理程序。**

在成為網橋埠的介面上設置的 IP 地址應該移動到特殊網橋的自身介面(br0:網橋本身),這是唯一能夠參與路由的介面(還有其他選項,但讓我們保持簡單)。相關路線也是如此。

假設 OP 的預設網關是 192.168.1.1/24。讓我們為第一種情況重寫:

ip link add name br0 up type bridge
ip link set dev enp7s0 master br0

ip address flush dev enp7s0
# previous command will also have removed all associated routes as a side effect
ip address add 192.168.1.100/24 dev br0
# previous command added the LAN route too as a side effect (no noprefixroute here)
ip route add default via 192.168.1.1

這樣,主機和VM都可以訪問Internet。

請注意,對於 VM 部分,vnet5它也是一個橋接埠,也不參與路由。主機只是在虛擬機和路由器(192.168.1.1)之間交換幀:不涉及路由。

使用 VPN 和tun0介面

OpenVPN 依賴於 TUN/TAP 驅動程序(在 Linux 上由核心模組提供tun)。司機可以提供:

  • 第 2 層 TAP 介面

它的行為類似於乙太網設備,可以設置為乙太網橋接埠:vnet5由 VM 管理程序創建。

  • 或第 3 層 TUN 介面

它不包括幀資訊(乙太網 MAC 地址)也不處理幀,但僅處理第 3 層或更高層的協議:IPv4 或 IPv6。因此不能將其設置為乙太網橋接埠。tun0這是OpenVPN 在 TUN 模式下創建的 OP 。

OpenVPN 也可以使用可以橋接的 TAP 模式,但這也需要重新配置遠端伺服器端和所有網路佈局:遠端伺服器也將是 192.168.1.0/24 LAN 的一部分。OP似乎無法控制它。

因此,讓我們考慮使用 OP 的 TUN 介面可以做什麼:這將在第 3 層完成:路由,而不是在第 2 層。

僅對受信任的 VM 重複使用以前的設置

如果主機不包括高級防火牆,包括防火牆限制和/或橋接路徑中的更改,它不能強制 VM 將自己用作網關:像以前一樣橋接的 VM 可以簡單地忽略主機並保留 192.168.1.1作為網關,其流量tun0最終不使用主機的介面。

如果虛擬機可以被信任和重新配置,可以按照br0上述方式應用任何 OpenVPN 設置br0(用enp7s0``br0

  • 在主機上

使用基於策略/源的路由為該特定源選擇不同的路由結果:

ip rule add from 192.168.1.221 lookup 1000
ip rule add iif tun0 lookup 1000
ip route add 192.168.1.0/24 dev br0 table 1000
ip route add default dev tun0 table 1000

設置為路由器:

sysctl -w net.ipv4.ip_forward=1

如果沒有類似的 NAT 規則已經處理這種情況:

 iptables -t nat -A POSTROUTING -s 192.168.1.221 -o tun0 -j MASQUERADE
  • 在 (Linux) VM 上,使用主機作為網關而不是主機的路由器
ip route flush to default
ip route add default via 192.168.1.100

推薦用於不受信任的虛擬機:不要將主機主介面設置為橋接埠

這使得通過虛擬機的流量更容易強制執行,tun0因為它不會查看不應篡改的網路部分。

  • 更改 VM 設置以使用其自己的 IP 網路

範例:192.168.100.0/24 和靜態 IP 192.168.100.2/24(而不是主機的網路 DHCP),預設網關為 192.168.100.1。在 Linux 虛擬機上:

ip address add 192.168.100.2/24 dev enp1s0
ip route add default via 192.168.100.1
  • 在主機上,從初始配置開始(無橋接enp7s0

甚至可以在下面使用零橋(即:直接ip address add 192.168.100.1/24 dev vnet5vnet5設置為橋埠),但libvirt可能會使這更加困難。

只需為 VM 提供一個專用網橋(這裡使用地址 192.168.100.1/24,儘管通常libvirt提供一個預設網橋virbr0,地址為 192.168.122.1/24):

ip link add name br0 up type bridge
ip address add 192.168.100.1/24 dev br0
ip link set dev vnet5 master br0

並且還使用策略路由來更改與兩個涉及的介面的 VM 相關的流量的行為:br0tun0. 像往常一樣,它涉及對備用路由表中現有路由的一些複製和更改。這裡tun0假設只為主機及其虛擬機提供服務。最終目標是:來自VM端的任何東西都被路由到tun端,來自TUN端的任何東西都被路由到VM端,忽略任何不需要的端。

ip rule add iif br0 lookup 2000
ip rule add iif tun0 lookup 2000
ip route add 192.168.100.0/24 dev br0 table 2000
ip route add default dev tun0 table 2000 # layer 3 interfaces don't need a gateway

注意:來自tun0主機的傳入數據包(即:未路由)已由本地路由表處理,不需要表 2000 中的任何其他路由。

設置為路由器:

sysctl -w net.ipv4.ip_forward=1

然後完成 NAT,因為遠端 OpenVPN 伺服器不知道 192.168.100.0/24:

iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o tun0 -j MASQUERADE

如果 VM 仍應能夠訪問 192.168.1.0/24 LAN:

  • 再次更新表 2000 以適應這個

將主表的 LAN 路由複製到表 2000:

ip route add 192.168.1.0/24 dev enp7s0 table 2000
  • 並再次添加適當的 MASQUERADE 規則

…因為 VM 現在位於其他系統不知道的不同 LAN 中:

iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o enp7s0 -j MASQUERADE

(可以進行一些 iptables 規則分解)。

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