5fe5c76375f30dc045e8da0cb9b1411a51bdafb1
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
生产部署(静态编译,避免 glibc 版本问题):
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -extldflags=-static" -o bin/inp2ps ./cmd/inp2ps/
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w -extldflags=-static" -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 |
必填 | 认证 token(uint64) |
-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 + raw binary 数据面)
- Web 控制台
- UDP 端口转发
- 自动升级
- Docker 镜像
License
MIT
Description
Languages
Go
84.7%
HTML
15%
Makefile
0.3%