# 网络代理与网络隧道知识专题

> 目标：建立代理、隧道、网关、NAT、端口转发之间的统一认知，并用当前 Mac ↔ aland 的 Deskflow 稳定连接作为完整案例。

## 一、先建立总的心智模型

网络中间技术看起来相似，但关注的问题不同：

| 技术 | 核心问题 | 典型动作 |
|---|---|---|
| 代理 Proxy | 谁替谁通信？ | 接收一段连接，再代表一方建立另一段连接 |
| 隧道 Tunnel | 数据怎样穿过中间网络？ | 封装、传输、解封装，可选加密 |
| 网关 Gateway | 流量从哪里进入另一个系统或网络？ | 路由、治理、协议转换、安全控制 |
| NAT | 地址怎样改写？ | 改写 IP/端口及连接跟踪状态 |
| 端口转发 | 某个入口端口送到哪里？ | 把监听端口的流量转给固定目标 |

```mermaid
flowchart TB
    APP["应用：Deskflow / 浏览器 / SSH"]
    APP --> PROXY["代理：代替一方建立连接"]
    APP --> TUNNEL["隧道：把数据封装后运到另一端"]
    APP --> GATEWAY["网关：系统或网络的统一入口"]
    PROXY --> NET["底层 TCP / UDP / IP 网络"]
    TUNNEL --> NET
    GATEWAY --> NET
    NET --> NAT["NAT / 路由 / 防火墙"]
```

一句话记忆：

- 代理关注**通信角色**。
- 隧道关注**运输方式**。
- 网关关注**系统边界与治理**。
- NAT 关注**地址改写**。

它们不是互斥关系：一个 API 网关通常通过反向代理转发；`ssh -D` 是 SOCKS 代理通过 SSH 隧道运输；VPN 网关会建立网络层隧道。

---

## 二、网络代理专题

### 2.1 代理的基本结构

代理通常把一次端到端通信拆成两段连接：

```mermaid
flowchart LR
    C["客户端"] -->|"连接 1"| P["代理"]
    P -->|"连接 2"| S["目标服务"]
    S --> P --> C
```

代理可以只转发字节，也可以理解协议并执行鉴权、缓存、过滤、路由和日志记录。

### 2.2 正向代理与反向代理

```mermaid
flowchart LR
    C["客户端"] --> FP["正向代理<br/>代表客户端"] --> INTERNET["互联网服务"]
    U["外部用户"] --> RP["反向代理<br/>代表服务器"] --> S["后端服务集群"]
```

| 类型 | 代表谁 | 隐藏谁 | 常见场景 |
|---|---|---|---|
| 正向代理 | 客户端 | 客户端和内部网络 | 企业出口、访问控制、调试、SOCKS |
| 反向代理 | 服务端 | 后端拓扑和真实地址 | HTTPS、负载均衡、域名/路径路由 |

### 2.3 按工作层次分类

| 层次 | 能看到什么 | 常用技术 |
|---|---|---|
| L4/TCP 代理 | TCP/UDP 连接、IP、端口 | HAProxy TCP、Nginx Stream、Envoy TCP Proxy |
| L7/应用代理 | HTTP 方法、域名、路径、请求头等 | Nginx HTTP、Caddy、Squid、Kong、APISIX |
| 通用代理协议 | 客户端明确告诉代理目标地址 | SOCKS4/5、HTTP CONNECT |
| 透明代理 | 应用未显式配置代理，流量被系统重定向 | TPROXY、策略路由、服务网格 sidecar |

### 2.4 代理适用场景

1. **统一入口**：多个后端只暴露一个域名。
2. **流量治理**：鉴权、限流、熔断、灰度、审计。
3. **隐藏与隔离**：客户端看不到后端真实地址，或服务端看不到原始客户端地址。
4. **协议处理**：TLS 终止、HTTP/2、WebSocket、gRPC 转换。
5. **调试与观测**：mitmproxy、Charles 等查看应用层请求。
6. **统一出口**：企业内网通过 Squid/SOCKS 访问外部网络。

### 2.5 基础工具

| 需求 | 工具 |
|---|---|
| 使用 HTTP/SOCKS 代理 | `curl -x`、环境变量 `HTTP_PROXY`/`ALL_PROXY` |
| 临时创建 SOCKS 代理 | `ssh -D` |
| HTTP 调试代理 | mitmproxy |
| 正向 HTTP 代理 | Squid |
| Web 反向代理 | Nginx、Caddy |
| 负载均衡 | HAProxy、Envoy |
| 简单 TCP 中继 | socat |

