diff --git a/.vitepress/config/cn.ts b/.vitepress/config/cn.ts index dd9eb9e..0c6bec7 100644 --- a/.vitepress/config/cn.ts +++ b/.vitepress/config/cn.ts @@ -32,6 +32,7 @@ export const cn = defineConfig({ { text: '网对网', link: '/guide/network/network-to-network' }, { text: '无 TUN 模式(免 Root 权限)', link: '/guide/network/no-root' }, { text: 'SOCKS5', link: '/guide/network/socks5' }, + { text: '端口转发(Port Forward)', link: '/guide/network/port-forward' }, { text: '搭建共享节点', link: '/guide/network/host-public-server' }, { text: 'P2P 优化', link: '/guide/network/p2p-optimize' }, { text: '魔法 DNS', link: '/guide/network/magic-dns' }, diff --git a/.vitepress/config/en.ts b/.vitepress/config/en.ts index 6391759..cb66e53 100644 --- a/.vitepress/config/en.ts +++ b/.vitepress/config/en.ts @@ -31,6 +31,7 @@ export const en = defineConfig({ { text: 'Network-to-Network', link: '/en/guide/network/network-to-network' }, { text: 'No TUN Mode (No Root Required)', link: '/en/guide/network/no-root' }, { text: 'SOCKS5', link: '/en/guide/network/socks5' }, + { text: 'Port Forward', link: '/en/guide/network/port-forward' }, { text: 'Hosting Public Server', link: '/en/guide/network/host-public-server' }, { text: 'P2P Optimization', link: '/en/guide/network/p2p-optimize' }, { text: 'Magic DNS', link: '/en/guide/network/magic-dns' }, diff --git a/en/guide/network/no-root.md b/en/guide/network/no-root.md index a255632..9c0671d 100644 --- a/en/guide/network/no-root.md +++ b/en/guide/network/no-root.md @@ -4,4 +4,4 @@ Since creating a TUN device requires ROOT permissions, EasyTier provides a metho When using the no TUN mode for networking, nodes can be accessed via virtual IP (TCP, UDP, and ICMP are all supported), and can also act as subnet proxies (using the -n parameter). However, they cannot actively initiate access to other nodes. -To actively access other nodes in no TUN mode, you can use EasyTier's [SOCKS5 server feature](/guide/network/socks5). +To actively access other nodes in no TUN mode, you can use EasyTier's [SOCKS5 server feature](/guide/network/socks5), or use the [Port Forward](/en/guide/network/port-forward) feature to forward local port traffic to a destination address in the virtual network. diff --git a/en/guide/network/port-forward.md b/en/guide/network/port-forward.md new file mode 100644 index 0000000..1f1d15d --- /dev/null +++ b/en/guide/network/port-forward.md @@ -0,0 +1,115 @@ +# Port Forward + +EasyTier provides a port forward feature that "exposes" TCP/UDP sockets on the host to EasyTier's virtual network (overlay), or forwards host port traffic to a destination address (`dst`) within the virtual network. + +Typical use cases: + +- Listen on a local port so other nodes in the virtual network can access a local service through that port. +- Start EasyTier on a node in the virtual network, listen on a port, and forward the traffic to a service on another node in the virtual network, without any extra configuration on the target node. +- In no-TUN mode or restricted environments, use port forward as an alternative to TUN-based access to the virtual network. + +Supported protocols: `tcp` and `udp`. Each rule consists of three parts: a "bind address (host)", a "dst address (virtual network IPv4)", and a "protocol". + +## Network Topology + +Assume the network topology is as follows: multiple nodes (A, B, C) want to access the `5201` service on node D in the virtual network via their local port `5202`. Each node configures its own port forward rule to forward local `127.0.0.1:5202` traffic to `10.144.0.20:5201` in the virtual network. + +```mermaid +graph LR + A1[Node A Local App
127.0.0.1:5202] -->|TCP/UDP| A(EasyTier
Node A) + B1[Node B Local App
127.0.0.1:5202] -->|TCP/UDP| B(EasyTier
Node B) + C1[Node C Local App
127.0.0.1:5202] -->|TCP/UDP| C(EasyTier
Node C) + A -->|Virtual Network Data Plane| D(EasyTier
Node D 10.144.0.20) + B -->|Virtual Network Data Plane| D + C -->|Virtual Network Data Plane| D + D -->|TCP/UDP| S[Target Service
10.144.0.20:5201] + + classDef endpoint fill:#1e90ff,stroke:#ffffff,color:#ffffff + classDef easy fill:#4682b4,stroke:#ffffff,color:#ffffff + + class A1,B1,C1,S endpoint + class A,B,C,D easy + linkStyle 3 stroke:#ffa500,stroke-width:2px,stroke-dasharray:5 5 + linkStyle 4 stroke:#ffa500,stroke-width:2px,stroke-dasharray:5 5 + linkStyle 5 stroke:#ffa500,stroke-width:2px,stroke-dasharray:5 5 + + style A stroke-width:2px + style B stroke-width:2px + style C stroke-width:2px + style D stroke-width:2px +``` + +## Using Port Forward + +Port forward is configured via the `--port-forward` parameter, in the format: + +``` +:/// +``` + +- `proto`: protocol, either `tcp` or `udp`. +- `bind_addr`: the listen address on the host, e.g. `127.0.0.1:5202` or `0.0.0.0:5202`. +- `dst_addr`: destination address in the virtual network, must be an IPv4 literal address, e.g. `10.144.0.20:5201`. + +`--port-forward` can be specified multiple times to configure multiple forwarding rules. + +### TCP Port Forward + +Forward local port `127.0.0.1:5202` to `10.144.0.20:5201` in the virtual network: + +```sh +sudo easytier-core --port-forward tcp://127.0.0.1:5202/10.144.0.20:5201 +``` + +After startup, any program that can reach the bind address can access the `10.144.0.20:5201` service in the virtual network via `127.0.0.1:5202`. + +### UDP Port Forward + +Forward local port `127.0.0.1:5202` to `10.144.0.20:5201` in the virtual network: + +```sh +sudo easytier-core --port-forward udp://127.0.0.1:5202/10.144.0.20:5201 +``` + +### Configuring Multiple Rules + +Multiple rules can be configured at startup by specifying `--port-forward` multiple times, e.g. to expose both TCP and UDP services: + +```sh +sudo easytier-core \ + --port-forward tcp://127.0.0.1:5202/10.144.0.20:5201 \ + --port-forward udp://127.0.0.1:5202/10.144.0.20:5201 +``` + +## Configuring via Configuration File + +In addition to command-line parameters, port forward rules can be written into the configuration file, corresponding to the `port_forwards` field. Each rule has three fields: `bind_addr`, `dst_addr`, and `proto`: + +```toml +[[port_forwards]] +proto = "tcp" +bind_addr = "127.0.0.1:5202" +dst_addr = "10.144.0.20:5201" + +[[port_forwards]] +proto = "udp" +bind_addr = "127.0.0.1:5202" +dst_addr = "10.144.0.20:5201" +``` + +## Modifying Dynamically via Management RPC + +While EasyTier is running, port forward rules can be dynamically added or removed via the management RPC (`ConfigRpcService/PatchConfig`) without restarting the instance. This approach is commonly used in iOS/FFI or programmatic integration scenarios, e.g. iOS calls the PatchConfig RPC via `easytier_ios_call_json_rpc` to modify the instance configuration. + +## Performance + +EasyTier's port forward is built on the virtual network data plane. Native UDP forward can reach close to 999 Mbit/s under a 1 Gbit/s load; TCP forward, after data-plane and host-driver loop optimizations, can reach close to 1.17 Gbit/s per stream. Performance is primarily affected by the data plane and the system network stack. Using the kernel network stack is recommended for higher throughput. + +## Limitations and Notes + +::: warning Note +- **Bind conflict**: The `(protocol, bind address)` combination must be unique. If two rules share the same `(protocol, bind address)` but have different `dst`, the first one binds successfully and the second one fails at startup because the port/address is already in use. The caller must ensure that `(protocol, bind address)` pairs are unique. +- **Destination address restriction**: `dst_addr` must be an IPv4 literal address in the virtual network. If the destination does not exist in EasyTier's routes, a normal network error is returned and there is no fallback to the host network. +- **UDP large packet reordering**: The Core buffer allows a maximum IPv4 UDP payload of 65507 bytes, but under the current MTU and smoltcp limits, extreme reordering may exceed the number of fragments smoltcp can track (at most 16 segments), causing very large packets to be dropped under high reordering. +- **UDP first inbound packet**: The UDP listening socket installs the precise UDP data-plane flow only after it has sent to a peer. A newly bound socket may not receive the first packet from an unknown peer until mutual flows are established. This behavior does not affect the TUN plane or port-forward destinations reachable via TUN. +::: diff --git a/guide/network/no-root.md b/guide/network/no-root.md index ab7c1ee..6af281f 100644 --- a/guide/network/no-root.md +++ b/guide/network/no-root.md @@ -4,4 +4,4 @@ 使用无 TUN 模式组网时,节点可以通过虚拟 IP 被访问(TCP、UDP 和 ICMP 都支持),也可以做子网代理(使用 -n 参数)。但是无法主动发起对其他节点的访问。 -为了在无 TUN 模式下主动访问其他节点,可使用 EasyTier 的 [SOCKS5 服务器功能](/guide/network/socks5)。 +为了在无 TUN 模式下主动访问其他节点,可使用 EasyTier 的 [SOCKS5 服务器功能](/guide/network/socks5),或使用 [端口转发(Port Forward)](/guide/network/port-forward) 功能,将本机端口的流量转发到虚拟网内的目标地址。 diff --git a/guide/network/port-forward.md b/guide/network/port-forward.md new file mode 100644 index 0000000..b9409af --- /dev/null +++ b/guide/network/port-forward.md @@ -0,0 +1,113 @@ +# 端口转发(Port Forward) + +EasyTier 提供端口转发功能,可将宿主机上的 TCP/UDP 套接字"暴露"到 EasyTier 的虚拟网(overlay),或将宿主端口流量转发到虚拟网内的目标地址(dst)。 + +典型使用场景: + +- 在本地监听一个端口,让虚拟网内的其他节点可通过该端口访问到本地服务。 +- 在虚拟网内某节点上启动 EasyTier 并监听端口,将流量转发到虚拟网内另一节点的服务,无需在该目标节点额外配置。 +- 在无 TUN 模式或受限环境下,通过端口转发替代 TUN 接入虚拟网。 + +支持的协议:`tcp` 和 `udp`。每条规则由「bind 地址(宿主)」「dst 地址(虚拟网 IPv4)」「协议」三部分组成。 + +## 网络拓扑 + +假设网络拓扑如下,多个节点(A、B、C)希望通过本机端口 `5202` 访问虚拟网内节点 D 的 `5201` 服务。每个节点各自配置端口转发规则,将本机 `127.0.0.1:5202` 流量转发到虚拟网内 `10.144.0.20:5201`。 + +```mermaid +graph LR + A1[节点 A 本机应用
127.0.0.1:5202] -->|TCP/UDP| A(EasyTier
节点 A) + B1[节点 B 本机应用
127.0.0.1:5202] -->|TCP/UDP| B(EasyTier
节点 B) + C1[节点 C 本机应用
127.0.0.1:5202] -->|TCP/UDP| C(EasyTier
节点 C) + A -->|虚拟网数据平面| D(EasyTier
节点 D 10.144.0.20) + B -->|虚拟网数据平面| D + C -->|虚拟网数据平面| D + D -->|TCP/UDP| S[目标服务
10.144.0.20:5201] + + classDef endpoint fill:#1e90ff,stroke:#ffffff,color:#ffffff + classDef easy fill:#4682b4,stroke:#ffffff,color:#ffffff + + class A1,B1,C1,S endpoint + class A,B,C,D easy + linkStyle 3 stroke:#ffa500,stroke-width:2px,stroke-dasharray:5 5 + linkStyle 4 stroke:#ffa500,stroke-width:2px,stroke-dasharray:5 5 + linkStyle 5 stroke:#ffa500,stroke-width:2px,stroke-dasharray:5 5 + + style A stroke-width:2px + style B stroke-width:2px + style C stroke-width:2px + style D stroke-width:2px +``` + +## 使用端口转发 + +端口转发通过 `--port-forward` 参数配置,参数格式为: + +``` +:/// +``` + +- `proto`:协议,可选 `tcp` 或 `udp`。 +- `bind_addr`:宿主上的监听地址,例如 `127.0.0.1:5202` 或 `0.0.0.0:5202`。 +- `dst_addr`:虚拟网内目标地址,必须是 IPv4 字面地址,例如 `10.144.0.20:5201`。 + +`--port-forward` 可以多次指定,配置多条转发规则。 + +### TCP 端口转发 + +将本机 `127.0.0.1:5202` 端口转发到虚拟网内 `10.144.0.20:5201`: + +```sh +sudo easytier-core --port-forward tcp://127.0.0.1:5202/10.144.0.20:5201 +``` + +启动后,本机或其他可访问该 bind 地址的程序即可通过 `127.0.0.1:5202` 访问虚拟网内的 `10.144.0.20:5201` 服务。 + +### UDP 端口转发 + +将本机 `127.0.0.1:5202` 端口转发到虚拟网内 `10.144.0.20:5201`: + +```sh +sudo easytier-core --port-forward udp://127.0.0.1:5202/10.144.0.20:5201 +``` + +### 同时配置多条规则 + +可在启动时通过多次指定 `--port-forward` 配置多条规则,例如同时暴露 TCP 和 UDP 服务: + +```sh +sudo easytier-core \ + --port-forward tcp://127.0.0.1:5202/10.144.0.20:5201 \ + --port-forward udp://127.0.0.1:5202/10.144.0.20:5201 +``` + +## 通过配置文件配置 + +除命令行参数外,端口转发规则也可写入配置文件,对应字段为 `port_forwards`,每条规则含 `bind_addr`、`dst_addr` 与 `proto` 三个字段: + +```toml +[[port_forwards]] +proto = "tcp" +bind_addr = "127.0.0.1:5202" +dst_addr = "10.144.0.20:5201" + +[[port_forwards]] +proto = "udp" +bind_addr = "127.0.0.1:5202" +dst_addr = "10.144.0.20:5201" +``` + +## 通过管理 RPC 动态修改 + +EasyTier 运行过程中可通过管理 RPC(`ConfigRpcService/PatchConfig`)动态添加或删除端口转发规则,无需重启实例。该方式常用于 iOS/FFI 或编程式集成场景,例如 iOS 通过 `easytier_ios_call_json_rpc` 调用 PatchConfig RPC 修改实例配置。 + +## 性能 + +EasyTier 的端口转发基于虚拟网数据平面实现,原生 UDP 转发在 1 Gbit/s 负载下可接近 999 Mbit/s;TCP 转发经数据平面与宿主-驱动循环优化后,单流吞吐可接近 1.17 Gbit/s。性能主要受数据平面与系统网络栈影响,建议优先使用内核网络栈以获得更高吞吐。 + +## 限制与注意事项 + +- **绑定冲突**:`(协议, bind 地址)` 组合必须唯一。若两条规则使用相同的 `(协议, bind 地址)` 但不同 `dst`,第一条绑定成功后,第二条在启动阶段会因端口/地址已被占用而失败。调用方需保证 `(协议, bind 地址)` 对唯一。 +- **目标地址限定**:`dst_addr` 必须为虚拟网 IPv4 字面地址。若目标在 EasyTier 路由中不存在,会返回正常网络错误,不会回退到宿主网络。 +- **UDP 大包乱序**:Core 缓冲允许最大 IPv4 UDP 有效负载 65507 字节,但在当前 MTU 与 smoltcp 限制下,极端乱序可能超过 smoltcp 能追踪的分片数(最多 16 段),导致极大包在高度乱序下丢包。 +- **UDP 首包入站**:UDP 监听 socket 在发送给某个 peer 之后才会安装精确的 UDP 数据平面 flow;新绑定 socket 可能收不到来自未知 peer 的第一包,直到双方建立互返流。此行为不影响 TUN 平面或经 TUN 可达的 port-forward 目的地。