基于 WireGuard 搭建虚拟局域网

Laeni
2022-12-06~2022-12-08

平时生活和工作中你是否有遇到过这些问题?

  • 在家需要远程公司电脑,所以使用向日葵或者TeamViewer,但是这类工具经常卡顿、担心被监视、并且需要保证它们的代理一直在电脑上运行?
  • github经常无法打开、下载慢、clone慢甚至失败?
  • 需要上GoogleYouTube
  • Mac应用商店在公司网络下打开为空白?
  • 需要从百度王盘下载一个文件,但是公司网络无法访问?
  • 电脑是Linux系统,不能使用公司VPN?
  • 在外紧急情况下想通过手机访问公司网络?
  • 家里有一台闲置电脑,想将它作为服务器使用?

内网穿透 vs VPN

实际上,VPN本质上也是内网穿透,但是和我们平时说的内网穿透不同,我们平时说的内网穿透一般是指以frp为代表的端口映射,即将内网某主机的某个指定端口映射到公网服务器上的一个指定端口上,当访问公网服务器的映射端口时,内网穿透软件将该端口接受到的流量转发内网,从而达到从公网访问的目的。

假设现在需要从家里远程访问公司Windows桌面,并通过frp实现。

  1. 简单映射方案

    图1所示,如果从家里访问172.1.2.3:3389,只需要访问119.2.3.4:23389即可达到目的。但是这样虽然解决了我们远程的问题,同时也带来了新的问题,那就是远程桌面端口只接暴露在公网,存在很大的安全隐患。

  2. 安全方案(STCP/SUDP)

VPN一般是基于IP地址进行管控,只要一台机器到另一台机器网络是同的,那我们就可以值接访问该机器的任何端口,并且默认情况下,所有VPN网络下的机器,我们都可以随意访问。

为什么是WireGuard

VPN产品千千万,为什么选择WireGuard?

官网:WireGuard是一个非常简单但快速和现代的VPN,它利用最先进的加密技术。它的目标是比IPsec更快,更简单,更精简,更有用,同时避免了巨大的头痛。它打算比OpenVPN的性能高得多。WireGuard被设计为一种通用VPN,用于在嵌入式接口和超级计算机上运行,适用于许多不同的情况。它最初是为Linux内核发布的,现在是跨平台的(Windows,macOS,BSD,iOS,Android)并且可以广泛部署。它目前正在大量开发中,但它已经被认为是业内最安全、最易于使用和最简单的 VPN 解决方案。

性能好

同时使用同一台服务器的公网IP和VPN虚拟内网IP进行Ping测试,分别进行3次,每次发送20个包:

次数公网虚拟内网
1--- 159.xx.xx.xx ping statistics ---10 packets transmitted, 10 received, 0% packet loss, time 9015msrtt min/avg/max/mdev = 8.502/9.105/11.954/0.965 ms--- 10.10.1.1 ping statistics ---10 packets transmitted, 10 received, 0% packet loss, time 9015msrtt min/avg/max/mdev = 10.152/10.656/11.604/0.449 ms
2--- 159.xx.xx.xx ping statistics ---10 packets transmitted, 10 received, 0% packet loss, time 9016msrtt min/avg/max/mdev = 10.428/10.807/11.379/0.319 ms--- 10.10.1.1 ping statistics ---10 packets transmitted, 10 received, 0% packet loss, time 9014msrtt min/avg/max/mdev = 10.053/10.453/10.776/0.187 ms
3--- 159.xx.xx.xx ping statistics ---10 packets transmitted, 10 received, 0% packet loss, time 9010msrtt min/avg/max/mdev = 8.730/9.328/10.889/0.750 ms--- 10.10.1.1 ping statistics ---10 packets transmitted, 10 received, 0% packet loss, time 9014msrtt min/avg/max/mdev = 8.335/10.320/11.350/0.744 ms

由上面测试结果可知,即使VPN数据包采用了加密传输,但是性能几乎不受影响。

该性能得益于先进的加密技术,因为在同等安区强度下,采用的非对称加密算法Curve25519所需要的密钥长度更低,计算速度也更快。

简单

