共计 5452 个字符,预计需要花费 14 分钟才能阅读完成。
背景
之前在企业级环境中,对于物理隔离的不同网络,使用了基于 IPSEC
协议的 VPN 方式进行组网。站内文章:在微软云使用site to site VPN连接到本地网络
而家宽环境下,往往只有单端具备公网IP,甚至两端可能都没有公网IP。那么使用 IPSEC
方式的 VPN 则需要配置 NAT穿透。配置相对就会变复杂。
使用 WireGuard
是一个不错的方案。
简单介绍 WireGuard
官网链接:www.wireguard.com
#简单易用
WireGuard 的目标是像 SSH 一样易于配置和部署。只需交换非常简单的公钥(与交换 SSH 密钥完全一样)即可建立 VPN 连接,其余所有操作均由 WireGuard 透明处理。
#高性能
WireGuard 运行于 Linux 内核态而不是用户态,使用UDP传输数据而不是TCP。它的处理效率更高。需要内核版本 > 5.4。
#通过网络接口实现通信
WireGuard 的工作原理是添加一个(或多个)网络接口,如eth0
或wlan0
,称为wg0
(或wg1
、wg2
、等)。然后可以使用或wg3
正常配置此网络接口,使用或为其添加和删除路由。Wireguard接口就像是一个安全的虚拟网卡,连接了不同设备。
#WireGuard 和 IPsec 都是常用的 VPN 协议,各有优劣。以下是它们的对比:
- 安全性:
- IPsec: 使用成熟的加密算法,如 AES、3DES 等,安全性有保证。支持 IKEv1 和 IKEv2 协议进行密钥交换。
- WireGuard: 使用了最新的加密算法,如 ChaCha20、Poly1305 等,安全性高。密钥交换过程简单,基于 Noise 协议框架。
- 性能:
- IPsec: 由于使用了复杂的加密和认证算法,以及 IKE 协议的开销,性能相对较低。
- WireGuard: 设计简单,使用了高效的加密算法,内核实现优化,性能更高。
- 配置和使用难度:
- IPsec: 配置相对复杂,需要了解更多网络和安全知识。不同厂商的实现可能有差异,互操作性有时会出现问题。
- WireGuard: 配置非常简单,用户友好。跨平台支持良好,不同实现之间互操作性强。
- 穿透 NAT 和防火墙的能力:
- IPsec: 通过 NAT-T(NAT Traversal)技术,可以穿透大多数 NAT 设备。但某些防火墙可能会阻止 IPsec 流量。
- WireGuard: 天然支持 NAT 穿透,不需要额外配置。由于使用 UDP 协议,通常不会被防火墙阻止。
- 移动设备支持:
- IPsec: 大多数移动设备都内置了 IPsec 支持,兼容性好。但移动网络下的重连和漫游支持可能不稳定。
- WireGuard: 提供了 Android 和 iOS 的原生应用,移动设备支持良好。在网络切换时可以快速重连。
- 生态系统和社区支持:
- IPsec: 有广泛的厂商支持和成熟的生态系统,支持各种身份验证方法(如 IKEv2 EAP、证书等)。社区活跃,文档丰富。
- WireGuard: 社区活跃,文档和教程丰富。但生态系统相对较新,第三方工具和插件相对较少。
总的来说,如果注重性能、易用性和 NAT 穿透能力,可以选择 WireGuard;如果注重成熟度、兼容性和灵活的身份验证方式,则 IPsec 是更好的选择。具体选择还需要根据实际需求和网络环境而定。
实施
介绍此次组网的拓扑:
需要说明 WireGuard 本身没有客户端和服务端的定义,这里是为了便于理解。将具有公网IP的云服务器端称为服务端,其他客户端主动与服务端物理IP建链。
WireGuard 的各个节点之间都是对等的,打通之后可以实现任意设备互联,例如从移动设备访问家庭内网的任意设备。
需要注意 WireGuard 并不关心底层网络拓扑,所以可能需要结合 iptables 或者 route table 进行更细致的数据包路由分发。
设备 | 网络环境 | 操作系统 | 物理网卡IP | 虚拟IP |
---|---|---|---|---|
公网云服务器 | 公网 | Ubuntu 20.04 | 1.2.3.4 | 10.200.0.1 |
家庭内网服务器-1 | 内网 | Centos 7 | 192.168.2.11 | 10.200.0.2 |
家庭内网服务器-* | 内网 | – | 192.168.2.* | – |
家庭内网网关 | 内网 | OpenWRT | 192.168.2.1 | – |
移动设备 | 公网 | Android | – | 10.200.0.3 |
WireGuard 使用公钥加密方式进行通信,每个节点都有一对公钥和私钥。通信双方通过交换公钥来建立安全连接,而私钥则用于身份验证和加密数据。
即下文配置中,每端配置文件需要填入本端私钥和对端公钥。
服务端部署
# 安装
apt install wireguard
# 更改内核参数允许IP转发
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf && sysctl -p
# 生成密钥
cd /etc/wireguard/
wg genkey | tee server.key | wg pubkey > server.key.pub
wg genkey | tee nas_centos_1.key | wg pubkey > nas_centos_1.key.pub
wg genkey | tee xiaomi14.key | wg pubkey > xioami14.key.pub
# 生成配置文件
--------------------
# vim /etc/wireguard/wg0.conf
[Interface]
PrivateKey = 【server.key内容】
Address = 10.200.0.1/24
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
ListenPort = 51820
MTU = 1420
# 家宽服务器 CentOS OPS
[Peer]
PublicKey = 【nas_centos_1.key.pub内容】
AllowedIPs = 10.200.0.2/32, 192.168.2.0/24
# 移动设备 小米14
[Peer]
PublicKey = 【xioami14.key.pub内容】
AllowedIPs = 10.200.0.3/32,192.168.2.0/24
--------------------
# 启动服务
wg-quick up wg0
# 检查服务
wg
# 防火墙放行ICMP协议和WG端口,不赘述配置
# 使用systemd管理服务
wg-quick down wg0
systemctl start wg-quick@wg0
systemctl enable wg-quick@wg0
配置文件简单解释下:
- PrivateKey:本端私钥
- Address:本端虚拟IP
- PublicKey:对端公钥
- AllowedIPs:允许被访问的IP列表
在启动服务后,我们可以观察下路由表:
11:38:02 # route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 人工屏蔽 0.0.0.0 UG 0 0 0 eth0
10.200.0.0 0.0.0.0 255.255.255.0 U 0 0 0 wg0
人工屏蔽 0.0.0.0 255.255.255.0 U 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.2.0 0.0.0.0 255.255.255.0 U 0 0 0 wg0
会自动添加 AllowedIPs
中的IP转发到网络接口wg0。
也可以观察下网络接口wg0:
11:43:37 # ifconfig wg0
wg0: flags=209<UP,POINTOPOINT,RUNNING,NOARP> mtu 1420
inet 10.200.0.1 netmask 255.255.255.0 destination 10.200.0.1
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC)
RX packets 129 bytes 7728 (7.7 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 847 bytes 108192 (108.1 KB)
TX errors 15 dropped 3 overruns 0 carrier 0 collisions 0
WireGuard会启动一个新的网络接口用于隧道通信。
家庭内网配置
在 192.168.2.10 上进行配置:
# 安装
yum install wireguard-tools wireguard-dkms
# 更改内核参数允许IP转发
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf && sysctl -p
# 配置iptables规则,进行源地址转换
# 需要配置为开机自动运行,方式因人而异。我写入在了 /etc/rc.local
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# 编辑配置文件
11:57:07 # bim /etc/wireguard/wg0.conf
[Interface]
PrivateKey = 【nas_centos_1.key内容】
Address = 10.200.0.2/32
DNS = 114.114.114.114
[Peer]
PublicKey = 【server.key.pub内容】
AllowedIPs = 10.200.0.0/24
PersistentKeepalive = 60
Endpoint = 1.2.3.4:51820
# 启动服务
wg-quick up wg0
# 检查服务
wg
# 防火墙放行ICMP协议和WG端口,不赘述配置
# 使用systemd管理服务
wg-quick down wg0
systemctl start wg-quick@wg0
systemctl enable wg-quick@wg
安卓客户端配置
配置文件参考家庭内网客户端配置,修改 Address、PrivateKey、PublicKey 的值即可,然后启动隧道。
测试
从公网服务器 ping 其他家庭内网设备:
12:13:27 # ping 10.200.0.2
PING 10.200.0.2 (10.200.0.2) 56(84) bytes of data.
64 bytes from 10.200.0.2: icmp_seq=1 ttl=64 time=21.8 ms
64 bytes from 10.200.0.2: icmp_seq=2 ttl=64 time=21.3 ms
64 bytes from 10.200.0.2: icmp_seq=3 ttl=64 time=21.3 ms
^C
--- 10.200.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 21.265/21.455/21.753/0.213 ms
12:13:31 # ping 192.168.2.11
PING 192.168.2.11 (192.168.2.11) 56(84) bytes of data.
64 bytes from 192.168.2.11: icmp_seq=1 ttl=63 time=21.6 ms
64 bytes from 192.168.2.11: icmp_seq=2 ttl=63 time=21.6 ms
64 bytes from 192.168.2.11: icmp_seq=3 ttl=63 time=21.2 ms
^C
--- 192.168.2.11 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 21.242/21.477/21.614/0.166 ms
12:13:38 # ping 192.168.2.1
PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=63 time=19.5 ms
64 bytes from 192.168.2.1: icmp_seq=2 ttl=63 time=20.4 ms
64 bytes from 192.168.2.1: icmp_seq=3 ttl=63 time=20.8 ms
^C
--- 192.168.2.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 19.479/20.229/20.793/0.552 ms
总结
网上检索的方案,大部分只会介绍基于虚拟IP通信,即每个客户端都需要单独安装wg并部署。并且无法用原本内网IP通信。
而我觉得这样不优雅,家庭内网中有多台设备,我是期望直接打通整个内网。例如从公网服务器直接与 192.168.2.*通信。
方法为在AllowedIPs
中配置好CIDR,并在内网唯一一台wg客户端上使用 iptables 进行源地址转换。这样只需要部署1个客户端,极大减少了复杂度。