openclaw 752988a7f4 fix: SDWAN TUN device lifecycle + stability
Key fixes:
- SDWAN config: use absolute path /root/.openclaw/workspace/inp2p/sdwan.json
- Client: register handlers BEFORE ReadLoop (race condition fix)
- Client: make ensureTUNReader non-fatal on error
- Client: fix TUN device conflict between ip tuntap add and ioctl
- Client: fix panic on empty TUN read (n==0 check)
- Build: static binary with -extldflags=-static for glibc compatibility

Verified: hcss(10.10.0.3) <-> i-6986(10.10.0.2) ping 5/5, 0% loss, 44ms
2026-03-02 22:16:45 +08:00
2026-03-02 15:25:30 +08:00

INP2P

自研 P2P 隧道组网系统。两个二进制,零依赖部署。

inp2ps  — 信令服务器STUN + WebSocket + REST API
inp2pc  — 客户端NAT 探测 + 打洞 + 中继 + 端口转发)

为什么造这个

试过 OpenP2P、FRP、ZeroTier各有各的问题。OpenP2P 最接近需求,但踩了一堆坑:

  • MsgReportBasic 不回响应 → 客户端反复断连
  • Push 消息白名单太窄 → 操作被拒绝
  • TOTP relay 认证链过于复杂 → Access Denied
  • peerNatType=314 跳过所有打洞 → 只走 relay
  • 中继节点选择单一,没有分层概念

INP2P 从协议层重新设计,解决以上所有问题。

特性

  • 连接优先级UDP 直连 → UDP 打洞 → TCP 直连 → TCP 打洞 → 私有中继 → 超级中继 → 服务器中继
  • 流多路复用:一条 P2P 连接承载多个隧道7 字节帧头StreamID + Flags + Length
  • 分层中继:任意客户端可选开启 --relay / --super,自动参与中继
  • TOTP 认证CRC64 token + 时间窗口验证,跨用户场景用 HMAC-SHA256 一次性令牌
  • NAT 探测:内置 STUN 服务端UDP×2 + TCP×2客户端自动探测 NAT 类型
  • 断线重连5 秒退避自动重连,节点上线广播触发隧道重建
  • 静态编译:零 CGO 依赖,单二进制部署

快速开始

编译

git clone https://gitea.king.nyc.mn/openclaw/inp2p.git
cd inp2p
go build -o bin/inp2ps ./cmd/inp2ps/
go build -o bin/inp2pc ./cmd/inp2pc/

生产编译(更小体积):

CGO_ENABLED=0 go build -ldflags="-s -w" -o bin/inp2ps ./cmd/inp2ps/
CGO_ENABLED=0 go build -ldflags="-s -w" -o bin/inp2pc ./cmd/inp2pc/

启动服务器

# 生成 token
# token 是 CRC64(user + password) 的结果,客户端和服务端必须一致
./bin/inp2ps -token 12345678 \
  -ws-port 27183 \
  -stun-udp1 27182 -stun-udp2 27183 \
  -stun-tcp1 27180 -stun-tcp2 27181

健康检查:

curl http://localhost:27183/api/v1/health
# {"status":"ok","version":"0.1.0","nodes":0}

启动客户端

节点 A开启中继能力

./bin/inp2pc \
  -serverhost your-server.com \
  -serverport 27183 \
  -node nodeA \
  -token 12345678 \
  -relay \
  -config config.json \
  -newconfig

节点 B

./bin/inp2pc \
  -serverhost your-server.com \
  -serverport 27183 \
  -node nodeB \
  -token 12345678 \
  -config config.json \
  -newconfig

参数说明

inp2ps

参数 默认值 说明
-token 必填 认证 tokenuint64
-ws-port 27183 WebSocket 信令端口
-stun-udp1 27182 UDP STUN 端口 1
-stun-udp2 27183 UDP STUN 端口 2
-stun-tcp1 27180 TCP STUN 端口 1
-stun-tcp2 27181 TCP STUN 端口 2

inp2pc