---

## 三、网络隧道专题

### 3.1 隧道的底层原理

隧道不是“必须基于代理”。它的核心是把内层数据装入外层协议：

```mermaid
flowchart LR
    INNER["内层数据<br/>字节流 / IP 包 / 以太网帧"]
    INNER --> ENC["隧道入口<br/>封装；可选加密"]
    ENC ==>|"外层 TCP / UDP / IP 包"| NETWORK["中间网络"]
    NETWORK ==> DEC["隧道出口<br/>解封装；可选解密"]
    DEC --> RESTORE["恢复内层数据"]
```

中间网络只负责运输外层包。加密不是“隧道”的必要条件：SSH、WireGuard、IPsec 会加密；GRE、VXLAN 通常只封装，不天然提供机密性。

### 3.2 隧道的主要类型

| 粒度 | 代表技术 | 承载内容 | 场景 |
|---|---|---|---|
| 单端口/字节流 | SSH `-L`、`-R` | 某个 TCP 服务 | 跳板访问、临时暴露内网服务 |
| 动态应用连接 | SSH `-D` + SOCKS | 多个目标 TCP 连接 | 临时通用代理 |
| 网络层 | WireGuard、IPsec、OpenVPN | IP 数据包 | 远程办公、站点互联 |
| 网络覆盖层 | GRE、VXLAN | IP 包或以太网帧 | 数据中心、虚拟网络 |
| 应用协议穿透 | HTTP CONNECT、WebSocket tunnel | 加密字节流或应用数据 | 穿过 HTTP 代理/防火墙 |

### 3.3 SSH 三种端口转发

#### 本地转发 `-L`

```bash
ssh -N -L 8080:internal.example:80 jump-host
```

本机监听 `8080`，流量经过 SSH 到远端，再由远端连接 `internal.example:80`。适合“本机要访问远端内网服务”。

#### 远程/反向转发 `-R`

```bash
ssh -N -R 24802:127.0.0.1:24802 remote-host
```

远端监听 `24802`，流量经过 SSH 返回本机，再由本机连接 `127.0.0.1:24802`。适合“远端要访问本机，但远端无法主动连接本机”。Deskflow 使用的就是这个模式。

#### 动态转发 `-D`

```bash
ssh -N -D 127.0.0.1:1080 remote-host
```

本机提供 SOCKS 代理。应用每次可以指定不同目标，SSH 服务端代为连接，因此它是“SOCKS 代理 + SSH 加密隧道”。

### 3.4 SSH 隧道内部怎么工作

```mermaid
sequenceDiagram
    participant A as 本地应用
    participant C as ssh 客户端
    participant D as 远端 sshd
    participant S as 目标服务
    C->>D: 建立 TCP 连接并完成 SSH 握手/认证
    A->>C: 连接本地或远端监听入口
    C->>D: 在 SSH 连接中打开逻辑 Channel
    D->>S: 按转发规则建立目标 TCP 连接
    A<<->>S: 字节流经 SSH Channel 加密运输
```

一条 SSH TCP 连接可以复用终端、文件传输和多个转发 Channel。SSH 进程或底层 TCP 连接消失，所有依赖它的隧道也随之消失。

### 3.5 隧道适用场景

1. 两端路由不对称或某一端地址经常变化。
2. 服务在 NAT、防火墙或内网后，无法直接被访问。
3. 通过跳板机访问内网数据库、Web 服务、远程桌面。
4. 在不可信网络上加密传输原本未加密的协议。
5. 将两个网段连接成虚拟专网。
6. 在既有协议允许的出口上承载其他流量。

---

## 四、代理与隧道的选择

```mermaid
flowchart TD
    START["我要解决什么问题？"]
    START -->|"统一管理 HTTP/API"| APIGW["反向代理 / API 网关"]
    START -->|"某个应用经统一出口访问"| FWD["HTTP / SOCKS 正向代理"]
    START -->|"临时访问一个远端端口"| SSHL["SSH -L"]
    START -->|"让远端访问本地服务"| SSHR["SSH -R"]
    START -->|"让多个应用走远端出口"| SSHD["SSH -D / SOCKS"]
    START -->|"整机或整个网段互通"| VPN["WireGuard / IPsec / OpenVPN"]
```

| 判断问题 | 更可能的方案 |
|---|---|
| 是否需要理解并治理 HTTP/API？ | 代理或 API 网关 |
| 是否只转发一个固定 TCP 服务？ | SSH 端口隧道或 TCP 转发 |
| 是否要承载整个网段？ | VPN/网络层隧道 |
| 是否需要客户端动态选择多个目标？ | SOCKS 代理，必要时通过 SSH 隧道 |
| 是否只是地址/端口映射？ | NAT/端口转发，不一定需要代理或隧道 |

