Skip to content

refactor(ohos): 拆分 OHRS 包并按 socket 精细保护 VPN 流量 - #2543

Merged
KKRainbow merged 15 commits into
EasyTier:mainfrom
FrankHan052176:refactor/ohos-socket-protection-packages
Sep 9, 2026
Merged

KKRainbow merged 15 commits into
EasyTier:mainfrom
FrankHan052176:refactor/ohos-socket-protection-packages

Conversation

@FrankHan052176

@FrankHan052176 FrankHan052176 commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

背景

根据与 EasyTier 作者关于 HarmonyOS VPN socket 管理的讨论,本 PR 不再对整个进程调用 protectProcessNet(),而是利用主线已经集中的 TCP/UDP 创建入口,对需要走物理网络的 socket 单独调用 HarmonyOS VpnConnection.protect(fd)。

本 PR 同时完成 OHRS 包职责拆分,并吸收原 PR #2534 的本机子网代理路由、配置 Schema 和 loopback 路由修复,用于替代 #2534。根据后续 review,额外的通配 TCP 用户态入站旁路已移除,正常 TUN 入站使用现有 native listener。

修改内容

1. 拆分 OHRS 内层包

保留 ArkTS 只加载一个 easytier-ohrs HAR/.so,Rust 内部按职责拆成两个同级包:

ArkTS/HAR
   |
easytier-ohrs (N-API facade)
   |                    |
   v                    v
easytier-ohos-core      easytier-ohos-features
  • easytier-ohos-core
    • Tokio runtime 与 NativeInstanceManager
    • runtime state projection
    • kernel socket protocol
    • TUN route 聚合
    • HarmonyOS 单 socket 保护握手
  • easytier-ohos-features
    • 配置持久化与迁移
    • SQLite metadata/field storage
    • Schema reflection/validation
    • import/export 与 share link
  • easytier-ohrs
    • 保持稳定的 N-API facade
    • 向 core 传递 owned config snapshot/route DTO

core 与 features 互不依赖,基础运行包不会再反向拉入 SQLite、配置迁移或 Schema UI 依赖。

2. 按 socket 精细保护 VPN 外部流量

保护意图位于 easytier-core 的 TcpBindOptions::need_protect / UdpBindOptions::need_protect,通过现有创建请求交给宿主。native adapter 使用异步 NativeSocketProtector 回调,等待成功 ACK 后才 bind/connect/listen 或暴露 accepted child;未注册 capability 的平台保持 no-op。WASI 不新增 import,现有 socket options 升级到 v3 并携带该布尔值;外部宿主需更新 decoder 并在自己的创建流程内落实保护。详见 docs/socket-protection.md。

当前覆盖:

  • TCP connect
  • 对外 TCP listener 及 accepted child
  • UDP bind
  • DNS TCP/UDP
  • route probe
  • UPnP gateway route probe

HarmonyOS OHRS core 实现异步 request/ack broker:

  • Rust 创建 socket 后复制 FD,并在 ArkTS acknowledgement 前持有 OwnedFd
  • ArkTS 使用复制 FD 调用 VpnConnection.protect(fd)
  • Rust 等待成功 acknowledgement 后才继续 connect/use
  • 队列上限 128,失败时 fail-closed
  • shutdown 只取消尚未派发的请求;已经交给 ArkTS 的 FD 会保留到 completion,避免 FD 重用竞态
  • ArkTS pump 异常时保留 disabled protector,使新建外部 socket 失败,而不是静默退化为不保护
  • protect/create/destroy 通过同一个异步队列串行化,避免 TUN 重建与 FD protect 交叉
  • pump/单次 protect 失败会通知生命周期 owner,先停止 Core,再 drain protection 并销毁 VPN,运行状态转为 error

低层 TCP/UDP bind options 的 need_protect 默认 true,Rust Default/new 与 JSON 缺省字段一致;删除各出站调用点冗余的 true 设置。native/OHRS 不按 purpose 重复推断、覆盖显式 flag;下列原有例外构造器显式 false:

  • PortForward / ProxyNat / Socks5 等客户端侧 TCP listener
  • HolePunchControl
  • UDP Socks5 association(当前 purpose 同时表示 ingress/egress,先避免错误批量保护)
  • UDP PortForward / PortLease

