wsstunnel 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wsstunnel-0.3.0/LICENSE +21 -0
- wsstunnel-0.3.0/PKG-INFO +576 -0
- wsstunnel-0.3.0/README.md +561 -0
- wsstunnel-0.3.0/pyproject.toml +23 -0
- wsstunnel-0.3.0/setup.cfg +4 -0
- wsstunnel-0.3.0/ws_tunnel/__init__.py +10 -0
- wsstunnel-0.3.0/ws_tunnel/__main__.py +9 -0
- wsstunnel-0.3.0/ws_tunnel/cli.py +86 -0
- wsstunnel-0.3.0/ws_tunnel/client.py +130 -0
- wsstunnel-0.3.0/ws_tunnel/relay.py +140 -0
- wsstunnel-0.3.0/wsstunnel.egg-info/PKG-INFO +576 -0
- wsstunnel-0.3.0/wsstunnel.egg-info/SOURCES.txt +14 -0
- wsstunnel-0.3.0/wsstunnel.egg-info/dependency_links.txt +1 -0
- wsstunnel-0.3.0/wsstunnel.egg-info/entry_points.txt +2 -0
- wsstunnel-0.3.0/wsstunnel.egg-info/requires.txt +3 -0
- wsstunnel-0.3.0/wsstunnel.egg-info/top_level.txt +1 -0
wsstunnel-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 ws-tunnel
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
wsstunnel-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wsstunnel
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: WebSocket reverse shell relay with HTTP proxy support
|
|
5
|
+
Author: yuanguangshan
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/yuanguangshan/wstunnel
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: websocket-client>=1.3.0
|
|
12
|
+
Requires-Dist: websockets>=10.0
|
|
13
|
+
Requires-Dist: click>=8.0
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# ws-tunnel
|
|
17
|
+
|
|
18
|
+
**WebSocket 远程 Shell 中继工具** — 通过 WebSocket + HTTP 代理穿透受限网络环境,实现远程交互式 Shell。
|
|
19
|
+
|
|
20
|
+
适用场景:受限容器环境(在线 IDE、CI runner)、仅允许 HTTP 出站的内网设备、IoT 边缘设备、安全测试。
|
|
21
|
+
|
|
22
|
+
## 架构
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
第三方电脑(浏览器/websocat/Python)
|
|
26
|
+
│
|
|
27
|
+
│ ws://your-vps:8080 或 wss://your-vps:443
|
|
28
|
+
│
|
|
29
|
+
▼
|
|
30
|
+
┌──────────────────────────────────┐
|
|
31
|
+
│ VPS(中继服务) │
|
|
32
|
+
│ ws-tunnel relay --port 8080 │
|
|
33
|
+
│ │
|
|
34
|
+
│ 角色:中继转发 │
|
|
35
|
+
│ 依赖:Python 3.10+ + websockets │
|
|
36
|
+
└──────────┬──────────────┬─────────┘
|
|
37
|
+
│ │
|
|
38
|
+
前端(Frontend) 后端(Backend)
|
|
39
|
+
发送命令 注册并执行
|
|
40
|
+
│ │
|
|
41
|
+
│ ▼
|
|
42
|
+
│ ┌────────────────────────┐
|
|
43
|
+
│ │ 目标容器/设备(客户端) │
|
|
44
|
+
│ │ ws-tunnel client \ │
|
|
45
|
+
│ │ --server ws://... │
|
|
46
|
+
│ │ │
|
|
47
|
+
│ │ 通过 HTTP 代理穿透 │
|
|
48
|
+
│ │ 启动交互式 shell │
|
|
49
|
+
│ └────────────────────────┘
|
|
50
|
+
│
|
|
51
|
+
▼
|
|
52
|
+
你看到的输出
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 快速开始(5 分钟)
|
|
56
|
+
|
|
57
|
+
### 1️⃣ VPS 端
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# 安装
|
|
61
|
+
git clone <your-repo> && cd ws-tunnel
|
|
62
|
+
pip install -e .
|
|
63
|
+
|
|
64
|
+
# 启动中继(带 token + TLS)
|
|
65
|
+
ws-tunnel relay --port 8080 --token mysecret --cert /path/to/cert.pem --key /path/to/key.pem
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 2️⃣ 容器端
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# 安装依赖
|
|
72
|
+
pip install websocket-client
|
|
73
|
+
|
|
74
|
+
# 下载客户端脚本
|
|
75
|
+
curl -O https://your-server/ws_tunnel/client.py
|
|
76
|
+
|
|
77
|
+
# 运行(带代理 + token)
|
|
78
|
+
python3 client.py --server wss://your-vps:443 --proxy http://127.0.0.1:18080 --token mysecret
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 3️⃣ 连接测试
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# 方式一:websocat
|
|
85
|
+
websocat ws://your-vps:8080
|
|
86
|
+
# 输入 token 认证(如果中继有 token)
|
|
87
|
+
AUTH:mysecret
|
|
88
|
+
# 然后就可以执行命令了
|
|
89
|
+
whoami
|
|
90
|
+
ls -la
|
|
91
|
+
|
|
92
|
+
# 方式二:Python 一行
|
|
93
|
+
python3 -c "
|
|
94
|
+
import websocket
|
|
95
|
+
ws = websocket.create_connection('ws://your-vps:8080')
|
|
96
|
+
ws.send('AUTH:mysecret')
|
|
97
|
+
print('Auth:', ws.recv())
|
|
98
|
+
ws.send('whoami')
|
|
99
|
+
print('Output:', ws.recv())
|
|
100
|
+
ws.close()
|
|
101
|
+
"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## 安装
|
|
105
|
+
|
|
106
|
+
### 从源码安装
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git clone <your-repo>
|
|
110
|
+
cd ws-tunnel
|
|
111
|
+
pip install -e .
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
安装后获得 `ws-tunnel` 命令和 `ws_tunnel` Python 包。
|
|
115
|
+
|
|
116
|
+
### 仅安装依赖
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
pip install -r requirements.txt
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 系统依赖
|
|
123
|
+
|
|
124
|
+
- Python >= 3.10
|
|
125
|
+
- 中继端依赖:`websockets`,`click`
|
|
126
|
+
- 客户端依赖:`websocket-client`,`click`
|
|
127
|
+
|
|
128
|
+
## 详细使用指南
|
|
129
|
+
|
|
130
|
+
### VPS 端(中继服务)
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# 最小启动(不安全,仅内网测试)
|
|
134
|
+
ws-tunnel relay --port 8080
|
|
135
|
+
|
|
136
|
+
# 生产启动(认证 + TLS)
|
|
137
|
+
ws-tunnel relay \
|
|
138
|
+
--port 443 \
|
|
139
|
+
--token $(openssl rand -hex 32) \
|
|
140
|
+
--cert /etc/letsencrypt/live/example.com/fullchain.pem \
|
|
141
|
+
--key /etc/letsencrypt/live/example.com/privkey.pem
|
|
142
|
+
|
|
143
|
+
# 调试启动(看所有 WebSocket 消息)
|
|
144
|
+
ws-tunnel relay --port 8080 --token mysecret --verbose
|
|
145
|
+
|
|
146
|
+
# 静默运行(仅错误日志)
|
|
147
|
+
ws-tunnel relay --port 8080 --token mysecret --quiet
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### 所有 relay 参数
|
|
151
|
+
|
|
152
|
+
| 参数 | 默认值 | 说明 |
|
|
153
|
+
|------|--------|------|
|
|
154
|
+
| `--host` | `0.0.0.0` | 监听地址 |
|
|
155
|
+
| `--port` | `8080` | 监听端口 |
|
|
156
|
+
| `-t, --token` | — | 认证令牌,不设则不开启认证 |
|
|
157
|
+
| `--cert` | — | TLS 证书路径(提供后启用 wss://) |
|
|
158
|
+
| `--key` | — | TLS 私钥路径,未指定时使用 --cert |
|
|
159
|
+
| `--verbose` | — | 输出 DEBUG 级别日志 |
|
|
160
|
+
| `--quiet` | — | 仅输出 WARNING 及以上日志 |
|
|
161
|
+
|
|
162
|
+
### 容器端(客户端)
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# 基本连接(直连)
|
|
166
|
+
ws-tunnel client --server ws://your-vps:8080 --token mysecret
|
|
167
|
+
|
|
168
|
+
# 通过 HTTP 代理连接(常见于受限容器)
|
|
169
|
+
ws-tunnel client \
|
|
170
|
+
--server ws://your-vps:8080 \
|
|
171
|
+
--proxy http://127.0.0.1:18080 \
|
|
172
|
+
--token mysecret
|
|
173
|
+
|
|
174
|
+
# 使用 wss 加密连接 + 自签名证书
|
|
175
|
+
ws-tunnel client \
|
|
176
|
+
--server wss://your-vps:443 \
|
|
177
|
+
--token mysecret \
|
|
178
|
+
--insecure
|
|
179
|
+
|
|
180
|
+
# 指定其他 shell(如 sh、zsh)
|
|
181
|
+
ws-tunnel client \
|
|
182
|
+
--server ws://your-vps:8080 \
|
|
183
|
+
--token mysecret \
|
|
184
|
+
--shell /bin/zsh
|
|
185
|
+
|
|
186
|
+
# 缩短重连间隔(快速重试场景)
|
|
187
|
+
ws-tunnel client --server ws://... --token mysecret --reconnect 2
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
#### 所有 client 参数
|
|
191
|
+
|
|
192
|
+
| 参数 | 默认值 | 说明 |
|
|
193
|
+
|------|--------|------|
|
|
194
|
+
| `--server` | **必填** | 中继服务器地址,如 `ws://1.2.3.4:8080` |
|
|
195
|
+
| `--proxy` | — | HTTP 代理地址,如 `http://127.0.0.1:18080` |
|
|
196
|
+
| `--reconnect` | `5` | 初始重连间隔秒数(指数退避,最大 300s) |
|
|
197
|
+
| `-t, --token` | — | 认证令牌,需与 relay 端一致 |
|
|
198
|
+
| `--insecure` | — | 跳过 TLS 证书验证(自签名证书) |
|
|
199
|
+
| `--shell` | `/bin/bash` | 远程 shell 路径 |
|
|
200
|
+
| `--verbose` | — | 输出 DEBUG 级别日志 |
|
|
201
|
+
| `--quiet` | — | 仅输出 WARNING 及以上日志 |
|
|
202
|
+
|
|
203
|
+
### 通过环境变量统一管理 token
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
export WS_TUNNEL_TOKEN=mysecret
|
|
207
|
+
|
|
208
|
+
# 之后 --token 会自动读取,无需再写
|
|
209
|
+
ws-tunnel relay --port 8080
|
|
210
|
+
ws-tunnel client --server ws://your-vps:8080
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## 常见工作流
|
|
214
|
+
|
|
215
|
+
### 工作流 A:从零搭建生产隧道
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
# ── VPS 端 ──
|
|
219
|
+
# 1. 安装 ws-tunnel
|
|
220
|
+
pip install wsstunnel
|
|
221
|
+
|
|
222
|
+
# 2. 用 Let's Encrypt 申请证书
|
|
223
|
+
sudo apt install certbot nginx
|
|
224
|
+
sudo certbot certonly --standalone -d tunnel.example.com
|
|
225
|
+
|
|
226
|
+
# 3. 生成随机 token
|
|
227
|
+
export WS_TUNNEL_TOKEN=$(openssl rand -hex 32)
|
|
228
|
+
echo "Token: $WS_TUNNEL_TOKEN" # 保存好
|
|
229
|
+
|
|
230
|
+
# 4. 启动中继(端口 443)
|
|
231
|
+
ws-tunnel relay \
|
|
232
|
+
--port 443 \
|
|
233
|
+
--cert /etc/letsencrypt/live/tunnel.example.com/fullchain.pem \
|
|
234
|
+
--key /etc/letsencrypt/live/tunnel.example.com/privkey.pem
|
|
235
|
+
|
|
236
|
+
# ── 容器端 ──
|
|
237
|
+
# 5. 连接(自动读取 WS_TUNNEL_TOKEN)
|
|
238
|
+
ws-tunnel client --server wss://tunnel.example.com:443
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### 工作流 B:受限容器穿透(HTTP 代理场景)
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
# ── VPS 端(简单启动,只需端口)──
|
|
245
|
+
ws-tunnel relay --port 8080 --token mysecret
|
|
246
|
+
|
|
247
|
+
# ── 容器端 ──
|
|
248
|
+
# 容器通常有 HTTP 代理环境变量
|
|
249
|
+
echo $http_proxy # 如 http://127.0.0.1:18080
|
|
250
|
+
|
|
251
|
+
# 连接(需指定代理)
|
|
252
|
+
ws-tunnel client \
|
|
253
|
+
--server ws://your-vps:8080 \
|
|
254
|
+
--proxy http://127.0.0.1:18080 \
|
|
255
|
+
--token mysecret
|
|
256
|
+
|
|
257
|
+
# ── 你的电脑 ──
|
|
258
|
+
websocat ws://your-vps:8080
|
|
259
|
+
# 输入: AUTH:mysecret
|
|
260
|
+
# 现在你可以执行远程命令了
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### 工作流 C:TLS 自签名 + 本地测试
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
# 1. 生成自签名证书
|
|
267
|
+
openssl req -x509 -newkey rsa:2048 \
|
|
268
|
+
-keyout key.pem -out cert.pem \
|
|
269
|
+
-days 365 -nodes -subj "/CN=localhost"
|
|
270
|
+
|
|
271
|
+
# 2. 启动中继(wss://)
|
|
272
|
+
ws-tunnel relay --port 4433 --cert cert.pem --key key.pem --token test123
|
|
273
|
+
|
|
274
|
+
# 3. 启动客户端(跳过证书验证)
|
|
275
|
+
ws-tunnel client --server wss://127.0.0.1:4433 --token test123 --insecure
|
|
276
|
+
|
|
277
|
+
# 4. 前端测试
|
|
278
|
+
python3 -c "
|
|
279
|
+
import ssl, websocket
|
|
280
|
+
ws = websocket.create_connection(
|
|
281
|
+
'wss://127.0.0.1:4433',
|
|
282
|
+
sslopt={'cert_reqs': ssl.CERT_NONE}
|
|
283
|
+
)
|
|
284
|
+
ws.send('AUTH:test123')
|
|
285
|
+
print('Auth:', ws.recv())
|
|
286
|
+
ws.send('echo hello_world')
|
|
287
|
+
import time; time.sleep(1)
|
|
288
|
+
print('Output:', ws.recv())
|
|
289
|
+
ws.close()
|
|
290
|
+
"
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### 工作流 D:系统服务(systemd 自动启动)
|
|
294
|
+
|
|
295
|
+
VPS 端的 `/etc/systemd/system/ws-tunnel.service`:
|
|
296
|
+
|
|
297
|
+
```ini
|
|
298
|
+
[Unit]
|
|
299
|
+
Description=ws-tunnel WebSocket Relay
|
|
300
|
+
After=network.target
|
|
301
|
+
|
|
302
|
+
[Service]
|
|
303
|
+
Type=simple
|
|
304
|
+
User=root
|
|
305
|
+
Environment=WS_TUNNEL_TOKEN=mysecret
|
|
306
|
+
ExecStart=/usr/local/bin/ws-tunnel relay --port 443 --cert /etc/letsencrypt/live/example.com/fullchain.pem --key /etc/letsencrypt/live/example.com/privkey.pem
|
|
307
|
+
Restart=always
|
|
308
|
+
RestartSec=10
|
|
309
|
+
|
|
310
|
+
[Install]
|
|
311
|
+
WantedBy=multi-user.target
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
sudo systemctl daemon-reload
|
|
316
|
+
sudo systemctl enable --now ws-tunnel
|
|
317
|
+
sudo journalctl -u ws-tunnel -f # 查看日志
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## 认证协议
|
|
321
|
+
|
|
322
|
+
中继端设置 `--token` 后启用认证:
|
|
323
|
+
|
|
324
|
+
| 角色 | 第一条消息 | 服务端响应 | 说明 |
|
|
325
|
+
|------|-----------|-----------|------|
|
|
326
|
+
| **后端(容器)** | `IAM_BACKEND:<token>` | — | 注册成功后开始转发 shell 输出 |
|
|
327
|
+
| **前端(第三方)** | `AUTH:<token>` | `AUTH_OK` / `AUTH_FAIL` | 收到 `AUTH_OK` 后即可发命令 |
|
|
328
|
+
| **任意错误** | 其他消息 | `AUTH_FAIL` + 断开 (1008) | 拒绝连接 |
|
|
329
|
+
|
|
330
|
+
### 不设 token 时
|
|
331
|
+
|
|
332
|
+
保持完全向后兼容——第一条消息直接决定角色:
|
|
333
|
+
|
|
334
|
+
| 消息 | 角色 |
|
|
335
|
+
|------|------|
|
|
336
|
+
| `IAM_BACKEND` | 注册为后端 |
|
|
337
|
+
| 其他任意内容 | 注册为前端,内容作为第一条命令 |
|
|
338
|
+
|
|
339
|
+
## TLS / WSS 加密
|
|
340
|
+
|
|
341
|
+
### 方式一:使用已有证书(推荐)
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
# VPS 端
|
|
345
|
+
ws-tunnel relay --port 443 \
|
|
346
|
+
--cert /etc/letsencrypt/live/example.com/fullchain.pem \
|
|
347
|
+
--key /etc/letsencrypt/live/example.com/privkey.pem
|
|
348
|
+
|
|
349
|
+
# 容器端(使用标准 CA 证书,无需额外参数)
|
|
350
|
+
ws-tunnel client --server wss://example.com:443 --token mysecret
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### 方式二:自签名证书
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
# 1. 生成证书
|
|
357
|
+
openssl req -x509 -newkey rsa:2048 \
|
|
358
|
+
-keyout key.pem -out cert.pem \
|
|
359
|
+
-days 365 -nodes -subj "/CN=your-vps-ip"
|
|
360
|
+
|
|
361
|
+
# 2. VPS 端
|
|
362
|
+
ws-tunnel relay --port 443 --cert cert.pem --key key.pem --token mysecret
|
|
363
|
+
|
|
364
|
+
# 3. 容器端(必须加 --insecure 跳过验证)
|
|
365
|
+
ws-tunnel client --server wss://your-vps:443 --token mysecret --insecure
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
> **安全提示**:`--insecure` 跳过证书验证,中间人可以解密流量。建议只用于测试,或配合 token 认证使用。
|
|
369
|
+
|
|
370
|
+
### 方式三:nginx 反向代理(生产推荐)
|
|
371
|
+
|
|
372
|
+
优点:证书管理交给 nginx(自动续期),ws-tunnel 只需监听内网端口,无需 reload。
|
|
373
|
+
|
|
374
|
+
```nginx
|
|
375
|
+
# /etc/nginx/sites-available/tunnel
|
|
376
|
+
server {
|
|
377
|
+
listen 443 ssl;
|
|
378
|
+
http2 on;
|
|
379
|
+
server_name tunnel.example.com;
|
|
380
|
+
|
|
381
|
+
ssl_certificate /etc/letsencrypt/live/tunnel.example.com/fullchain.pem;
|
|
382
|
+
ssl_certificate_key /etc/letsencrypt/live/tunnel.example.com/privkey.pem;
|
|
383
|
+
|
|
384
|
+
location / {
|
|
385
|
+
proxy_pass http://127.0.0.1:8080;
|
|
386
|
+
proxy_http_version 1.1;
|
|
387
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
388
|
+
proxy_set_header Connection "upgrade";
|
|
389
|
+
proxy_set_header Host $host;
|
|
390
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
391
|
+
proxy_read_timeout 86400s;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
# ws-tunnel 在本地 8080 裸运行
|
|
398
|
+
ws-tunnel relay --port 8080 --token mysecret
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
## 使用第三方客户端连接
|
|
402
|
+
|
|
403
|
+
### websocat(推荐,交互式体验)
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
# 安装
|
|
407
|
+
brew install websocat # macOS
|
|
408
|
+
cargo install websocat # 或从源码
|
|
409
|
+
|
|
410
|
+
# 连接
|
|
411
|
+
websocat ws://your-vps:8080
|
|
412
|
+
|
|
413
|
+
# 连接后输入认证(如果有 token):
|
|
414
|
+
AUTH:mysecret
|
|
415
|
+
|
|
416
|
+
# 然后即可交互式操作
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Python 脚本
|
|
420
|
+
|
|
421
|
+
```python
|
|
422
|
+
import websocket
|
|
423
|
+
import time
|
|
424
|
+
|
|
425
|
+
ws = websocket.create_connection("ws://your-vps:8080")
|
|
426
|
+
|
|
427
|
+
# 认证(如果有 token)
|
|
428
|
+
ws.send("AUTH:mysecret")
|
|
429
|
+
auth_resp = ws.recv()
|
|
430
|
+
assert auth_resp == "AUTH_OK", f"Auth failed: {auth_resp}"
|
|
431
|
+
|
|
432
|
+
# 发送命令
|
|
433
|
+
ws.send("uname -a")
|
|
434
|
+
time.sleep(0.5)
|
|
435
|
+
|
|
436
|
+
# 读取输出
|
|
437
|
+
ws.settimeout(2)
|
|
438
|
+
try:
|
|
439
|
+
while True:
|
|
440
|
+
output = ws.recv()
|
|
441
|
+
print(output, end="")
|
|
442
|
+
except websocket.WebSocketTimeoutException:
|
|
443
|
+
pass
|
|
444
|
+
|
|
445
|
+
ws.close()
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### 浏览器(F12 控制台)
|
|
449
|
+
|
|
450
|
+
```javascript
|
|
451
|
+
const ws = new WebSocket("ws://your-vps:8080");
|
|
452
|
+
ws.onmessage = (e) => console.log(e.data);
|
|
453
|
+
|
|
454
|
+
// 认证(如果有 token)
|
|
455
|
+
ws.send("AUTH:mysecret");
|
|
456
|
+
|
|
457
|
+
// 发送命令
|
|
458
|
+
ws.send("ls -la");
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
## 使用库 API(在 Python 代码中调用)
|
|
462
|
+
|
|
463
|
+
```python
|
|
464
|
+
from ws_tunnel import run_relay, run_client
|
|
465
|
+
|
|
466
|
+
# 启动中继(阻塞)
|
|
467
|
+
run_relay("0.0.0.0", 8080, token="mysecret")
|
|
468
|
+
|
|
469
|
+
# 启动中继 + TLS
|
|
470
|
+
run_relay(
|
|
471
|
+
"0.0.0.0", 443,
|
|
472
|
+
token="mysecret",
|
|
473
|
+
cert_path="/path/to/cert.pem",
|
|
474
|
+
key_path="/path/to/key.pem",
|
|
475
|
+
)
|
|
476
|
+
|
|
477
|
+
# 启动客户端
|
|
478
|
+
run_client(
|
|
479
|
+
"ws://your-vps:8080",
|
|
480
|
+
proxy="http://127.0.0.1:18080",
|
|
481
|
+
token="mysecret",
|
|
482
|
+
shell="/bin/bash",
|
|
483
|
+
reconnect_interval=5,
|
|
484
|
+
insecure=True,
|
|
485
|
+
)
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
## 故障排查
|
|
489
|
+
|
|
490
|
+
### 连接被拒绝
|
|
491
|
+
|
|
492
|
+
```
|
|
493
|
+
Connection refused
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
- 检查 VPS 端的端口是否开放:`ss -tlnp | grep 8080`
|
|
497
|
+
- 检查防火墙:`ufw status` 或云平台安全组规则
|
|
498
|
+
- 确认中继已在运行:`ps aux | grep ws-tunnel`
|
|
499
|
+
|
|
500
|
+
### 认证失败
|
|
501
|
+
|
|
502
|
+
```
|
|
503
|
+
AUTH_FAIL
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
- 确认 relay 端设置了 `--token`
|
|
507
|
+
- 确认 client 端使用了相同的 token
|
|
508
|
+
- token 区分大小写
|
|
509
|
+
|
|
510
|
+
### 代理连接失败
|
|
511
|
+
|
|
512
|
+
```
|
|
513
|
+
Proxy connection failed
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
- 确认容器内有 HTTP 代理可用:`echo $http_proxy`
|
|
517
|
+
- 测试代理本身是否正常:`curl -x http://127.0.0.1:18080 http://example.com`
|
|
518
|
+
- 代理地址格式:`http://host:port`(必须是 http://,不是 https://)
|
|
519
|
+
|
|
520
|
+
### TLS 证书错误
|
|
521
|
+
|
|
522
|
+
```
|
|
523
|
+
[SSL: CERTIFICATE_VERIFY_FAILED]
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
- 自签名证书:客户端加 `--insecure`
|
|
527
|
+
- 证书过期:检查证书有效期 `openssl x509 -in cert.pem -noout -dates`
|
|
528
|
+
- 域名不匹配:证书 CN 需与连接域名一致
|
|
529
|
+
|
|
530
|
+
### bash 未找到
|
|
531
|
+
|
|
532
|
+
```
|
|
533
|
+
FileNotFoundError: /bin/bash
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
- 容器内可能没有 bash,改用 `--shell /bin/sh`
|
|
537
|
+
- 确认指定路径的正确性:`which bash`
|
|
538
|
+
|
|
539
|
+
### 后端未连接
|
|
540
|
+
|
|
541
|
+
```
|
|
542
|
+
[Error] No backend connected
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
- 确保容器端已启动并在运行
|
|
546
|
+
- 检查容器端日志是否有错误
|
|
547
|
+
- 容器端的网络可达性:`ping your-vps` 或 `curl ws://your-vps:8080`
|
|
548
|
+
|
|
549
|
+
## 已知限制
|
|
550
|
+
|
|
551
|
+
| 限制 | 说明 |
|
|
552
|
+
|------|------|
|
|
553
|
+
| **单后端** | 同一时间只能有一个容器连接。如需多容器,可启动多个 relay 实例 |
|
|
554
|
+
| **消息时序** | 多条命令连续发送可能导致输出交错。建议每条命令后等待响应 |
|
|
555
|
+
| **无压缩** | 大量输出(如 `cat largefile`)会逐字节发送,效率不高 |
|
|
556
|
+
| **无心跳** | 依赖 TCP keepalive 检测连接断开。长时间无命令不会主动断开 |
|
|
557
|
+
| **bash 独占** | 当前绑定了 `/bin/bash -i`,无法直接转发其他 TCP 服务(如 MySQL) |
|
|
558
|
+
|
|
559
|
+
## 从旧版升级
|
|
560
|
+
|
|
561
|
+
| 版本 | 变更 | 迁移说明 |
|
|
562
|
+
|------|------|---------|
|
|
563
|
+
| v0.1.0 → v0.2.0 | 新增 TLS、认证、shell 参数 | 需 Python >= 3.10;旧 `python3 ws_relay.py` 仍可用,但不再维护 |
|
|
564
|
+
| v0.2.0 起 | CLI 统一为 `ws-tunnel` | 建议通过 `pip install -e .` 安装后使用 |
|
|
565
|
+
|
|
566
|
+
## 发布到 PyPI
|
|
567
|
+
|
|
568
|
+
```bash
|
|
569
|
+
pip install build twine
|
|
570
|
+
python -m build
|
|
571
|
+
twine upload dist/*
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
## 许可证
|
|
575
|
+
|
|
576
|
+
MIT
|