---

## 五、Deskflow 实战：动态 IP 的 Mac 如何与固定 IP 的 aland 稳定连接

### 5.1 问题模型

- Mac 是 **Deskflow Server**，提供键鼠输入，监听 TCP `24802`。
- aland 是 **Deskflow Client**，需要连接 Deskflow Server。
- aland 地址固定：`30.74.56.169`。
- Mac 的 Wi-Fi、DHCP 或 VPN 地址可能变化，而且 aland 无法可靠地主动访问 Mac。

如果采用普通直连：

```mermaid
flowchart LR
    A["aland Deskflow Client"] -.->|"失败或不稳定：Mac 地址变化/路由不可达"| M["Mac Deskflow Server :24802"]
```

### 5.2 核心决策：反转建连方向

不再让 aland 寻找动态地址的 Mac，而是让 Mac 永远主动连接固定地址的 aland：

```mermaid
flowchart LR
    DC["aland Deskflow Client"] -->|"连接自身 127.0.0.1:24802"| RL["aland sshd<br/>远程转发监听"]
    RL ==>|"已建立的 SSH 加密连接"| SC["Mac ssh/autossh"]
    SC -->|"连接 127.0.0.1:24802"| DS["Mac Deskflow Server"]
```

注意两个不同的“方向”：

- **SSH 建连方向**：Mac → aland。
- **Deskflow 业务流方向**：aland Client → aland 本地端口 → SSH 隧道 → Mac Server。

因此它叫 SSH **远程/反向端口转发**，并不代表 SSH TCP 连接由 aland 发起。

### 5.3 当前实际命令

命令在 Mac 上由脚本执行：

```bash
autossh -M 0 -N \
  -o ServerAliveInterval=15 \
  -o ServerAliveCountMax=3 \
  -o ExitOnForwardFailure=yes \
  -o ConnectTimeout=10 \
  -o BatchMode=yes \
  -R 24802:127.0.0.1:24802 \
  30.74.56.169
```

`-R 24802:127.0.0.1:24802` 应从 SSH 服务端 aland 的视角阅读：

1. 在 aland 上监听 `24802`。
2. 收到连接后，把字节送进现有 SSH 连接。
3. 在 Mac 侧连接 `127.0.0.1:24802`。
4. 该目标正是 Mac 的 Deskflow Server。

由于 `-R` 未指定非 loopback 监听地址，当前 aland 实际仅监听 `127.0.0.1:24802` 和 `[::1]:24802`，没有向公司网络暴露此入口。

### 5.4 为什么 Mac IP 变化不影响配置

```mermaid
sequenceDiagram
    participant M as Mac
    participant A as aland 30.74.56.169
    M->>A: Mac 用当前任意可用源 IP 主动建立 SSH
    A-->>M: 在已建立连接上承载反向端口 Channel
    Note over M,A: aland 只需要固定地被 Mac 找到
    Note over M: Mac 自己不需要一个可被 aland 主动访问的固定 IP
```

网络切换会让原 SSH TCP 连接断开，但不会要求修改目标配置；Mac 恢复网络后仍然连接同一个 `30.74.56.169`，然后重新创建远程转发。

### 5.5 三层稳定性与自愈

```mermaid
flowchart TB
    L["launchd<br/>RunAtLoad + KeepAlive"] --> A["autossh<br/>负责 SSH 重连"]
    A --> W["自定义 SSH wrapper<br/>连接前清理 aland 残留转发"]
    W --> S["ssh -N -R<br/>真正维持隧道"]
    S --> D["Deskflow TCP 业务流"]
```

1. **launchd**：登录后自动启动；进程异常退出后重新拉起。
2. **autossh**：`-M 0` 表示不使用额外监控端口，而依赖 SSH 的 `ServerAliveInterval=15` 与 `ServerAliveCountMax=3` 检测失活并重连。
3. **wrapper 清理**：每次连接前在 aland 执行 `free-deskflow-port.sh`，清理仍占用 `24802` 的旧无子进程转发会话，避免新连接报 `remote port forwarding failed for listen port 24802`。
4. **ExitOnForwardFailure**：如果远程端口未成功建立，SSH 直接失败，让 autossh 能识别并重试，而不是留下“SSH 活着但业务隧道没建立”的假健康状态。

常驻进程链：

```text
macOS launchd
└── deskflow-tunnel.sh
    └── autossh
        └── ssh -N -R 24802:127.0.0.1:24802 30.74.56.169
```

Mac 休眠期间隧道不可用；唤醒并恢复网络后自动重建。Mac 关机或用户会话退出后，隧道也不存在。aland 不需要额外的隧道客户端，但 `sshd` 和 Deskflow Client 必须运行。

### 5.6 2026-08-03 当前状态核验

本次只读核验结果：

- Mac `com.deskflow.tunnel`：`running`，`autossh` 正在运行。
- Mac Deskflow Server：监听 `*:24802`。
- Mac 本地已有 SSH 转发到 Deskflow 的 `ESTABLISHED` 连接。
- aland：`127.0.0.1:24802`、`[::1]:24802` 正在监听。
- aland Deskflow Client：连接自身 `127.0.0.1:24802`，状态为 `ESTABLISHED`。
- aland Deskflow Client 和 Mac Deskflow Server 当前均在运行。

结论：**历史设计、当前脚本和两端运行状态一致，现有稳定连接正常。**

### 5.7 安全边界

- aland 的隧道入口只绑定 loopback，这是合理且安全的默认值。
- Deskflow 自身 TLS 当前关闭，但 aland ↔ Mac 的业务主体在 SSH 连接内加密。
- 当前 Mac Deskflow Server 实际监听 `*:24802`，因此除了 SSH 隧道入口外，Mac 所在网络是否能直接访问该端口还取决于 macOS 防火墙和网络路由。这不影响反向隧道工作，但它是独立于隧道的暴露面。
- SSH 主机密钥、私钥权限和 aland 账户权限仍然属于安全边界；隧道加密不等于目标服务自身拥有独立认证。

### 5.8 故障定位顺序

先按链路从外到内排查：

```mermaid
flowchart LR
    L["launchd"] --> A["autossh/ssh"] --> R["aland :24802 监听"] --> C["aland Deskflow Client"] --> S["Mac Deskflow Server"]
```

```bash
# 1. Mac：launchd 和 autossh
launchctl print gui/$(id -u)/com.deskflow.tunnel | grep -E 'state|pid'
pgrep -fl autossh

# 2. aland：反向监听和连接
ssh 30.74.56.169 "ss -tan | grep 24802"

# 3. Mac：隧道日志
tail /tmp/deskflow-tunnel.log

# 4. aland：Deskflow Client
ssh 30.74.56.169 "pgrep -af deskflow"

# 5. Mac：Deskflow Server 是否监听
lsof -nP -iTCP:24802
```

常见故障与归属：

| 现象 | 可能层次 |
|---|---|
| aland 没有 `24802` LISTEN | SSH `-R` 未建立 |
| 报 remote port forwarding failed | 旧会话残留或端口被占 |
| 有 LISTEN、无 ESTABLISHED | aland Deskflow Client 未运行或连接目标错误 |
| 两端 ESTABLISHED、键鼠无响应 | Deskflow、屏幕布局、macOS 权限或输入法问题 |
| Mac 唤醒后短暂不可用 | 旧 TCP 已失效，等待 autossh 检测并重建 |

---

## 六、建议的学习专题顺序

1. **TCP/IP 基础**：IP、端口、TCP 连接、监听套接字、路由。
2. **NAT 与防火墙**：SNAT、DNAT、连接跟踪、入站/出站规则。
3. **代理技术**：正向/反向、L4/L7、HTTP CONNECT、SOCKS5。
4. **SSH 转发**：`-L`、`-R`、`-D`、Channel 复用、KeepAlive。
5. **VPN 与网络层隧道**：TUN/TAP、WireGuard、IPsec、路由表。
6. **网关与服务治理**：API Gateway、Ingress、负载均衡、服务网格。
7. **可靠性**：守护进程、健康检查、自动重连、幂等清理、可观测性。
8. **安全**：最小监听范围、认证授权、TLS/SSH、密钥管理、暴露面。

## 七、当前配置的权威来源

- `~/smb-work/T8-work-env/deskflow-setup.md`：Deskflow 架构、自愈方案和排障记录。
- `~/bin/deskflow-tunnel.sh`：当前 autossh/SSH 参数。
- `~/bin/deskflow-ssh-wrapper.sh`：重连前清理逻辑。
- `~/Library/LaunchAgents/com.deskflow.tunnel.plist`：launchd 常驻配置。
- `~/smb-work/T22-ai-automation/HANDOFF.md`：Deskflow 输入法守护等相关历史。

