wireguard作爲一個微皮恩的後起之秀,具備配置簡單,上手快速的特點,而且由於其太過於先進,對IPv6的支持非常好,可以給每一個加入進來的節點分配一個本地組播IPv6+內網IPv4地址。而且其還有一個非常厲害的優點,就是可以輕鬆假設一個非星形的微皮恩網絡,這在Open微皮恩上比較難以實現的。
由於wireguard這個協議過於先進,所以linux內核版本如果低了還裝不上,這裏使用Ubuntu 18.04爲例介紹安裝和配置過程。本文所實現的效果就是你的一臺在IPv4 Only環境下的服務器或PC,能夠同時訪問IPv4網絡和IPv6網絡上的站點,並且具備一個全局單播IPv6地址,這樣其他人如果有IPv6網絡就可以直接通過IPv6地址來訪問你這臺IPv4環境中的服務器,化普通服務器爲雙棧服務器。但是有一個前提要求,就是你需要一臺IPv6+IPv4的雙棧服務器來作爲wireguard的Server端可以,這臺Server端僅僅是做網絡轉發用,所以配置不需要太高,帶寬足夠大就行。可惜目前國內較火的雲主機提供商騰訊雲,阿里雲,華爲雲等均沒有雙棧服務器可以選擇,所以此處我選擇一家美國的雲主機服務商提供的雙棧服務器,1核512M內存來做示範。
首先要在我們的服務端雙棧服務器上安裝wireguard,操作系統爲Ubuntu 18.04,其他版本可能會碰到內核版本太低的問題
sudo add-apt-repository ppa:wireguard/wireguard
dudo apt-get update
dudo apt-get install wireguard
這樣wireguard就安裝完成了
然後我們編寫一個配置文件,由於wireguard協議沒有server端和客戶端之分,大家都是平等的節點,只是在網絡路由上有區別,互相之間通過一對密鑰來認證,所以我們首先來生成服務端的一對密鑰和客戶端的一對密鑰
生成密鑰使用wg genkey命令可以生成一個私鑰,然後wireguard有一個方法能夠根據私鑰來算出公鑰,密鑰並沒有server和client之分(這點不同於Open微皮恩的SSL密鑰),於是我們這樣來生成
# wg genkey
YIFnXXCCt1H1KD/UcRZ7dr91dXjdKSFnUEZVBmkHdFs=
# echo "YIFnXXCCt1H1KD/UcRZ7dr91dXjdKSFnUEZVBmkHdFs=" | wg pubkey
T0hbccLqGqfapjoQ5ijgxQDRhQ4KPuqeYQIkKxWRiHM=
如上所示,先生成一個私鑰,然後通過管道傳給 wg pubkey方法就生成了一個公鑰,於時我們就有了一個密鑰對
私鑰:YIFnXXCCt1H1KD/UcRZ7dr91dXjdKSFnUEZVBmkHdFs=
公鑰:T0hbccLqGqfapjoQ5ijgxQDRhQ4KPuqeYQIkKxWRiHM=
顧名思義,私鑰就是每個節點自己知道,別人不知道,用來解密流量的。公鑰就是自己可以不知道但是和你相連的節點必須知道,用來認證你並且給你發流量的。
由於我們有兩個節點,所以我們用上面的方法再生成一對密鑰
私鑰2:YDPB08gE6pxmSsUOEYmPcl6AovjJdWw8cvkkXUErclg=
公鑰2:bgbcIhmmoxsC4PPo6627A6Md+/OyHF224Rd8zQjzd1U=
然後我們開始編寫服務端的配置文件,此處我們把先生成的那對密鑰交給服務端
vi /etc/wireguard/wg0.conf
[Interface]
ListenPort = 36889
PrivateKey = YIFnXXCCt1H1KD/UcRZ7dr91dXjdKSFnUEZVBmkHdFs=
Address = 10.0.20.1/24, fd86::1/64
PostUp = ip6tables -t nat -A POSTROUTING -o ens3 -j MASQUERADE; iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE
PostDown = ip6tables -t nat -D POSTROUTING 1; iptables -t nat -D POSTROUTING 1
[Peer]
Endpoint = 10.0.20.2:36889
PublicKey = bgbcIhmmoxsC4PPo6627A6Md+/OyHF224Rd8zQjzd1U=
AllowedIPs = 10.0.20.2/32, fd86::2/64
由於wireguard是類似於點對點的微皮恩,所以每個節點上的配置文件要寫上自己的私鑰和別的節點的公鑰,再[interface]節點上寫自己的私鑰,該節點只有一個,代表自己。再[peer]節點上寫上其他節點的公鑰,[peer]節點可以寫一個或多個。Address就是自身配置的地址,兩個節點之間要統一起來,儘量使用內網地址,如192.168.0.0/16,10.0.0.0/8,172.17.0.0/16這樣的地址,IPv6也不要用2000::以上的地址,以免和公網上的衝突,我這裏使用的是fd86::。
AloowedIPs不是說允許哪些IP連接進入,而是說哪些目的地址的IP要路由到該節點去,此處我們就把發送到10.0.20.2的數據包發送到我們的客戶端服務器去
PostUP和PostDown是wireguard再啓動前和啓動後執行的腳本,可以直接寫腳本,用;分割,也可以用sh "腳本文件路徑" 的方式。這裏我寫的兩條是爲該服務器增加路由器的功能,即根據目標地址選擇相應的網卡進行NAT,我這臺服務器上配有公網IP的網卡爲ens3,要根據實際情況來設置。
注意,由於我們的雙棧服務器要當成路由器來使用,所以要打開內核的相關模塊,並且要打開防火牆
vi /etc/sysctl.conf 重點是下面這兩行
# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1
# Uncomment the next line to enable packet forwarding for IPv6
# Enabling this option disables Stateless Address Autoconfiguration
# based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1
然後使用下面語句來生效
sysctl -p
防火牆配置屬於基礎知識,這裏不再贅述
然後我們啓動服務端的wireguard服務
wg setconf wg0 /etc/wireguard/wg0.conf
wg-quick up wg0
其中,第一句有可能會報Address的異常,我們不用管,只要第二局能啓動wg0網卡即可,然後可以通過ifconfig命令查看當前的網卡配置
root@vultr:~# ifconfig
ens3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 45.66.229.137 netmask 255.255.254.0 broadcast 45.77.229.255
inet6 fe80::5400:1ff:fee9:1cb8 prefixlen 64 scopeid 0x20<link>
inet6 2401:19f0:7400:84fe:5400:1ff:fee9:1cb8 prefixlen 64 scopeid 0x0<global>
ether 56:00:01:e9:1c:b8 txqueuelen 1000 (Ethernet)
RX packets 60027 bytes 29461061 (29.4 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 65477 bytes 29978573 (29.9 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 226 bytes 20481 (20.4 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 226 bytes 20481 (20.4 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
wg0: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1420
inet 10.0.20.1 netmask 255.255.255.0 destination 10.0.20.1
inet6 fd86::1 prefixlen 64 scopeid 0x0<global>
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC)
RX packets 20216 bytes 3230204 (3.2 MB)
RX errors 92 dropped 42 overruns 0 frame 92
TX packets 20985 bytes 19153392 (19.1 MB)
TX errors 42 dropped 163 overruns 0 carrier 0 collisions 0
然後開始寫客戶端節點,也就是IPv4環境的服務器的配置文件,和服務端節點的語法一樣,不同的就是路由策略和密鑰
[Interface]
PrivateKey = YDPB08gE6pxmSsUOEYmPcl6AovjJdWw8cvkkXUErclg=
Address = 10.0.20.2/24, fd86::2/64
[Peer]
PublicKey = T0hbccLqGqfapjoQ5ijgxQDRhQ4KPuqeYQIkKxWRiHM=
Endpoint = 45.66.229.137:36889
AllowedIPs = 0.0.0.0/0, ::/0
客戶端的配置文件相當於把服務端的調換一下位置,然後把各自的弓腰換乘私鑰,私鑰換成公鑰,這裏的[Peer]的Endpoint要填寫服務端wireguard連接的IP和端口,AllowedIPs 這個比較有誤導性,不是說限制哪些IP可以連接的意思,而是說哪些目的地址的IP需要路由到該節點的意思。這裏就是把所有的IPv4地址和IPv6地址都轉發到服務端去。在windows機器上0.0.0.0/0這種寫法可能會導致IPv4不通,還需要我們單獨把服務端的IP寫一條路由指向公網網卡,然後寫成0.0.0.0/1,128.0.0.0/1的形式。
然後客戶端也通過一樣的方式啓動wireguard,此時我們在服務端ping 客戶端的IPv4 和IPv6地址,就可以通了
ping 10.0.20.2
ping fd86::2
此時客戶端也可以訪問IPv6站點了,看到自己在外網的IP就是wireguard服務端在外網的IPv6地址。
此時客戶端只有一個內網的IPv6地址,沒有公網的全局單播地址,那麼要怎樣才能從公網通過IPv6直接訪問我們的客戶端呢。
因爲我們在購買雲主機的時候,雲主機廠商往往會給你一個/64的地址,也就是說你的雙棧服務器可以配置2^64個全局單播的IPv6地址,一輩子都用不完,我們只需在服務端拿出一個IPv6地址,然後做DNAT轉發,就可以把發送到該IPv6地址的數據包全部通過wireguard轉發給客戶端了,實現方法如下
首先給服務端雙棧服務器配置兩個IPv6地址
vi /etc/netplan/10-ens3.yaml
network:
version: 2
renderer: networkd
ethernets:
ens3:
dhcp4: no
addresses: [45.66.229.137/23,'2401:19f0:7400:84fe:5400:01ff:fee9:1cb8/64','2001:19f0:7400:84fe::2/64','2001:19f0:7400:84fe::3/64','2001:19f0:7400:84fe::4/64']
gateway4: 45.66.1.1
nameservers:
addresses: [108.61.10.10]
routes:
- to: 169.254.0.0/16
via: 45.66.1.1
metric: 100
注意網關和DNS要根據實際來設置
2401:19f0:7400:84fe:5400:01ff:fee9:1cb8/64是運營商通過DHCP分配的地址,2001:19f0:7400:84fe::2/64是我要分配給客戶端的地址,剩下那幾個::3 和::4是留着備用的地址
然後使用下面命令來生效
netplan apply
然後使用ifconfig就會發現這幾個地址都配置上了,在外網也能ping通這幾個新加的IPv6地址
ens3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 45.66.229.137 netmask 255.255.254.0 broadcast 45.66.229.255
inet6 fe80::5400:1ff:fee9:1cb8 prefixlen 64 scopeid 0x20<link>
inet6 2401:19f0:7400:84fe::2 prefixlen 64 scopeid 0x0<global>
inet6 2401:19f0:7400:84fe::3 prefixlen 64 scopeid 0x0<global>
inet6 2401:19f0:7400:84fe::4 prefixlen 64 scopeid 0x0<global>
inet6 2401:19f0:7400:84fe:5400:1ff:fee9:1cb8 prefixlen 64 scopeid 0x0<global>
ether 56:00:01:e9:1c:b8 txqueuelen 1000 (Ethernet)
RX packets 52116 bytes 27323543 (27.3 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 57379 bytes 27749047 (27.7 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
然後我們只需要使用ip6tables做一條DNAT策略,就可以把某個IPv6地址的數據包全都轉發給客戶端了(服務端不需要做SNAT,因爲客戶端把服務端當成網關了,我們上面的命令會讓服務端自動做SNAT)
ip6tables -t nat -A PREROUTING -d 2401:19f0:7400:84fe::2 -j DNAT --to-destination fd86::2
這樣在客戶端連接好wireguard服務端之後,如果有人在IPv6網絡訪問2401:19f0:7400:84fe::2這個地址的時候,就相當於訪問我們的客戶端服務器了,我們IPv4 Only的客戶端也就變成傳說中的雙棧服務器了。你需要做的只是把服務端的帶寬儘可能提高,延遲儘可能的降低。因爲很多雲主機他的IPv4路由路徑和IPv6的路徑是不一樣的。有時候IPv6的路徑和延遲要遠遠大於IPv4