Files
inp2p/README.md
2026-03-02 15:25:30 +08:00

301 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 依赖,单二进制部署
## 快速开始
### 编译
```bash
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/
```
生产编译(更小体积):
```bash
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/
```
### 启动服务器
```bash
# 生成 token
# token 是 CRC64(user + password) 的结果,客户端和服务端必须一致
./bin/inp2ps -token 12345678 \
-ws-port 27183 \
-stun-udp1 27182 -stun-udp2 27183 \
-stun-tcp1 27180 -stun-tcp2 27181
```
健康检查:
```bash
curl http://localhost:27183/api/v1/health
# {"status":"ok","version":"0.1.0","nodes":0}
```
### 启动客户端
节点 A开启中继能力
```bash
./bin/inp2pc \
-serverhost your-server.com \
-serverport 27183 \
-node nodeA \
-token 12345678 \
-relay \
-config config.json \
-newconfig
```
节点 B
```bash
./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
```
## 测试
```bash
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 部署示例
### 服务器
```ini
[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
```
### 客户端
```ini
[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
- [x] 信令连接 + 认证
- [x] NAT 探测UDP/TCP STUN
- [x] UDP/TCP 打洞 + 双端协调
- [x] 流多路复用隧道
- [x] 中继握手 + TOTP 认证
- [ ] SDWAN 虚拟组网TUN 网卡 + 虚拟 IP
- [ ] Web 控制台
- [ ] UDP 端口转发
- [ ] 自动升级
- [ ] Docker 镜像
## License
MIT