配套 ArkTS 应用已移除 protectProcessNet(),在存在 TUN 的整个 runtime 生命周期中运行 pull pump,并复用同一个 VpnConnection 完成单 FD protect 与后续 TUN create/destroy。配套实现分支:FrankHan052176/EasyTier-ArkTS@refactor/per-socket-vpn-protection。

3. 收敛为正常 TUN/native 端口转发路径

  • 移除本 PR 新增的 spawn_data_plane_tcp_port_forward 及 force_smoltcp + IPv4 wildcard 调用分支;port_forward.rs 相对 PR 基线已无差异。
  • 本地 native listener/accepted socket 显式不保护,overlay 回包可以遵循 TUN 路由;物理/underlay egress 单独保护。不能继续用额外 userspace ingress 绕过正常 host/TUN 路由问题。
  • 保留既有 DataPlane API、generic no-tun smoltcp proxy 和 force_smoltcp 选项;本 PR 不全面删除 smoltcp。
  • 保留 literal loopback 目的地址固定走 Host 的独立路由修正。
  • 安卓子网代理恢复、以及真实设备可否停用 force_smoltcp,仍需平台实测,不能由单元测试或旧 UID0 证据直接得出。

4. 修复本机子网代理 TUN 路由

本机配置的 proxy_cidrs 只作为网络宣告,不再加入同一节点的 HarmonyOS TUN routes。本机 TUN 继续包含:

  • 本节点虚拟 CIDR
  • 手动 routes
  • 从远端节点学到的 runtime proxy_cidrs

避免 Core TCP/UDP proxy 访问物理局域网目标时被自己的 TUN 再次捕获。

5. 修复配置 Schema 枚举

  • Schema API 返回 protobuf JSON 使用的 enum name,而不是 numeric wire value
  • 新建配置显式使用 CompressionAlgoPb::None
  • 避免 ArkTS field save 写入 1 后被 NetworkConfig JSON 反序列化拒绝

6. CI 契约检查

OHOS workflow 现在会串行执行两个内层包的测试,并使用 cargo check --tests 验证外层 N-API facade 的测试代码可编译。

验证

最新简化:5aef4ea2

  • 移除诊断-only NativeSocketPurpose,native callback只接收handle;Unix/Windows共用Socket保护入口,保持u64句柄宽度。
  • 合并bind/bind_with_protection为同一个async bind,TCP listener复用create_tcp_socket,UDP去掉纯转发wrapper。只迁移legacy WebSocket一处await和既有bind测试;其原有保护策略不变,portable默认true仍由factory显式传入。
  • ArkTS请求shape保留,purpose字段现在为通用socket;ACK、fail-closed和duplicate FD生命周期不变。
  • 保留并加强时序测试:native保护3、TCP2、WebSocket2、Core(含smoltcp)888、OHRS7+5全部通过,N-API/WASI/no-default/fmt/diff check通过。
  • 与0353f993比较:两个src目录的累计PR diff 868→792行(新增+删除口径,-8.8%);native 634→558行(-12.0%),实际native源文件总行数净减少138。
  • 本轮Core源码/WASI v3文档布局未改;新CI已触发,未构建安装新设备包。

先前默认值与TUN收敛:0353f993

  • 默认保护 + 显式本地例外;特别保持内核 TCP proxy listener 的 fresh bind replacement 为 false。
  • easytier-core --lib --features proxy-smoltcp-stack:888 tests passed,包含 DataPlane/port-forward 原有回归。
  • native protection ordering:3 tests passed,覆盖默认出站保护、ACK 前不 connect、失败关闭、显式 false 及四类本地 listener/accepted child 不保护。
  • OHRS core/features:7 + 5 tests passed;外层 N-API cargo check --tests 通过。
  • wasm32-wasip1 default + proxy-smoltcp-stack、native no-default check、root/nested fmt 与 diff check 通过。
  • WASI options 保持 v3,import 名称及签名不变;外部 host 仍须落实创建期保护。
  • 已推送并触发本轮 CI,不能复用旧 head 的全绿结论。本轮未重建/安装设备 HAP。
  • 相对基线,easytier-core 的差异从上一轮 20 个文件减少为 12 个文件。

