IPv4 only環境下通過Wireguard獲取全局IPv6地址

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章