代码和规划:从Linux 内核5.6开始,已经将 WireGuard 合并,所以这决定了它永远不会过于复杂,并且它目前仅有四千多行代码。WireGuard 的目的仅仅是专注于 VPN 核心功能,其他辅助功能(比如帐号、流量统计等)不属于 WireGuard 的范围。

使用:WireGuard 的其中一个目标就是易用性,因为它就像是平常我们用的SSH一样:如果两台设备需要安全通信,只需要相互交换公钥即可。

安全

  1. 上面说到,如果需要通信,则必须相互交换公钥,也就是说 WireGuard 节点之间的通信使用了非对称加密技术。一般情况下,默认的加密已经很安全了,但是如果有抗量子破解需求,则还可以在非对称加密的基础上额外加一层对称加密。

  2. 此外,由于 WireGuard 限制,如果需要使用使用同一套对称密钥,则中间至少应个2个节点(如下图中,只有AD能使用同一套密钥,否则不能正常工作),而实际使用中,一般都是每个节点都由唯一的密钥,所以即使有密钥泄露,也能很大程度降低风险。

    A --- B --- C --- D
    

方便

  1. 再也不用需要翻墙的时候开启VPN,不需要的时候关闭。
  2. 公司和家庭网(主要指个人笔记本)可以随时相互访问。

案例

以下案例用到的节点相关信息如下:

节点名节点公网IP虚拟IP规划wg密钥节点地域备注
c1119.23.74.8610.2.1.1/24pri: CG+bTCcBDJNSrZpn20agJZ/sxUme2IDY2EDHGLYDuH0=pub: eJiVaMlpODRZZvijCh/RZ35Je7j6p6UgUiptgInnp24=深圳云服务器
c28.219.59.3310.2.1.2/24pri: OIv7qBkjoLqEANvaSiFJubWELlbZeCLEHeNf9eEV+F4=pub: MnenNYGmfb+nLkyV2boNQFPKF9jjOkZ8Z4XpobQHwFo=新加坡云服务器
local-10.2.1.3/24pri: mAbillYOFrevzGGpJXw8jqKTN3CH8jf5v7Y+pSV0JmY=pub: 9q0YYF9bos1vgyeQhpNl8sKYTtfko+XmC9j+NOzf8Vg=-笔记本电脑

以上节点全部为Ubuntu,并已安装了WireGuard,安装非常简单,一条命令即可,其他系统可参考官网。

  1. 手动采用wg命令进行组网,实现c1local节点之间相互访问.

    c1:

    # step.1 生成节点密钥对
    $ wg genkey > private `# 每个节点都要独立创建自己的密钥对,密钥对不能公用。`
    $ cat private | wg pubkey `# 从私钥中提取公钥`
    eJiVaMlpODRZZvijCh/RZ35Je7j6p6UgUiptgInnp24=
    
    # step.2 添加一个网络接口(可通过 ip address 查看当前已有的网络接口,初始状态为 'lo' 和 'eth0')
    $ ip link add wg0 type wireguard `# 接口名为'wg0',接口类型为'wireguard',只有安装了wireguard才能使用该类型`
    $ ip addr add 10.2.1.1/24 dev wg0 `# 设置接口的ip地址`
    $ sudo wg set wg0 private-key private `# 设置接口私钥`
    $ ip link set wg0 up
    
    # step.3 加入对等节点(local)
    $ wg set wg0 peer 9q0YYF9bos1vgyeQhpNl8sKYTtfko+XmC9j+NOzf8Vg= allowed-ips 10.2.1.1/32 endpoint 119.23.74.86:47833
    
    # 删除
    $ ip link delete dev wg0
    

    local:

    # step.1 生成节点密钥对
    $ wg genkey > private `# 每个节点都要独立创建自己的密钥对,密钥对不能公用。`
    $ cat private | wg pubkey `# 从私钥中提取公钥`
    9q0YYF9bos1vgyeQhpNl8sKYTtfko+XmC9j+NOzf8Vg=
    
    # step.2 添加一个网络接口(可通过 ip address 查看当前已有的网络接口,初始状态为 'lo' 和 'eth0')
    $ ip link add wg0 type wireguard `# 接口名为'wg0',接口类型为'wireguard',只有安装了wireguard才能使用该类型`
    $ ip addr add 10.2.1.3/24 dev wg0 `# 设置接口的ip地址`
    $ sudo wg set wg0 private-key private `# 设置接口私钥`
    $ ip link set wg0 up
    
    # step.3 加入对等节点(local)
    $ wg set wg0 peer 9q0YYF9bos1vgyeQhpNl8sKYTtfko+XmC9j+NOzf8Vg= allowed-ips 10.2.1.3/32
    
    # 删除
    $ ip link delete dev wg0
    

  2. 使用wg-quick重新实现案例1的需求。

    这里只接使用上面生成的密钥。

    c1:

    $ cat <<EOF | sudo tee /etc/wireguard/wg0.conf
    [Interface]
    Address = 10.2.1.1/24
    PrivateKey = CG+bTCcBDJNSrZpn20agJZ/sxUme2IDY2EDHGLYDuH0=
    
    [Peer]
    # Name = local
    AllowedIPs = 10.2.1.3/32
    PublicKey = 9q0YYF9bos1vgyeQhpNl8sKYTtfko+XmC9j+NOzf8Vg=
    EOF
    

    local:

    $ cat <<EOF | sudo tee /etc/wireguard/wg0.conf
    [Interface]
    Address = 10.2.1.3/24
    PrivateKey = mAbillYOFrevzGGpJXw8jqKTN3CH8jf5v7Y+pSV0JmY=
    
    [Peer]
    # Name = c1
    AllowedIPs = 10.2.1.1/32
    PublicKey = eJiVaMlpODRZZvijCh/RZ35Je7j6p6UgUiptgInnp24=
    Endpoint = 119.23.74.86:39781
    EOF
    
  3. 基于c3进行科学上网.

    $ cat <<EOF | sudo tee /etc/wireguard/wg0.conf
    [Interface]
    Address = 10.2.1.2/24
    PrivateKey = mAbillYOFrevzGGpJXw8jqKTN3CH8jf5v7Y+pSV0JmY=
    
    [Peer]
    # Name = local
    AllowedIPs = 10.2.1.3/32
    PublicKey = 9q0YYF9bos1vgyeQhpNl8sKYTtfko+XmC9j+NOzf8Vg=
    EOF
    

常见问题

  1. 单节点是否稳定?

    这个问题一般是考虑是否会被墙的问题,即网络层面的问题。

    而网络层面的问题应分为两类,一类是普通网络流量,比如SSH或者是HTTP这种很常见的流量,如果连SSH这种都无法访问,那多半是物理层面的问题,这种问题即使出现,一般持续不了很长时间,如果想要尽可能避免这种问题,那服务器所在地域的选择可能至关重要。另一类是仅WireGuard流量无法正常路由,其他流量没问题,这种情况及有可能是防火墙对UDP包进行过滤或者专门针对WireGuard流量包进行拦截导致的,该问题的解决方案可以参考问题2

  2. 如何将WireGuard的通信协议更改为TCP

    如果是因为UDP流量被拦截,那很自然就会想到能不能采用TCP来规避这种情况。但是WireGuard本身不提供这种操作,至于不采用TCP的原因与WireGuard设计有关,详情可以参考官网中漫游相关部分。

    不过,虽然WireGuard本身不支持,但是可以通过其他方式间接实现,比如上面提到的frp。我们可以通过frpWireGuard监听端口映射到墙内公网服务器上,甚至通过SUDP方式映射到本机中,而frp客户端与服务端之间的通信可以伪装成类似HTTPS的流量,这样就解决了问题。

    为了获得更好的性能,如非必要,应尽量采用原生的UDP进行通信,因为再加一层转换非常耗费性能。

  3. 如何做到仅允许某个节点访问部分节点?

  4. 境外服务器流量被莫名消耗?

  5. 能ping通,但是不能作为代理访问其他资源?

  6. 如何代理类似Google这种超多节点的流量?

  7. WireGuard各节点的IP能随便设置吗?


发现错误或想为文章做出贡献? 在 GitHub 上编辑此页面!
© 2020-2025 All Right Reserved 滇ICP备17005647号-2