本文涉及到 WireGuard 的使用介紹、國內(nèi)外流量的分流等內(nèi)容
WireGuard 安裝
在使用 WireGuard 之前,需要分別在服務(wù)器和本地安裝。
由于本人的服務(wù)器上使用 debian 9、本地使用 Arch Linux,因此這里只給出這兩種系統(tǒng)上的安裝方式,其他系統(tǒng)上的安裝可以在官網(wǎng)找到。
Debian
echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable.list
printf 'Package: *
Pin: release a=unstable
Pin-Priority: 150
' > /etc/apt/preferences.d/limit-unstable
apt update
apt install wireguard
Arch Linux
pacman -S wireguard-dkms wireguard-tools
WireGuard 配置
WireGuard 的配置分為 Interface 和 Peer,其中 Interface 可以認(rèn)為是對本地機(jī)器的配置,而 Peer 是配置連進(jìn)來的機(jī)器的
在服務(wù)器和本地的大部分配置是一樣的,先添加一個(gè)接口:
ip link add wg0 type wireguard
如果報(bào)錯(cuò),并提示 RTNETLINK answers: Operation not supported,先檢查下 wireguard 模塊是否已經(jīng)加載:
lsmod | grep wireguard
如果沒有加載,試下執(zhí)行 modprobe wireguard,如果報(bào)錯(cuò),重啟下機(jī)器。
在服務(wù)器端為 wg0 添加一個(gè)地址 192.168.128.1/24
ip addr add 192.168.128.1/24 dev wg0
同樣在本地為 wg0 添加另一個(gè)地址 192.168.128.254/24
ip addr add 192.168.128.254/24 dev wg0
然后分別在服務(wù)器和本地添加 private key
wg set wg0 private-key <(wg genkey)
如果是要用 sudo 來執(zhí)行的,需要使用以下命令:
sudo bash -c 'wg set wg0 private-key <(wg genkey)'
為服務(wù)器添加一個(gè)監(jiān)聽端口,本地使用隨機(jī)端口就行了,不需要固定端口:
wg set wg0 listen-port 12345
以上是 Interface 的設(shè)置,下面配置 Peer。
首先在服務(wù)器上加入本地的 Peer:
需要添加本地的公鑰,可以在本地通過以下命令獲?。?br/>
wg show wg0 public-key
獲取到公鑰后,還要獲取本地 wg0 上的 IP 地址(192.168.128.254)加入到 perr 的 AllowIPs 里:
wg set wg0 peer '<本地的公鑰>' allowed-ips <本地 wg0 上設(shè)置的 IP 地址,如 192.168.128.254/32>
同樣,把服務(wù)器上的公鑰加入本地,這里要把服務(wù)器的外網(wǎng) ip 作為 endpoint,這里以 wireguard.example.org 為例,要不本地就不知道連那臺(tái)服務(wù)器了:
wg set wg0 peer '<服務(wù)器上的公鑰>' allowed-ips 0.0.0.0/0 endpoint wireguard.example.org:12345
注:這里 allowed-ips 使用 0.0.0.0/0,這樣相當(dāng)于 wireguard 全局生效。
現(xiàn)在 wireguard 的配置基本配好了,可以通過以下命令來啟動(dòng):
ip link set dev wg0 up
啟動(dòng) wg0 接口,這時(shí)可以 ping 下服務(wù)器端的地址 ping 192.168.128.1,如果 ping 通說明 wireguard 正常工作了。
如果 ping 不通,檢查下對方的公鑰及 ip 地址是否正確了。
現(xiàn)在本地跟服務(wù)器已經(jīng)在同一個(gè)內(nèi)網(wǎng)上,可以彼此通信了。
但本地現(xiàn)在是無法通過服務(wù)器連接到外面的網(wǎng)絡(luò),如果需要通過服務(wù)器連接到外面的網(wǎng)絡(luò),要在服務(wù)器上設(shè)置流量轉(zhuǎn)發(fā)和 NAT 才可以。
轉(zhuǎn)發(fā)與 NAT
首先,檢查下 ip 轉(zhuǎn)發(fā)是否已開啟:
sysctl net.ipv4.ip_forward
如果等于 1 說明已經(jīng)開啟,否則可以使用:
sysctl net.ipv4.ip_forward=1
來臨時(shí)開啟,如果想永久生效,需要編輯
/etc/sysctl.conf 文件,查找到 net.ipv4.ip_forward 這一行,把最前端的 # 號(注釋)去掉,如果其值不為 1
的,改成 1。如果找不到,就把 net.ipv4.ip_forward=1 加在文件最下面。
然后使用命令 sysctl -p 來使其生效。
接下來檢查下 iptables 里 filter 表的 FORWARD 鏈的 policy 是否為 ACCEPT:
iptables -t filter -L FORWARD
如果 policy 為 DROP,需要允許 wg0 接口才行:
iptables -t filter -A FORWARD -i wg0 -j ACCEPT
iptables -t filter -A FORWARD -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT
然后看下 nat 表的 POSTROUTING 鏈里是否已經(jīng)做了出口的 NAT 了(這里假設(shè)服務(wù)器上連接外網(wǎng)的接口是 eth0):
iptables -t nat -L POSTROUTING -v
如果還沒有,使用以下命令加上:
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PS:如果出口不是 eth0 接口的,把 eth0 換成正真的出口接口
在服務(wù)器設(shè)置好后,還要在本地加上路由,把流量轉(zhuǎn)發(fā)到 wg0 接口上。
本地路由
ip route add <endpoint>/32 via <出口接口的網(wǎng)關(guān)IP> dev <出口接口>
ip route add default via 192.168.128.1 dev wg0 src 192.168.128.254
配置好后,可以在本地 ping 下 8.8.8.8,如果 ping 的通,并且 tracepath 8.8.8.8 的路由里有 192.168.128.1,說明已經(jīng)通了。
wg-quick
通過這樣配置后就可以使用 WireGuard 作為 VPN 上網(wǎng)了,但當(dāng)前配置會(huì)在重啟后失效。
如果每次重啟都手動(dòng)配置的話,比較麻煩。還好,WireGuard 提供了 wg-quick 命令,該命令可以讀取和保存配置文件。
并且 wg-quick 也提供也 systemctl 的服務(wù)配置,這樣可以設(shè)置開機(jī)自啟動(dòng)。
wg-quick 默認(rèn)的配置目錄為 /etc/wireguard,文件以 wireguard 的接口名(如上文中的 wg0)為文件名,文件名后綴為 .conf。
以下分別是服務(wù)器和本地的配置文件,保存到 /ett/wireguard/wg0.conf:
服務(wù)器:
[Interface]
Address = <服務(wù)器上設(shè)定 wg0 接口的地址,如:192.168.128.1/24>
PrivateKey = <使用 `wg-genkey` 生成的私鑰>
ListenPort = <服務(wù)器上 wg0 監(jiān)聽的端口,如:1234>
[Peer]
PublicKey = <本地的公鑰,可以使用 `echo <本地私鑰> | wg-pubkey` 生成>
AllowedIPs = <本地 wg0 接口上的地址,如:192.168.128.254/32>
本地:
[Interface]
Address = <本地設(shè)定 wg0 接口的地址,如:192.168.128.254/24>
PrivateKey = <使用 `wg-genkey` 生成的私鑰>
[Peer]
PublicKey = <服務(wù)器的公鑰,可以使用 `echo <服務(wù)器私鑰> | wg-pubkey` 生成>
AllowedIPs = 0.0.0.0/0
Endpoint = <服務(wù)器外網(wǎng)地址:服務(wù)器上 wg0 監(jiān)聽的端口,如:0.1.2.3:1234>
配置好后,可以使用 wg-quick up wg0 來啟動(dòng)(注意,如果你按照了上面 [WireGuard 配置](#WireGuard 配置) 命令手動(dòng)配置過,需要先刪除 wg0 接口和對應(yīng)的路由才行)。
如果測試沒問題后,可以使用 systemctl enable [email protected] 來設(shè)置開機(jī)自啟動(dòng)。
優(yōu)化國內(nèi)外流量
通過上面設(shè)置好后,雖然可以通過 WireGuard VPN 上網(wǎng)了,但有個(gè)問題,這個(gè) VPN 是全局性的,即所有的流量都會(huì)從 VPN 里出去。
如果服務(wù)器在美國的話,在上國內(nèi)的網(wǎng)站時(shí),會(huì)繞了一圈,延時(shí)非常大。這時(shí),我們可以通過策略路由的方式,分流國內(nèi)外的流量,使國內(nèi)的流量不用走 VPN。
在上面通過 wg-quick 啟動(dòng)過,如果本地配置里 AllowedIPs 設(shè)置了 0.0.0.0/0,意思是全局生效,其主要也是通過策略路由來實(shí)現(xiàn)的。
下面是 wg-quick 啟動(dòng)時(shí)的日志:
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip address add 192.168.128.254/24 dev wg0
[#] ip link set mtu 1420 dev wg0
[#] ip link set wg0 up
[#] wg set wg0 fwmark 51820
[#] ip -4 route add 0.0.0.0/0 dev wg0 table 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
以上的日志信息可以看出是條條命令來的,通過這些命令,大概可以猜得出 wg-quick 是如何啟動(dòng)的:
首先使用 ip link add wg0 type wireguard 添加一個(gè)名為 wg0、類型為 wireguard 的虛擬接口;
然后通過 wg setconf wg0 /dev/fd/63 加載配置,從 /dev/fd/63 可以看到,配置應(yīng)該是通過 process substitution 的方式加載進(jìn)來的;
ip address add 192.168.128.254/24 dev wg0 這條命令上面也提到過,就是為 wg0 接口添加一個(gè) IP 地址的;
ip link set mtu 1420 dev wg0 設(shè)置 wg0 接口上的 IP 包的 mtu 值;
ip link set wg0 up 啟動(dòng) wg0 接口
wg set wg0 fwmark 51820 為 wg0 接口上的包添加一個(gè) fwmark 值,主要為了下面命令里策略路由用的;
ip -4 route add 0.0.0.0/0 dev wg0 table 51820 為一個(gè) id 為 51820 表添加默認(rèn)的路由,該路由的通過 wg0 接口
ip -4 rule add not fwmark 51820 table 51820 這條命令就是主要的策略路由,通過以上三條命令就可以實(shí)現(xiàn)全局的流量轉(zhuǎn)發(fā)了。
由于策略路由是有優(yōu)先級的,所以我們可以在把所有國內(nèi)的 IP 段添加到優(yōu)先于上面的這條策略路由,這樣就可以不用經(jīng)過 wg0 接口了。
首先要獲取到國內(nèi)的 IP 段,可以通過到 apnic 查詢到國內(nèi)的 IPv4 地址段。
該頁面里的 IPv4 格式是:起始地址|地址數(shù)量,但 ip rule 要求 CIDR 格式格式,所以需要轉(zhuǎn)換下。轉(zhuǎn)換起來也挺簡單,這里地址數(shù)量都是 2 的 n 次方,因此對其以 2 為底求地址數(shù)量的對數(shù),然后用 32 減去其對數(shù)就可以了。
例如:
apnic|CN|ipv4|45.249.112.0|1024|20160511|allocated
起始地址是 45.249.112.0,數(shù)量是 1024,即 2^10,因此可轉(zhuǎn)換成 CIDR 格式是:45.249.112.0/22,加入到策略路由就是:
ip rule add to 45.249.112.0/22 priority 1024
priority 1024 就是設(shè)置優(yōu)先級的,數(shù)字小的優(yōu)先級高
apnic
里的分配給國內(nèi)的 IP 段比較分散,我統(tǒng)計(jì)了下,大概有 8 千多行。我們不可能手動(dòng)添加的,因此我寫了一個(gè) Node.js 腳本 來下載
apnic 的最新分配版,然后轉(zhuǎn)換下,可以導(dǎo)出成一個(gè) shell 腳本來運(yùn)行, shell 腳本里就是一條條上面的那種命令了。
雖然運(yùn)行 shell 腳本后,把規(guī)則添加到策略路由里了,但這些路由規(guī)則也是運(yùn)行時(shí)生效的,下次重啟電腦后需要重新加載。這里可沒有現(xiàn)成的自啟動(dòng)腳本,難道還要寫個(gè)自啟動(dòng)腳本嗎?
還好 wg-quick 里提供了相應(yīng)的鉤子,可以在 wg-quick 啟動(dòng)、關(guān)閉時(shí)執(zhí)行一條 shell 命令,這樣我們就可以把上面的 shell 腳本添加到 wg-quick 的配置文件里去了。這樣就不詳細(xì)寫了,具體可以看這里的示例。
這里有個(gè)問題,由于 shell 腳本里的命令太多了,執(zhí)行起來需要幾秒的時(shí)間。
這里有個(gè)方案,就是先導(dǎo)入 shell 腳本一遍,然后使用 ip rule save 導(dǎo)出保存,在 wg-quick 里通過 ip rule restore 還原配置就可以了,這樣速度很多,基本不用 1 秒就可以了。
但是在用 ip rule save 導(dǎo)出時(shí),會(huì)把所有的規(guī)則都導(dǎo)出來了,包含了系統(tǒng)默認(rèn)的和 wg-quick 添加的。再導(dǎo)入時(shí),會(huì)出現(xiàn)規(guī)則重復(fù)或混亂的情況。至于怎么解決,這里就不展開說了,有興趣的可以去研究下。
“智能” DNS
下面說下另一個(gè)問題。
眾所周知,在國內(nèi),有些域名已經(jīng)被污染了,使用運(yùn)營商提示的
DNS 服務(wù)器解析出來的是不對的 IP。因此我們需要一個(gè)安全的 DNS 服務(wù)器,CloudFlare 就提供這么一組 DNS 服務(wù)器,其提供的
1.1.1.1 和 1.0.0.1 支持 DNS-over-TLS,可以有效的防止被中間人攔擊污染。
但有個(gè)問題,在我這里訪問 1.1.1.1 比較慢,ping 1.1.1.1 顯示有 150ms 左右,如果所有的域名都通過 1.1.1.1 來解析的話,一些未被污染的域名訪問起來會(huì)受到影響。
還好有網(wǎng)友維護(hù)了一個(gè)
ChinaGFW 的列表,里面包含了被污染的域名,剛好我本地已經(jīng)搭建了 unbound 域名服務(wù)器,而且 unbound 支持
DNS-over-TLS,這樣就可以把被污染的域名加入到 unbound 的規(guī)則里,把這些域名通過 1.1.1.1
來解析,其他域名還是走運(yùn)營商提示的 DNS 來解析。
這里 是一個(gè) unbound 配置文件,里面包含的被污染的域名從 ChinaGFW 里轉(zhuǎn)出來的,里面的內(nèi)容類似:
forward-zone:
name: 'google.com'
forward-addr: 1.1.1.1@853
forward-addr: 1.0.0.1@853
forward-ssl-upstream: yes
name 表示被污染的域名,forward-addr 表示向上一級查詢的 DNS 服務(wù)器,可以有多個(gè),forward-ssl-upstream 表示開啟 DNS over TLS 功能。
配置文件的最后使用
這是一個(gè)獨(dú)立的配置文件,可以把它放到 /etc/unbound/ 下,然后在 /etc/unbound/unbound.conf 配置文件里加入 include: /etc/unbound/dns-over-tls.conf 來引入它。
加入后重啟 unbound 服務(wù)就可以生效了。
24小時(shí)免費(fèi)咨詢
請輸入您的聯(lián)系電話,座機(jī)請加區(qū)號