参数 默认值 说明
-serverhost 必填 服务器地址
-serverport 27183 服务器端口
-node 必填 节点名称(唯一标识)
-token 必填 认证 token与服务器一致
-insecure false 跳过 TLS 验证(用 ws:// 代替 wss://
-relay false 启用中继节点功能
-super false 启用超级中继(对所有用户开放)
-relay-port 27185 中继监听端口
-bw 10 共享带宽上限Mbps
-config config.json 配置文件路径
-newconfig false 忽略已有配置,使用命令行参数
-stun-udp1/2 同服务器 STUN 端口(通常与服务器一致)
-stun-tcp1/2 同服务器 STUN 端口(通常与服务器一致)

架构

┌─────────────────────────────────────────────┐
│                  inp2ps                      │
│                                             │
│  ┌─────────┐  ┌──────┐  ┌───────────────┐  │
│  │  STUN   │  │  WSS │  │  Coordinator  │  │
│  │ UDP × 2 │  │Server│  │  (punch sync) │  │
│  │ TCP × 2 │  │      │  │               │  │
│  └─────────┘  └──────┘  └───────────────┘  │
│                   │                         │
│           ┌───────┴───────┐                 │
│           │  Node Manager │                 │
│           │  (online/hb)  │                 │
│           └───────────────┘                 │
└─────────────────────────────────────────────┘
          ▲ WSS              ▲ WSS
          │                  │
┌─────────┴──┐        ┌─────┴────────┐
│   inp2pc   │◄──P2P──►│   inp2pc     │
│   nodeA    │  punch  │   nodeB      │
│            │  /relay │              │
│ ┌────────┐ │        │ ┌──────────┐ │
│ │ Tunnel │ │        │ │  Tunnel  │ │
│ │  Mux   │ │        │ │   Mux   │ │
│ └────────┘ │        │ └──────────┘ │
└────────────┘        └──────────────┘

连接建立流程

nodeA                    inp2ps                    nodeB
  │                        │                        │
  │── ConnectReq ─────────►│                        │
  │                        │── PunchStart ─────────►│
  │◄── PunchStart ─────────│                        │
  │                        │                        │
  │◄═══════ UDP/TCP Punch ═══════════════════════►│
  │                        │                        │
  │         (if punch fails, fallback to relay)     │
  │                        │                        │
  │── RelayNodeReq ───────►│                        │
  │◄── RelayNodeRsp ───────│── PushRelayOffer ────►│
  │                        │                        │
  │──── RelayHandshake ──►[R]◄── RelayHandshake ───│
  │                      [R] bridges A ↔ B          │
  │◄═══════════ Mux Stream ═══════════════════════►│

多路复用帧格式

 0       4    5       7
 ├───────┼────┼───────┤
 │Stream │Flag│Length │ Data...
 │  ID   │  s │      │
 └───────┴────┴───────┘
   4B     1B    2B      0~65535B

Flags: SYN=0x01 FIN=0x02 DATA=0x04 PING=0x08 PONG=0x10 RST=0x20
StreamID: 客户端奇数(1,3,5...) 服务端偶数(2,4,6...)

项目结构

inp2p/
├── cmd/
│   ├── inp2ps/main.go       # 服务器入口
│   └── inp2pc/main.go       # 客户端入口
├── internal/
│   ├── server/
│   │   ├── server.go        # WSS 主循环、登录、心跳、节点管理
│   │   └── coordinator.go   # 打洞协调、App 推送
│   └── client/
│       └── client.go        # NAT 探测、登录、打洞、中继、重连
├── pkg/
│   ├── protocol/            # 消息定义、编解码、NAT 类型枚举
│   ├── config/              # 配置结构体、默认值、环境变量
│   ├── auth/                # CRC64 token、TOTP、HMAC-SHA256 令牌
│   ├── nat/                 # UDP/TCP STUN 客户端和服务端
│   ├── signal/              # WebSocket 封装、handler、同步请求
│   ├── punch/               # UDP/TCP 打洞 + 优先级链
│   ├── mux/                 # 流多路复用7B 帧头)
│   ├── tunnel/              # 基于 mux 的端口转发
│   └── relay/               # 中继管理、TOTP 握手、会话桥接
├── go.mod
├── go.sum
├── TASKS.md                 # 任务拆分与进度
└── .gitignore

测试

go test ./... -v
internal/client  PASS   8.3s   — NAT + WSS + Login + Report 完整链路
internal/server  PASS   0.8s   — 双客户端登录 + Relay 节点发现
pkg/mux          PASS   0.2s   — 7 测试:并发/大载荷/FIN/session
pkg/tunnel       PASS   0.16s  — 端到端转发 + 5 并发 + 统计
pkg/relay        PASS   0.3s   — 双向桥接 + 1MB 中继 + 认证拒绝

防火墙

服务器需要开放以下端口:

端口 协议 用途
27183 TCP WebSocket 信令
27182, 27183 UDP STUN NAT 探测
27180, 27181 TCP STUN TCP 回退

客户端(如果开启 --relay

端口 协议 用途
27185 TCP 中继服务

Systemd 部署示例

服务器

[Unit]
Description=INP2P Signaling Server
After=network.target

[Service]
ExecStart=/usr/local/bin/inp2ps -token YOUR_TOKEN
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

客户端

[Unit]
Description=INP2P Client
After=network.target

[Service]
WorkingDirectory=/usr/local/inp2p
ExecStart=/usr/local/bin/inp2pc -serverhost your-server.com -node mynode -token YOUR_TOKEN -insecure
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Roadmap

  • 信令连接 + 认证
  • NAT 探测UDP/TCP STUN
  • UDP/TCP 打洞 + 双端协调
  • 流多路复用隧道
  • 中继握手 + TOTP 认证
  • SDWAN 虚拟组网TUN 网卡 + 虚拟 IP
  • Web 控制台
  • UDP 端口转发
  • 自动升级
  • Docker 镜像

License

MIT

Description
No description provided
Readme 14 MiB
Languages
Go 84.7%
HTML 15%
Makefile 0.3%