jayli / jayli/block-proxy

隧道客户端掉线后 5 小时不重连:代理访问隧道域名报 Proxy CONNECT aborted

Open
#2 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Kotlin
Stars
1
Forks
0
PR merge metrics
No merged PRs in 30d

Description

## 现象

```bash
curl -v -x http://admin:admin@192.168.124.10:8001 https://www.baidu.com
> CONNECT www.baidu.com:443 HTTP/1.1
> Proxy-Authorization: Basic bxxxxxxw==
* Proxy CONNECT aborted
curl: (56) Proxy CONNECT aborted
```

时间:2026-09-01 08:11 ~ 08:21(连续多次重试均失败)。

## 排查结论

**服务端无异常,根因是隧道客户端掉线且 5 小时未重连。**

- 服务器(192.168.124.10,OpenWRT)上 `www.baidu.com` 配置在 `tunnel_domains` 中,该域名的 CONNECT 被交给隧道做反向 CONNECT(`tunnel/manager.js` `forward()`),由隧道客户端代连。
- curl 请求到达服务器时隧道无活跃会话(`_connected=false`),被直接拒绝,日志与 curl 时刻精确对应:

```
[2026-09-01 08:11:30] [Tunnel] Forward rejected: tunnel disconnected for www.baidu.com:443
```

- 服务器侧逐项验证均正常:8001/8002/8003/8004 全部监听、8003 本地 HTTP/2 响应正常、防火墙 INPUT ACCEPT、`yui.cool:8003` 外部可达、pm2 进程 online 22h 无异常重启。

## 客户端活动时间线(服务器日志)

| 时间(2026 年) | 事件 |
| --- | --- |
| 8-30 全天 | 正常轮换,15 次会话,间隔 1~2h |
| 8-31 00:18 ~ 05:52 | 正常轮换(约 1.5h 一次) |
| **8-31 06:25 ~ 09:42** | **重建风暴:每 90~100 秒一个会话,持续约 3 小时**。服务器侧每个会话存活约 90s 后被 `liveness timeout` 踢连(上行通路失效,收不到任何上行帧) |
| 8-31 12:03 ~ 12:04 | 密集重建 3 次(修复测试痕迹) |
| **8-31 12:18 之后** | **风暴消失**,恢复 1.5~2h 正常轮换,持续约 14 小时(14:08, 16:05, 17:31, 18:48, 20:41, 20:59, 22:40) |
| 9-1 00:40、02:13 | 正常轮换 |
| **9-1 03:29:10** | **b36bc51d 会话 SSE 被关闭(无 liveness 踢连记录),15s 重连窗口内未重连,03:29:25 会话被服务器清理** |
| 9-1 03:29 之后 | **5 小时没有任何客户端连接尝试**(无 session created、无 TLS 失败、无新 TCP 连接痕迹) |

## 与 753395b 修复的关系

1. **修复有效**:8-31 06:25~09:42 的风暴与 commit 描述完全吻合(服务器 90s liveness-timeout 反复踢会话、客户端无限重建会话)。修复部署后(12:18 起)风暴消失,稳定运行约 14 小时。
2. **但 9-1 03:29 的断连是相反的表现**(风暴 = 疯狂重连;现在 = 完全不重连),服务器侧无法区分以下两种可能:
- **A. 设备问题(与代码无关)**:手机凌晨断电/断网/关机,SSE 被网络层关闭,之后一直未联网。
- **B. 潜在代码缺陷**:上行失败触发 `closeTransport` 整链重连后,若重连时网络"半死"(TCP 可建立但 HTTP 无响应,SSE 客户端 `readTimeout=0` 无超时),`XhttpTransport.runSseLoop()` 会卡死在 `connectSse()`,15s 重连窗口的过期检查永远执行不到 → 断连回调不触发 → `TunnelClient.mainLoop()` 在 `establishAndServe` 的等待循环中永远不退出。注:该卡死点是既有逻辑,修复 commit 未改动,但新代码新增的"上行失败触发整链重连"路径使其更容易被走到。

## 待办:客户端侧取证

需要手机侧证据定论,取证命令:

```bash
adb shell "run-as com.blockproxy.android sh -c 'tail -50 files/tunnel-diagnostics.log'"
adb logcat -d | grep -E "TunnelClient|XhttpTransport" | tail -60
```

判定标准:
- 诊断日志停在 `tunnel.connection_failed ... nextBackoffMs=60000` 循环 → 网络未恢复(情况 A)
- 停在 `sse.passive_disconnected` / `sse.connecting` 之后无下文 → 卡死(情况 B)
- 无 app 启动记录 → 手机关机/进程被杀(情况 A)

**即时恢复**:重启客户端 app(或手机)后隧道立即重连。

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by collecting the two listed adb/logcat commands from the client, then compare the output with the A/B criteria in the issue. Read XhttpTransport.runSseLoop() and connectSse(), followed by TunnelClient.mainLoop() and establishAndServe(), to trace the 15-second reconnect window. Done means the client-side evidence distinguishes a device outage from the suspected SSE stall and identifies the confirmed failure path.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin
Domain
mobile-dev, networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.