# 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
```

生产部署（静态编译，避免 glibc 版本问题）：

```bash
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/
```

### 启动服务器

```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` | 必填 | 认证 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
```

## 测试

```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 认证
- [x] SDWAN 虚拟组网（TUN 网卡 + 虚拟 IP + raw binary 数据面）
- [ ] Web 控制台
- [ ] UDP 端口转发
- [ ] 自动升级
- [ ] Docker 镜像

## License

MIT
