背景介紹:
??老家有幾臺老舊的電腦裝了一些web服務(wù),但是我在出租屋中如何訪問到這些web服務(wù)呢?這個(gè)涉及到2個(gè)局域網(wǎng)通信問題,本文使用wireguard單向打通2個(gè)局域網(wǎng),實(shí)現(xiàn)出租屋中任意主機(jī)均可以訪問老家web服務(wù)。
0x00 使用wireguard虛擬組網(wǎng)
??WireGuard 是一個(gè)易于配置、快速且安全的開源 VPN,它利用了最新的加密技術(shù)。目的是提供一種更快、更簡單、更精簡的通用 VPN,它可以輕松地在樹莓派這類低端設(shè)備到高端服務(wù)器上部署。Linux創(chuàng)造者Linus Torvalds非常喜歡WireGuard,以至于將其合并到 Linux Kernel 5.6 中。
??阿里云上申請一個(gè)公網(wǎng)ip服務(wù)器(Server),家中局域網(wǎng)有一個(gè)虛擬機(jī)A,在老家192.168.0.0/24網(wǎng)段申請一臺虛擬機(jī)做跳板機(jī),使用wireguard組虛擬局域網(wǎng)。部署成功后可以實(shí)現(xiàn)虛擬機(jī)A、公網(wǎng)服務(wù)器、老家虛擬機(jī)B三臺主機(jī)互相通信。其網(wǎng)絡(luò)拓?fù)鋱D如下所示:

0x01 wireguard訪問同局域網(wǎng)其他機(jī)器
??經(jīng)過第一步后,其實(shí)并沒有達(dá)到我們最終目的。此時(shí)在出租屋里使用虛擬機(jī)已經(jīng)可以訪問老家虛擬機(jī)B了,但是無法訪問虛擬機(jī)B同網(wǎng)段的web服務(wù)器。參考 https://iliasa.eu/wireguard-how-to-access-a-peers-local-network/
??根據(jù)數(shù)據(jù)流向,依次做如下幾個(gè)配置更改:
- 虛擬機(jī)A作為請求發(fā)起方,修改Peer中
AllowedIPs允許192.168.0.0/24流量包流入公網(wǎng)服務(wù)器。 - wireguard公網(wǎng)服務(wù)器收到192.168.0.0/24流量包后,應(yīng)該轉(zhuǎn)發(fā)給虛擬機(jī)B節(jié)點(diǎn),將192.168.0.0/24加入Peer為虛擬機(jī)B的
AllowedIPs。 - 虛擬機(jī)B的wg0網(wǎng)口接受到了來自公網(wǎng)服務(wù)器的192.168.0.0/24流量包后,應(yīng)該將該流量經(jīng)過源ip修正后由ens192網(wǎng)口發(fā)出。主要規(guī)則是
iptables -t nat -A POSTROUTING -o ens192 -j MASQUERADE,該規(guī)則用于當(dāng)流量包從ens192網(wǎng)口發(fā)出時(shí)將源ip地址從10.0.2.0/24統(tǒng)一修正為192.168.0.82。
??至此網(wǎng)絡(luò)拓?fù)鋱D依然沒有改變,相比于上一步新增制定了192.168.0.0/24流量包在整個(gè)wg虛擬網(wǎng)絡(luò)中的處理規(guī)則。虛擬機(jī)A在wireguard的幫助下,可以直接訪問老家web服務(wù)器了。
0x02 配置wireguard節(jié)點(diǎn)為網(wǎng)關(guān)服務(wù)器
??經(jīng)過第二步已經(jīng)實(shí)現(xiàn)了出租屋虛擬機(jī)A訪問老家web服務(wù)器。仔細(xì)思考下,發(fā)現(xiàn)一個(gè)用戶體驗(yàn)的問題:我出租屋里還有手機(jī)/平板,別的電腦和虛擬機(jī)。每增加一個(gè)設(shè)備都要部署一套wireguard服務(wù),那這個(gè)維護(hù)成本就太高了。理想情況是將虛擬機(jī)A配置為網(wǎng)關(guān)服務(wù)器,出租屋中其他機(jī)器流量都從虛擬機(jī)A轉(zhuǎn)發(fā)一下實(shí)現(xiàn)訪問老家的web服務(wù)。于是我在出租屋找到了另外一臺電腦C,嘗試將電腦C的網(wǎng)關(guān)設(shè)置為A服務(wù)器ip地址(192.168.93.128)。相比第一步,網(wǎng)絡(luò)拓?fù)鋱D增加了一臺電腦C,如下圖所示:

但是此時(shí)虛擬機(jī)C并不能成功ping通web服務(wù)器。下面通過抓包排查問題。
保持在虛擬機(jī)C中執(zhí)行ping 192.168.0.81,同時(shí)在虛擬機(jī)A中執(zhí)行 tcpdump -nn -i any icmp進(jìn)行抓包:
spring@spring-virtual-machine:~$ sudo tcpdump -nn -i any icmp
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
20:38:40.192152 ens33 In IP 192.168.93.129 > 192.168.0.81: ICMP echo request, id 3, seq 11, length 64
20:38:40.192201 wg0 Out IP 192.168.93.129 > 192.168.0.81: ICMP echo request, id 3, seq 11, length 64
20:38:41.215779 ens33 In IP 192.168.93.129 > 192.168.0.81: ICMP echo request, id 3, seq 12, length 64
20:38:41.215816 wg0 Out IP 192.168.93.129 > 192.168.0.81: ICMP echo request, id 3, seq 12, length 64
20:38:42.240394 ens33 In IP 192.168.93.129 > 192.168.0.81: ICMP echo request, id 3, seq 13, length 64
20:38:42.240432 wg0 Out IP 192.168.93.129 > 192.168.0.81: ICMP echo request, id 3, seq 13, length 64
20:38:43.263821 ens33 In IP 192.168.93.129 > 192.168.0.81: ICMP echo request, id 3, seq 14, length 64
20:38:43.263860 wg0 Out IP 192.168.93.129 > 192.168.0.81: ICMP echo request, id 3, seq 14, length 64
??在公網(wǎng)網(wǎng)關(guān)服務(wù)器也執(zhí)行tcpdump -nn -i any icmp相同的命令抓包,發(fā)現(xiàn)沒有任何顯示。
根據(jù)以上信息可以推斷出icmp包從虛擬機(jī)A的wg0網(wǎng)卡出去,但是公網(wǎng)服務(wù)器沒收到。
那么到底是包沒發(fā)出去還是服務(wù)器沒收到呢?看虛擬機(jī)A的wg0.conf:
[Interface]
PrivateKey = xxxxxxxxxxx
Address = 10.0.2.3/32
[Peer]
PublicKey = xxxxxxxxxxx
AllowedIPs = 10.0.2.0/24,192.168.0.0/24
Endpoint = xx.xx.xx.xx:xx
PersistentKeepalive = 25
??根據(jù)wg0.conf顯示,wireguard不認(rèn)識192.168.93.129這個(gè)ip,所以不會(huì)把這個(gè)包真的發(fā)出去。
??那么如何在流量包由wg0網(wǎng)卡發(fā)出去前將源地址換掉呢?SNAT(Source Network Address Translation源網(wǎng)絡(luò)地址轉(zhuǎn)換)功能閃亮登場,其作用是將ip數(shù)據(jù)包的源地址轉(zhuǎn)換成另外一個(gè)地址。關(guān)于NAT/SNAT/DNAT的關(guān)系及日常運(yùn)用場景網(wǎng)上有非常多的文章講,這里就不深入講原理了。
通過下述2條命令實(shí)現(xiàn)當(dāng)流量包目標(biāo)地址為10.0.2.0/24或者192.168.0.0/24時(shí)將源ip地址修正為10.0.2.3:
iptables -t nat -I POSTROUTING -s 192.168.93.0/24 -d 10.0.2.0/24 -j SNAT --to-source 10.0.2.3
iptables -t nat -I POSTROUTING -s 192.168.93.0/24 -d 192.168.0.0/24 -j SNAT --to-source 10.0.2.3
??每次wg服務(wù)啟動(dòng)時(shí)都敲這么一串也不是個(gè)辦法,可以加入到wg0.conf文件的PostUp和PostDown配置中。
??看下目前最新的虛擬機(jī)A的wg0.conf配置文件:
[Interface]
PrivateKey = xxxxxxx
Address = 10.0.2.3/32
DNS = 223.5.5.5,114.114.114.114
PostUp = iptables -t nat -I POSTROUTING -s 192.168.93.0/24 -d 10.0.2.0/24 -j SNAT --to-source 10.0.2.3; iptables -t nat -I POSTROUTING -s 192.168.93.0/24 -d 192.168.0.0/24 -j SNAT --to-source 10.0.2.3
PostDown = iptables -t nat -D POSTROUTING -s 192.168.93.0/24 -d 10.0.2.0/24 -j SNAT --to-source 10.0.2.3; iptables -t nat -D POSTROUTING -s 192.168.93.0/24 -d 192.168.0.0/24 -j SNAT --to-source 10.0.2.3
[Peer]
PublicKey = xxxxx
AllowedIPs = 10.0.2.0/24,192.168.0.0/24
Endpoint = xx.xx.xx.xx:xx
PersistentKeepalive = 25
至此,出租屋里面的主機(jī)只要將網(wǎng)關(guān)設(shè)置為虛擬機(jī)A的ip地址(192.168.93.128)均可以訪問老家的web服務(wù)器。