先前 Review follow-up:bb8fdb6e

  • easytier-core --lib:744 tests passed。
  • native protection ordering:3 tests passed(ACK 前不连接、失败/显式 false、accepted child 等待)。
  • OHRS core/features:7 + 5 tests passed;外层 N-API cargo check --tests 通过。
  • native default/no-default library check、rustfmt、diff check 通过。
  • wasm32-wasip1 精简及 default + proxy-smoltcp-stack check 通过;WASI import 签名不变,options decoder 需支持 v3。
  • 新 head 已触发 CI;之前 9c5b092 的 43/43 全绿不代表本轮 CI 已完成。
  • 本次没有重建/安装 HarmonyOS HAR/HAP;设备仍使用此前 Core 二进制,不把本地测试当作新 head 真机回归。

先前构建基线

已完成:

  • cargo check -p easytier --lib
  • cargo test -p easytier-ohos-core -p easytier-ohos-features --lib -- --test-threads=1
    • core: 8 passed
    • features: 5 passed
  • cargo check -p easytier-ohrs --tests
  • HarmonyOS ARM64 release HAR 构建成功
  • 新 HAR 已用于 ArkTS API 23 Debug App/HAP 编译、签名与覆盖安装
  • HAP 已确认包含 libeasytier_ohrs.so 和 easytier-ohrs ArkTS record

待补真机网络回归:

  • force-global + exit node 启动与外部连接
  • TCP/HDC 0.0.0.0:15555 -> 127.0.0.1:HDC
  • UDP transport/proxy regression
  • 本机子网代理 TCP/UDP
  • 快速启停与保护失败路径

提交结构

589c8d73 refactor(ohos): split facade feature and kernel crates
008ada4e feat(ohos): protect transport sockets individually
da8af467 fix(ohos): keep local proxy subnets off tun
79b8f6b5 fix(ohos): expose valid config enum values
e8ae7e1b refactor(ohos): finalize reusable core boundary
bcf851cc test(ohos): verify split package contracts
4bd2c7bc fix(port-forward): support wildcard userspace listeners
f31449fb chore(ohos): refresh split workspace lockfile
9c5b0921 fix(socket): normalize Windows raw socket handles
bb8fdb6e refactor(socket): carry VPN protection through host bind options
0353f993 refactor(socket): simplify protection defaults and TUN ingress
5aef4ea2 refactor(socket): consolidate native protection and socket creation

Closes and supersedes #2534.

Ok(())
}

