# WireGuard 多跳智能组网

- 作者的开发笔记：[WireGuard 多跳智能组网功能开发笔记](https://vaala.cat/posts/frp-panel-with-wireguard/)，点开有好玩的 Demo 哦！

> 组网功能目前处于测试阶段（最低支持版本：v0.1.25），可能存在一些问题，欢迎加入QQ群、提交Issue、发送邮件反馈

> 组网功能目前仅支持 Linux 操作系统组网

frp-panel 目前内置了 wiregaurd-go 用于实现组网功能。并且实现了 wireguard over UDP/Websocket 多跳组网、自定义路由、拓扑，按延迟和带宽智能计算最短路由，可以在复杂网络环境下实现优秀的组网体验。

## 开始组网

### 0. 概念介绍

在开始之前，你需要保证满足以下所有条件

1. 网络中至少有一个 Client 有公网IP作为中继节点
2. 参与组网的设备只能是 Linux 系统
3. 需要保证至少安装了 frp-panel master 和 frp-panel client
4. 需要以 root 用户权限安装 frp-panel client

接下来我们以一个简单介绍一下 frp-panel 组网的概念。

组网侧边菜单栏中，有四个子菜单。名字和对应的作用如下

1. **网络**：同一网络中的 Client 可以互通组网，一个 Client 可以加入多个网络。
2. **设备**：一个 Client 可以绑定多个设备，设备可以加入网络，同一网络中的设备可以互通。
3. **端点**：一个设备可以绑定多个端点，端点可以被其他设备连接，端点一般是公网IP+端口
4. **连接**：同一网络中的两个设备之间可以建立连接，这两个设备至少有一个设备绑定有端点。

这些概念可能比较绕，举一个例子

![组网概念示意图](/images/wg-net-example.svg)

图中，两个框代表了两个 Client。他们处于 `10.10.0.0/24` 这个相同的网络

左侧的Client：
- 拥有一个**设备** wg0 (虚拟网卡)，设备的虚拟IP是 `10.10.0.1`
- 设备 wg0 绑定了一个**端点** `10.10.0.1:51820`，这个端点是公网IP+端口
- 设备 wg0 加入了一个**网络** `10.10.0.0/24`
- 设备 wg0 可以与其他设备在网络 `10.10.0.0/24` 中互通

右侧的Client：
- 拥有一个**设备** wg0 (虚拟网卡)，设备的虚拟IP是 `10.10.0.2`
- 设备 wg0 加入了一个**网络** `10.10.0.0/24`
- 设备 wg0 可以与其他设备在网络 `10.10.0.0/24` 中互通
- 右侧的Client通过 `1.1.1.1:51820` 与左侧的Client建立了一个**连接**，这个连接的**端点**是 `1.1.1.1:51820`

这样，右侧的Client 就可以通过 frp-panel 的组网功能与左侧的Client 进行通信了。

### 1. 准备环境

由于组网依赖操作系统中已有的一些功能，因此需要首先检查环境是否满足要求。

打开终端，如果你的 Linux 系统拥有 `/etc/sysctl.d` 文件夹, 使用:
```bash
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/99-frp-panel.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.d/99-frp-panel.conf
echo 'net.ipv4.ping_group_range = 0 2147483647' | sudo tee -a /etc/sysctl.d/99-frp-panel.conf
sudo sysctl -p /etc/sysctl.d/99-frp-panel.conf
```
否则, 使用 `/etc/sysctl.conf` 文件:
```bash
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv4.ping_group_range = 0 2147483647' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p /etc/sysctl.conf
```

接下来，检查tun设备是否存在，如果存在，则跳过这一步，否则需要自行解决问题（为什么不问问神奇的AI呢）：

```bash
ls /dev/net/tun
```

如果命令成功，则表示可以进行下一步

### 2. 创建网络

点击组网侧边菜单栏中的**网络**，然后点击右上角按钮**新建网络**，填写网络名称和CIDR，如果有ACL需求，请输入ACL，如果没有ACL请忽略。

- **网络名称**：推荐小写英文，不要有特殊字符。
- **CIDR**：填写网络的CIDR，例如 `10.10.0.0/24`，表示网络的IP分配范围，这个例子代表是 `10.10.0.0` 到 `10.10.0.255` 这个范围内的IP都可以被分配。
- **ACL**：填写网络的ACL，可以控制节点之间建立**直接连接**的权限，格式如下：

```json
{
  "acls": [
    { "action": "allow", "src": ["cn"], "dst": ["cn"] },
    { "action": "allow", "src": ["us"], "dst": ["us"] }
  ]
}
```

ACL 是 JSON 格式，`action` 可以是 `allow` 或 `deny`，`src` 和 `dst` 是标签，标签可以是任意字符串，用于圈选设备，可以在后面创建设备时为设备分配标签。

例如，上面的例子表示，网络中的设备 `cn` 可以与设备 `cn` 直接连接，设备 `us` 可以与设备 `us` 直接连接。其他的设备之间无法直接连接。

> 注意⚠️，手动建立的连接不受ACL控制

点击**提交**按钮，网络创建成功。

### 3. 创建端点（非公网节点可跳过）

点击组网侧边菜单栏中的**端点**，然后点击按钮**新建端点**，按照以下要求填写
- **客户端**：选择一个公网客户端
- **主机名称**：填写节点的公网IP地址或域名，例如 `1.1.1.1` 或 `example.com`；
- **端口**：填写节点可对外访问的公网端口，例如 `51820`；
- **类型**：选择端点类型，支持 `ws` 和 `udp`，其中 `ws` 表示 WebSocket 类型，`udp` 表示 UDP 类型；
- **URI**：UDP类型不填URI。ws类型请填写完整URI，例如 `ws://example.com:51820`；

填写完成后点击创建。

### 4. 创建设备

点击组网侧边菜单栏中的**设备**，然后点击右上角按钮**加入网络**，用于将 Client 加入一个已知网络。

按照以下要求填写

- **客户端**：选择一个加入网络的客户端，要求是以 root 用户直接安装在 Linux 操作系统的 Client；
- **网络**：选择一个已知网络；
- **端点（非公网节点可跳过）**：选择一个已创建的端点；
- **接口名称**：填写设备名，要求必须是小写英文+数字的形式，如`frpp0`，推荐使用表单的默认值，格式不正确会造成启动失败。
- **本地地址**：这个设备在网络中的虚拟IP地址，例如 `10.10.0.2`，推荐使用表单的默认值（默认值会自动分配，即便表单显示重复也会自动分配），必须是在网络范围中的IP。
- **端口**：填写设备的端口，例如 `51820`，公网节点推荐与端点端口一致，选择端点时会默认填充；
- **MTU**：填写设备的MTU，例如 `1420`，推荐使用默认值；
- **标签**：用于控制设备之间建立**直接连接**的权限，推荐使用全英文，不要有特殊字符

填写完成后点击**提交**按钮，设备创建成功。

### 5. 测试网络

到这里，如果不出意外，你的设备已经组网成功。你可以点击“网络”菜单选择对应网络，进入“拓扑” tab页，查看自己网络的组网情况。

理论上，只要最短路的拓扑图中，两个节点间有一条路线（无论中间经过了多少跳），那么这两个节点之间就可以通信。

你可以在拓扑图节点上右键点击节点，选择“打开终端”，进入终端界面，测试节点之间是否可以通信。

例如，在 `10.10.0.1` 节点终端输入 `ping 10.10.0.2`，如果ping通，则表示组网成功。

点击每一条边，可以查看连接的详细路由等信息。

### 6. 优化网络（可选）

这一节的配置可以让两个节点选择更加优秀的连接，但不影响整体使用。

如果使用正常，不推荐手动优化，因为手动连接会突破ACL限制、不适应网络变化，错误配置可能导致网络不可用。如果需要手动优化，请谨慎操作。

此时的组网仅基于延迟计算最短路，可能会出现一些不理想的情况。

这时你可以在图中随意找到一个节点，鼠标从右侧的黑色小点拖拽到另一个节点的左侧黑色小点，填写表单建立一个连接（手动连接时不推荐选择端点避免端点变化造成问题）。

这时可以填写真实的带宽，将带宽也加入最短路权重计算。

如果你想两个节点无论何时都直接连接，有两个方法：

1. 配置ACL，让两个节点之间只能通过直接连接通信；
2. 配置手动连接，为他们配置1000Mbps的带宽，让两个节点之间可以直接连接。