fn spawn_data_plane_tcp_port_forward(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以去掉了?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

重新沿收包路径核对了一遍:这段与 per-socket protect 是独立功能。我先保留并补了说明,但收窄原来的必要性描述。

native port-forward listener/accepted socket 现在保持 unprotected,远端 TCP 由 EasyTier 自己终止,HDC 只处理本地连接,因此不能再仅凭“HDC 是 UID0”就断言这段一定不能删。普通 no_tun=true 也已有 generic TCP proxy -> 127.0.0.1:同端口 -> native port-forward 的回退路径,不应说删除会一概破坏 no-tun。

这段额外提供的是 force_smoltcp=true + IPv4 wildcard 下的 userspace inbound endpoint:匹配的 overlay TCP 在 DataPlane 直接终止,回包经 peer plane 发出,不依赖 host TUN 注入和 native TCP 的返程路由。force_smoltcp 可以与 no_tun=false 同用,此时 generic TCP proxy 不一定接管本机虚拟 IP;删除会把这类入站重新交给 host TUN。

所以它不是 protect 的必要组成部分,但原综合 PR 还包含这个可选的用户态入站能力,本次没有仅凭推断删除。尚未做“新版 unprotected native forward 与该 userspace path”的 HarmonyOS A/B,不能宣称新策略下 HDC 仍必须走它;如果希望将这项独立能力从本 PR 拆开,我可以另拆。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同意后续讨论的指正,已在 0353f99 移除这段额外 userspace ingress 及其调用;port_forward.rs 的最终内容已恢复到本 PR 基线。

正常 TUN 场景应让入站走现有 native listener,listener/accepted child 不保护,回包才能按 TUN 路由返回;物理 egress socket 单独保护。我之前用“独立用户态能力”解释保留,扩大了本次修复范围,现已收敛,不再靠额外 DataPlane listener 掩盖 host/TUN 路由问题。

原有 DataPlane bind/connect API、generic no-tun smoltcp proxy、force_smoltcp 选项本身不动;保留 literal loopback 走 Host 的独立路由修正。安卓子网代理是否恢复、哪些场景可不再 force_smoltcp,仍需真实平台回归,暂不将本地测试当作该结论。

本轮 Core 含 proxy-smoltcp-stack 的 888 项测试、native protect 时序 3 项、OHRS 7+5 项、N-API check 和 WASI check 均通过。

Comment thread easytier/src/common/dns.rs Outdated
let socket = create_dns_tcp_socket(&self.context, server_addr, bind_addr);
Box::pin(async move {
let socket = socket?;
protect_native_socket(&socket, NativeSocketPurpose::DnsTcp).await?;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

看看能否把 protect 做到 create socket 接口里面,need_protect 放到 socket bind options 里。
单独加一个接口意味着所有 abi 都要改,放到 bind options 里的话,wasi 的版本也可以受益

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已按这个方向调整,提交 bb8fdb6:

  • need_protect 放进 easytier-core 的 TcpBindOptions / UdpBindOptions,由现有 connect/bind 创建请求带给宿主;Core/WASM 不需要获得真实 FD,也没有新增 protect import。
  • native 的保护回调只作为宿主实现细节,创建流程等待保护成功 ACK 后才 bind/connect/listen;accepted child 继承 listener 的 flag,交付给 Core 前等待保护完成。失败/取消不放行 socket。
  • DNS TCP/UDP、route probe、UPnP probe 改为复用同一创建路径,移除了 DNS 这里独立的 post-create protect 调用;保护启用时也不会回退到不可控的 system DNS。
  • HarmonyOS 沿用 Notify + oneshot 的请求/ACK 桥接,不靠定时轮询;ArkTS protect 完成才唤醒创建方,保留 duplicated FD / fail-closed 语义。不是 fire-and-forget 事件。
  • WASI import 名字和签名不变,现有 socket options 文档升级 v2 -> v3,在 purpose 后增加一个 need_protect 字节。外部宿主需要更新 options decoder 并在自己的创建实现内执行保护;本仓库没有外部宿主实现,不能把 guest 编译通过说成外部平台已完成保护。

验证:easytier-core 744 tests;native protection ordering 3 tests;OHRS core/features 7+5 tests;N-API tests check;native default/no-default check;wasm32-wasip1 精简及 default+proxy-smoltcp-stack check 均通过。契约与 v3 布局写在 docs/socket-protection.md。新一轮 CI 已由 push 触发。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已根据后续建议在 0353f99 将低层 TCP/UDP bind options 的 need_protect 默认统一为 true(Rust Default/new 与 JSON 缺省字段一致),删掉连接、打洞、STUN、DNS、route/UPnP probe 等调用点冗余的 with_need_protect(true)。

只在原有例外构造器显式 false:本地 ProxyNat/SOCKS/PortForward/PortLease TCP listener,以及 UDP HolePunchControl/SOCKS/PortForward/PortLease。特别检查了 with_bind 替换整个对象的地方,内核 TCP proxy listener 的重新构造 bind 也显式 false,避免默认值改变后误保护 TUN 回包。

WASI v3 布局和 import 签名不再变化,flag 仍由创建请求传递。原生 callback / HarmonyOS Notify+oneshot ACK 的时序不变:保护成功后才 bind/connect/listen,失败不放行。测试验证四种本地 TCP listener 及其 accepted socket 不进入保护回调、出站默认保护,以及 serde/WASI 保留显式 false。

移除额外 port-forward ingress 后,easytier-core 相对 PR 基线的修改文件从 20 减到 12。本轮验证:Core 888 passed,native 时序 3 passed,OHRS 7+5 passed,N-API check、wasm32-wasip1 default+proxy-smoltcp-stack check、native no-default check、fmt/diff check 通过。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

继续做了实质简化,提交 5aef4ea:

  • 删除只剩诊断用途的 NativeSocketPurpose,native protector 回调现在只接收 handle;need_protect 仍是唯一保护决策输入。Unix/Windows 通过 socket2/SockRef 共用一个保护入口,保留 i686 handle -> u64 的正确转换。
  • 合并旧 bind 和 bind_with_protection 为一个 async bind;仓库里仅一个 legacy WebSocket 调用加 await、一个同步测试改异步,不增加预创建socket包装层。portable options 默认 true 不变,factory 显式传 flag;底层 builder 保留 legacy 直调不保护的默认行为。
  • TCP listener 复用 create_tcp_socket 再 listen(1024),去掉重复选项装配;UDP去掉一层纯转发wrapper;DNS继续复用共同创建路径,没有恢复重复的DNS-only实现。
  • ACK时序、fail-closed、namespace guard 不跨 await、SO_MARK 在 protect 前应用、accepted child继承和duplicated FD生命周期都保留。ArkTS请求shape不变,purpose诊断字段仅收敛为通用 socket。

保留三个时序测试,并加强listener创建本身等待ACK的断言。native保护3、TCP2、WebSocket2、Core888、OHRS7+5通过;N-API/WASI/no-default/fmt检查通过。

按相同PR基线164e2db6统计:native diff 634 -> 558行(-76,12.0%),Core/native合计868 -> 792行(-8.8%);native实际源文件总行数净减138。文件数native8 -> 9,是合并bind所需的WebSocket单处await迁移,不是搬文件凑减幅。未更新设备,CI已由push触发。

.bind_tcp(
TcpListenOptions::proxy_nat(listen_addr).with_bind(
TcpBindOptions::default()
.with_need_protect(false)

@KKRainbow KKRainbow Sep 6, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

udp proxy 的 socket 也得 protect false 吧

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

哦,应该不需要

let overlay_destination = if local_virtual_destination {
true
} else if dst_ip.is_loopback() {
false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里是多余的,loopback 地址进下面的 else 之后,必然返回 false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不过加了也可以吧

@KKRainbow

KKRainbow commented Sep 6, 2026 •

Copy link
Copy Markdown
Member
  1. major|置信度:高 — UDP 打洞 socket 被错误标记为无需保护

     hole_punch_control() 固定设置 need_protect=false
     (https://github.com/EasyTier/EasyTier/blob/5aef4ea2f58607d72a476e2b2701e5562f5b5451/easytier-core/src/socket/udp/virtual_socket.rs#L229-L230),但它不仅用于 loopback 控制包,也用于创建公网映射 listener
     (https://github.com/EasyTier/EasyTier/blob/5aef4ea2f58607d72a476e2b2701e5562f5b5451/easytier-core/src/connectivity/hole_punch/udp/binding.rs#L315-L325)和客户端打洞 socket
     (https://github.com/EasyTier/EasyTier/blob/5aef4ea2f58607d72a476e2b2701e5562f5b5451/easytier-core/src/connectivity/hole_punch/udp/client.rs#L78-L89)。这些 socket 会直接执行
     STUN、公网地址解析及向远端发送打洞包。

     启用全局 TUN 后,它们没有 VPN bypass,流量会重新进入 TUN,导致常规 UDP 打洞失败。建议让构造器默认保护,仅在 send_v4/v6_hole_punch_control_packet 的 loopback socket 上显式设置 false。

  2. major|置信度:高 — SOCKS5 UDP 出口 socket 同样未保护

     UdpBindOptions::socks5() 固定设置 false (https://github.com/EasyTier/EasyTier/blob/5aef4ea2f58607d72a476e2b2701e5562f5b5451/easytier-core/src/socket/udp/virtual_socket.rs#L256-L257),但 SOCKS5
     同时用它创建本地 inbound association 和访问目标地址的 outbound relay
     (https://github.com/EasyTier/EasyTier/blob/5aef4ea2f58607d72a476e2b2701e5562f5b5451/easytier-core/src/gateway/socks5/host.rs#L123-L140)。

     inbound 确实应保持未保护,但 outbound 必须绕过 EasyTier 自己的 TUN;否则 UDP ASSOCIATE 访问外部目标时会回流进 VPN。建议只在 inbound 路径设置 false,outbound 显式设置 true。

  3. major|置信度:高 — UPnP/NAT-PMP 只保护了探测 socket,实际协议流量仍未保护

     本 PR 仅将 resolve_internal_addr 的临时 route-probe socket
     (https://github.com/EasyTier/EasyTier/blob/5aef4ea2f58607d72a476e2b2701e5562f5b5451/easytier/src/common/upnp.rs#L518-L526)接入保护入口。但实际 NAT-PMP 客户端仍由 new_tokio_natpmp
     (https://github.com/EasyTier/EasyTier/blob/5aef4ea2f58607d72a476e2b2701e5562f5b5451/easytier/src/common/upnp.rs#L65-L71) / new_tokio_natpmp_with
     (https://github.com/EasyTier/EasyTier/blob/5aef4ea2f58607d72a476e2b2701e5562f5b5451/easytier/src/common/upnp.rs#L430-L446)内部重新创建 UDP socket;IGD discovery 和 SOAP HTTP 请求也由 igd-next 内部创建
     socket,完全绕过新的 socket factory。

     移除进程级保护后,发现、建立、续租和删除映射仍可能进入 TUN;即便初次建立碰巧成功,后续续租也可能失败并导致映射过期。需要让实际 IGD/NAT-PMP I/O 使用可保护的 socket/connector,而不只是保护 route probe。

@KKRainbow

Copy link
Copy Markdown
Member

igd-next 的处理看起来会比较麻烦

@KKRainbow

Copy link
Copy Markdown
Member

igd 可以先不用管,把其他的修一下吧

@FrankHan052176

Copy link
Copy Markdown
Contributor Author

按最新 socket review 更新并推送 fab6acdd:

  • UdpBindOptions::hole_punch_control() 恢复默认 need_protect=true。公网映射 listener、STUN 和客户端打洞 socket 都继续保护;只有 send_v4_hole_punch_control_packet / send_v6_hole_punch_control_packet 创建的 loopback 控制 socket 显式 false。
  • UdpBindOptions::socks5() 恢复默认 true。SOCKS5 association 的本地 inbound socket 在 gateway/socks5/host.rs 单独设为 false,transfer 创建的 outbound relay 保持 true。
  • NAT-PMP 不再使用 new_tokio_natpmp* 内部创建的 UDP socket,改为通过 EasyTier UDP factory 创建、保护并连接 gateway 后交给 new_natpmp_async_with;建立、续租、删除 mapping 共用该路径。
  • 删除 dataplane 中冗余的 loopback 分支。

关于 IGD:igd-next 0.17 的 Tokio provider 在库内部硬编码 UdpSocket::bind(SSDP discovery)和 Hyper client(SOAP HTTP),公开 Gateway<Tokio> API 没有 socket/connector 注入点。因此当前 PR 不能安全声称 IGD discovery/SOAP 已接入 per-socket protect;硬拷贝 discovery/parser 或重写 Hyper transport 会把本 PR 扩成第三方库适配工作。建议后续单独升级/patch igd-next provider,再覆盖 discovery、SOAP、renew/remove 全链路。当前 easytier --features upnp 已完成编译检查,NAT-PMP 路径已覆盖。

Sync with main after the igd-next crate was inlined (EasyTier#2555).

Conflict resolution in easytier/src/common/upnp.rs:
- drop the stale "type TokioGateway = Gateway<Tokio>" alias; the
  inlined crate::igd_next::Gateway is no longer generic over the
  async provider
- keep new_protected_natpmp from this branch, which routes NAT-PMP
  sockets through the protected socket factory

Everything else (lib.rs, wasi imports, lockfiles) auto-merged;
cargo check -p easytier --lib --features upnp passes.
Disable socket protection at the native RPC listener entry point so
accepted connections can return traffic through TUN. Keep the existing
IPv6-only bind policy and the protected defaults for transport listeners.

Exercise RPC bind and accept with a failing protector, and align UDP
constructor, loopback control, and WASI encoding tests with the current
default-protected policy and explicit local socket opt-outs.
@KKRainbow
KKRainbow merged commit 38e2a62 into EasyTier:main Sep 9, 2026
44 checks passed
ChanceFlow added a commit to ChanceFlow/EasyTier that referenced this pull request Sep 11, 2026
Brings in 16 upstream commits (347 files) on top of the GUI redesign,
including the core logic changes below.

Core / runtime
- fix(core): reset foreign networks when the event handler lags (EasyTier#2550)
- fix(config): normalize [secure_mode] when loading TOML (EasyTier#2562)
- feat(acl): ACL handling for JSON and TOML formats (EasyTier#2540)
- feat(upnp): inline the IGD client (EasyTier#2555)
- feat(wasi): run the core on Cloudflare Workers and browsers (EasyTier#2548)
- feat(web): URL path support for listener addresses (EasyTier#1967)
- feat(easytier-go): expose CreateInstanceTOML and ShowNodeInfo (EasyTier#2557)
- refactor(ohos): split OHRS crates with per-socket VPN protection (EasyTier#2543)

Android
- fix(android): keep the VPN running when pressing back (EasyTier#2546)
- feat(android): VPN quick-settings tile (EasyTier#2511)
- fix(android): avoid duplicate foreground notifications (EasyTier#2559)

Conflict resolutions (16 files)
- index.vue / mobile_vpn.ts / mobile_vpn.test.ts: kept the rewritten
  phone shell and ported upstream's tile wiring onto it, adapting the
  PrimeVue toast.add(...) calls to this branch's own toast() helper.
- Config.vue / UrlInput.vue: kept the Vuetify rewrites (the merged
  frontend-lib no longer depends on PrimeVue) and ported EasyTier#1967's path
  support and listener-protocol filtering into them by hand.
- config-generator: adopted upstream wholesale (Magisk module WebUI),
  reverting this branch's Vuetify conversion of that standalone tool.
- Android native: union. Kept the localized notification content,
  channel hygiene and the deliberate unused-permission cleanup; took
  upstream's specialUse service type (its API guard was wrong at
  >= Q), the back-press handler, the QS tile service and its alias.
- Removed a duplicate PROPERTY_SPECIAL_USE_FGS_SUBTYPE that the merge
  produced on TauriVpnService, and a duplicated happy-dom override in
  pnpm-workspace.yaml; regenerated pnpm-lock.yaml.

Verified after merge: frontend-lib vitest 17/17, easytier-gui
mobile_vpn 20/20, frontend-lib build (vue-tsc -b + vite) and
easytier-gui vue-tsc --noEmit + vite build all pass.
ChanceFlow added a commit to ChanceFlow/EasyTier that referenced this pull request Sep 11, 2026
The ohos workflow runs `cargo test/check --locked` against
easytier-contrib/easytier-ohrs/Cargo.toml, which failed with:

  error: cannot update the lock file .../easytier-ohrs/Cargo.lock
  because --locked was passed to prevent this

The committed lockfile is byte-identical to upstream/main, i.e. upstream
2.7.0 ships it stale after the EasyTier#2543 OHRS crate split (186 entries for the
pre-split layout). Regenerated with `cargo metadata`; `cargo metadata
--locked` now succeeds both locally and in the runner's step.

Only stale entries were dropped (4 insertions / 186 deletions); no
dependency versions were bumped.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants