Files
IPTables-Management/plan_iptables_forward.md

572 lines
26 KiB
Markdown
Raw Permalink 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.
# IPTables 端口转发管理脚本 · 实施方案
> 目标:在 Debian 12/13 上交付一个**自包含**、**交互式中文 CLI**、**可通过自动化测试验证**的端口转发管理工具。
> 本方案按**阶段化排队执行**,每个阶段都有明确的**进入/退出状态**与**验证方式**。
---
## 0. 速览 (Executive Summary)
| 维度 | 决策 |
|------|------|
| 协议 | 每条规则可选 TCP / UDP / 两者 |
| IP 版本 | 每条规则可选 IPv4 / IPv6 / 两者 (ip6tables) |
| 持久化 | `iptables-persistent` (netfilter-persistent 1.0.23) |
| 管理范围 | 仅管理本脚本添加的规则,靠 `-m comment --comment "MGMT:<UUID>"` 标识 |
| 存储 | `/var/lib/iptables-forward/rules.db` (pipe-separated KV) |
| UI 语言 | 交互全部中文,日志 & 代码英文 |
| 入口 | `iptables-forward.sh` (可选 `install.sh` 链接到 `/usr/local/bin/iptables-forward`) |
| 最小运行依赖 | bash ≥ 4, root/sudo, iptables, (可选) ip6tables, iptables-persistent |
---
## 1. 目标与边界
### 1.1 必须达成 (Must)
1. `./iptables-forward.sh` 启动后立即做**环境自检**;若缺失依赖,**明确列出并询问是否自动安装**,用户确认后静默 apt 安装完成。
2. 主菜单提供:**查看规则**、**添加规则**、**删除规则**、**环境状态**、**保存规则**、**退出**。
3. 添加时支持字段:协议 (tcp/udp/both)、本地端口、目标 IP (v4 或 v6)、目标端口、IP 版本 (4/6/both)、描述 (可选)。
4. 规则立即生效,且通过 `netfilter-persistent save` 写入 `/etc/iptables/rules.v4``/etc/iptables/rules.v6`
5. 重启后规则不丢失;重启后脚本再次打开仍能**正确列出已有的本脚本规则**。
6. 删除时仅删除本脚本管理的规则;操作需**二次确认**。
7. 所有输入经**校验** (IP 合法性、端口范围、协议枚举、IP 族与 IP 字符串匹配)。
8. 整套代码随附**自动化测试**,至少覆盖单元级校验与核心生命周期。测试脚本在 `tests/` 目录,`tests/run_all.sh` 一键运行。
### 1.2 不做 (Non-Goals)
- 不管理 INPUT/OUTPUT、路由表、防火墙策略。
- 不替代/改写非本脚本创建的 iptables 规则。
- 不实现 Web UI、REST API。
- 不在 nftables 纯原生语法下工作 (但兼容 Debian 13 的 `iptables-nft` 后端)。
- 不自动开放 `ufw`/`firewalld` (用户自行负责)。
---
## 2. 技术选型
| 模块 | 方案 | 理由 |
|------|------|------|
| Shell | `bash`, `set -Eeuo pipefail`, `trap` 兜底 | Debian 默认,行为可控 |
| 包管理 | `apt-get -y install` (non-interactive, `DEBIAN_FRONTEND=noninteractive`) | 避免交互弹窗 |
| 持久化 | `iptables-persistent` + `netfilter-persistent save/reload` | 官方包1.0.23 在 trixie 可用 |
| IP 转发 | 写 `/etc/sysctl.d/99-iptables-forward.conf``sysctl --system` | 现代 drop-in 模式 |
| 规则定位 | `iptables -m comment --comment "MGMT:<UUID>"` + 精确 `-D` 删除 | 无需 line-number 脆弱匹配 |
| UUID | `head -c 8` from `/proc/sys/kernel/random/uuid` (去掉 `-`) | 无外部依赖 |
| 存储格式 | pipe-separated KV一行一条规则 | 人眼可读、易用 `awk`/`grep` 解析 |
| UI | ANSI 颜色 + Unicode 盒线 (`╔═╗║╚╝╠╣╤╧`) | Debian 默认 UTF-8 终端可用 |
| IP 校验 | Bash 正则 (`^([0-9]{1,3}\.){3}[0-9]{1,3}$` + 段值 <=255 校验) + IPv6 相对宽松匹配 | 避免 `python`/`perl` 依赖 |
| 测试 | 纯 bash 测试框架,支持 mock 与 integration整数退出码断言 | 无需 bats/shunit |
### 2.1 iptables 规则模板 (每条逻辑规则生成)
对协议 P (tcp/udp) × IP 族 F (iptables/ip6tables),生成 **4 条** iptables 规则:
```text
# 1) PREROUTING DNAT — 外部进入的包改目标
$CMD -t nat -A PREROUTING -p <P> --dport <LPORT> \
-j DNAT --to-destination <TIP>:<TPORT> \
-m comment --comment "MGMT:<UUID>"
# 2) POSTROUTING MASQUERADE — 返程包伪装源地址
$CMD -t nat -A POSTROUTING -p <P> -d <TIP> --dport <TPORT> \
-j MASQUERADE \
-m comment --comment "MGMT:<UUID>"
# 3) FORWARD ACCEPT — 绕过 FORWARD DROP 策略
$CMD -A FORWARD -p <P> -d <TIP> --dport <TPORT> \
-m conntrack --ctstate NEW,ESTABLISHED,RELATED \
-j ACCEPT \
-m comment --comment "MGMT:<UUID>"
# 4) FORWARD 回程 ACCEPT — 允许 DNAT/MASQUERADE 后的回包继续转发
$CMD -A FORWARD -p <P> -s <TIP> --sport <TPORT> \
-m conntrack --ctstate ESTABLISHED,RELATED \
-j ACCEPT \
-m comment --comment "MGMT:<UUID>"
```
其中 `$CMD``iptables`(v4) 或 `ip6tables`(v6)。`<TIP>` v6 时需加 `[]` (仅在 `--to-destination` 部分)。
一条"逻辑规则"的展开上限:
- `proto=both` × `ipv=both` = 2 × 2 × 4 条 = **16** 条 iptables 规则
- 最常见 `proto=tcp` × `ipv=4` = 1 × 1 × 4 条 = **4**
所有规则共享同一个 UUID通过注释绑定删除时一并清除。
---
## 3. 目录结构
```text
IPTables-Management/
├── iptables-forward.sh # 主入口,交互菜单 (short, delegates to lib)
├── install.sh # 一键链接到 /usr/local/bin (可选)
├── lib/
│ ├── common.sh # 颜色/盒线/提示/通用校验 (IP, port)
│ ├── env_check.sh # 环境自检 + 自动安装 + sysctl 配置
│ ├── rules_mgr.sh # 添加/列表/删除 业务逻辑
│ ├── iptables_ops.sh # 纯 iptables 命令封装 (可被 mock)
│ ├── persist.sh # netfilter-persistent save/reload
│ └── storage.sh # rules.db 读写与解析
├── tests/
│ ├── lib/
│ │ └── assert.sh # 测试断言工具 (assert_eq, assert_contains)
│ ├── mocks/
│ │ └── iptables-mock.sh # mock iptables 命令, 记录调用
│ ├── test_common.sh # 校验函数单元测试 (IP, port 合法性)
│ ├── test_storage.sh # 存储层 CRUD 单元测试
│ ├── test_rules_unit.sh # rules_mgr + mock iptables
│ ├── test_env_check.sh # 环境检查决策表测试
│ ├── test_integration.sh # 真实 iptables 测试 (需要 root, 可跳过)
│ └── run_all.sh # 统一入口,支持 --skip-integration
├── plan_iptables_forward.md # 本文档
└── README.md # 使用说明 (最小化)
```
运行期状态与配置 (安装后产生)
```text
/var/lib/iptables-forward/
└── rules.db # 规则元数据库 (权限 640, root:root)
/etc/sysctl.d/
└── 99-iptables-forward.conf # ip_forward / ipv6 forwarding 开关
/etc/iptables/ # 由 iptables-persistent 管理
├── rules.v4
└── rules.v6
```
---
## 4. 核心组件设计
### 4.1 `lib/common.sh` — 基础设施层
职责:
- ANSI 颜色常量:`CLR_RED/GREEN/YELLOW/BLUE/CYAN/BOLD/DIM/RESET`
- 盒线绘制函数:`box_top / box_bottom / box_line / box_separator` (参数为宽度与内容)
- 日志函数:`log_info / log_warn / log_err / log_ok` (彩色 + 时间戳)
- 交互函数:
- `prompt_input "提示" [默认值]` → 回显字符串
- `prompt_confirm "提示" [y|n]` → 返回 0/1
- `prompt_select "提示" "选项1" "选项2" …` → 回显索引
- 校验:
- `validate_ipv4 <str>` → 0/1
- `validate_ipv6 <str>` → 0/1
- `validate_port <str>` → 0/1 (165535)
- `validate_proto <str>` → 0/1 (tcp/udp/both)
- `validate_ipver <str>` → 0/1 (4/6/both)
- `require_root` — 非 root 则打印提示并退出 2
### 4.2 `lib/env_check.sh` — 环境自检与安装
决策表 (脚本启动第 1 步)
| 检测项 | 条件 | 缺失行为 |
|--------|------|----------|
| 运行用户 | UID==0 | 立即 `exit 2`,提示 `sudo` |
| `iptables` | `command -v iptables` | apt install iptables |
| `ip6tables` | `command -v ip6tables` (若开启 v6) | 同上 (同包) |
| `iptables-persistent` | `dpkg -s iptables-persistent` | apt install iptables-persistent |
| `/proc/sys/net/ipv4/ip_forward` | 值为 1 | 写 `/etc/sysctl.d/99-iptables-forward.conf``sysctl --system` |
| `/proc/sys/net/ipv6/conf/all/forwarding` | 值为 1 | 同上 |
| `/var/lib/iptables-forward/` | 存在且可写 | `mkdir -p` + `chmod 750` |
关键实现要点:
- 汇总所有缺失项,一次性展示给用户,**只问一次**「是否自动修复?(y/N)」。
- 用户拒绝则退出 3告知用户手动命令。
- 用户同意则按顺序执行;任一步失败立即终止并回滚 sysctl 写入 (非常重要)。
- apt 安装使用:
```bash
DEBIAN_FRONTEND=noninteractive apt-get update -qq
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq iptables iptables-persistent
```
- `iptables-persistent` 安装时 debconf 会询问是否保存当前规则 → 预置答案:
```bash
echo iptables-persistent iptables-persistent/autosave_v4 boolean true | debconf-set-selections
echo iptables-persistent iptables-persistent/autosave_v6 boolean true | debconf-set-selections
```
### 4.3 `lib/storage.sh` — 规则元数据存储
文件:`/var/lib/iptables-forward/rules.db`
格式:每行一条规则,以 `|` 分隔 k=v 对。示例:
```text
uuid=a1b2c3d4|proto=tcp|lport=8080|tip=192.168.1.100|tport=80|ipver=4|desc=web|created=2026-04-17T10:00:00+08:00
uuid=e5f6g7h8|proto=both|lport=53535|tip=8.8.8.8|tport=53|ipver=4|desc=DNS|created=2026-04-17T10:05:00+08:00
```
接口:
- `storage_init` — 确保文件存在且权限为 0640 root:root
- `storage_add "<k=v>|<k=v>|…"` — 追加一行
- `storage_list` — 输出全部行
- `storage_get <uuid>` — 输出指定行,未找到返回 1
- `storage_delete <uuid>` — 原子替换 (写入临时文件后 `mv`)
- `storage_parse <line> <key>` — 从行中抽取字段值
### 4.4 `lib/iptables_ops.sh` — iptables 命令封装
为可测试性,所有 iptables 调用都经该层;测试时可以用 `IPTABLES_BIN` / `IP6TABLES_BIN` 环境变量替换为 mock。
```bash
: "${IPTABLES_BIN:=iptables}"
: "${IP6TABLES_BIN:=ip6tables}"
ipt_apply_rule() # args: uuid proto lport tip tport ipver
ipt_remove_rule() # args: uuid proto lport tip tport ipver
ipt_find_by_uuid() # args: uuid → 列出匹配的 (cmd, table, chain, rule) 组
```
`ipt_apply_rule` 内部展开为:对每个 (proto × ipver) 组合,调用 3 次对应的二进制。
`ipt_remove_rule` 使用**与添加完全一致的参数**加 `-D` 即可精确删除;不依赖 line number。
### 4.5 `lib/rules_mgr.sh` — 业务编排层
职责:
- `cmd_list` — 从 storage 读出全部规则,格式化为表格,对每条规则校验其 PREROUTING / POSTROUTING / 双向 FORWARD 规则是否仍在 iptables 中 (健康指示 [✓]/[!])。
- `cmd_add` — 交互表单 → 校验 → 生成 UUID → `ipt_apply_rule` → `storage_add` → `persist_save`。失败自动回滚已加 iptables 规则。
- `cmd_delete` — 调用 `cmd_list` 的交互版 → 用户选编号 → 二次确认 → `ipt_remove_rule` → `storage_delete` → `persist_save`。
### 4.6 `lib/persist.sh`
```bash
persist_save() { netfilter-persistent save >/dev/null; }
persist_reload() { netfilter-persistent reload >/dev/null; }
```
注意Debian 13 默认使用 `iptables-nft``netfilter-persistent save` 已兼容。若未来需要 legacy 后端,可通过 `update-alternatives --set iptables /usr/sbin/iptables-legacy` 切换,**本方案不做自动切换**。
### 4.7 `iptables-forward.sh` — 主入口
启动流程:
```text
1. trap ERR 收集异常, 打印彩色栈
2. source lib/common.sh
3. require_root
4. source 其它 lib
5. env_check_all (缺失→提示→修复→再检测;全部就绪才继续)
6. storage_init
7. main_menu loop
```
主菜单循环:
```text
┌──────────────────────────────────────┐
│ [1] 查看所有转发规则 │
│ [2] 添加新的转发规则 │
│ [3] 删除现有转发规则 │
│ [4] 查看环境状态 │
│ [5] 立即保存规则到磁盘 │
│ [0] 退出 │
└──────────────────────────────────────┘
```
---
## 5. 交互界面样例
### 5.1 主菜单
```text
╔══════════════════════════════════════════════════════╗
║ IPTables 端口转发管理工具 v1.0 ║
╠══════════════════════════════════════════════════════╣
║ 状态: [✓] 已就绪 规则数: 3 持久化: [✓] ║
╠══════════════════════════════════════════════════════╣
║ [1] 查看所有转发规则 ║
║ [2] 添加新的转发规则 ║
║ [3] 删除现有转发规则 ║
║ [4] 查看系统环境状态 ║
║ [5] 立即保存到磁盘 ║
║ [0] 退出 ║
╚══════════════════════════════════════════════════════╝
请选择 [0-5]:
```
### 5.2 规则列表
```text
╔══╤══════╤═════════╤═════════════════╤═════════╤══════╤════╤══════════════╗
║# │ 协议 │ 本地端口 │ 目标地址 │ 目标端口 │ IPv │ ✓ │ 描述 ║
╠══╪══════╪═════════╪═════════════════╪═════════╪══════╪════╪══════════════╣
║ 1│ TCP │ 8080 │ 192.168.1.100 │ 80 │ 4 │ ✓ │ web 服务 ║
║ 2│ UDP │ 53535 │ 8.8.8.8 │ 53 │ 4 │ ✓ │ DNS 转发 ║
║ 3│ TCP │ 2222 │ 2001:db8::1 │ 22 │ 6 │ ! │ SSH 跳板 ║
╚══╧══════╧═════════╧═════════════════╧═════════╧══════╧════╧══════════════╝
[✓] 规则存在且生效 [!] 规则在 db 但不在 iptables需修复
按回车返回主菜单...
```
### 5.3 添加表单
```text
╔══════════════════════════════════════════════════════╗
║ 添加新的端口转发规则 ║
╚══════════════════════════════════════════════════════╝
▸ 协议类型 [1] TCP [2] UDP [3] 两者 (默认 1):
▸ 本地监听端口 (1-65535):
▸ 目标 IP 地址:
▸ 目标端口 (1-65535):
▸ IP 版本 [1] IPv4 [2] IPv6 [3] 两者 (默认 1):
▸ 描述 (可选, 回车跳过):
─── 预览 ─────────────────────────────────
协议: TCP
监听端口: 8080
目标: 192.168.1.100:80
IP 版本: IPv4
描述: web 服务
▸ 确认添加? [y/N]:
```
### 5.4 删除确认
```text
▸ 请选择要删除的规则编号 (0 返回): 2
─── 即将删除 ────────────────────────────
UDP 127.0.0.1:53535 → 8.8.8.8:53 [DNS 转发]
▸ 确认删除? [y/N]:
```
---
## 6. 测试策略
### 6.1 单元测试 (Unit, 无需 root)
`tests/test_common.sh`:
- `validate_ipv4` 通过: `0.0.0.0 / 192.168.1.1 / 255.255.255.255`
- `validate_ipv4` 拒绝: `256.1.1.1 / 1.2.3 / abc / 空`
- `validate_ipv6` 通过: `::1 / 2001:db8::1 / fe80::1%eth0`
- `validate_ipv6` 拒绝: `:::1 / 1.2.3.4 / 空`
- `validate_port` 边界: `1 / 65535` 通过; `0 / 65536 / -1 / abc` 拒绝
- `validate_proto` / `validate_ipver` 枚举
`tests/test_storage.sh`:
- 初始化空 db
- 插入 3 条list 返回 3 条 (顺序保留)
- `get` 已存在 uuid 返回正确字段
- `get` 不存在 uuid 返回非零
- `delete` 存在的 uuid剩 2 条
- `delete` 不存在的 uuid 返回 1文件不变
- 并发安全tmpfile + mv 替换语义
`tests/test_rules_unit.sh`:
- 用 `iptables-mock.sh` 作为 `IPTABLES_BIN`,记录所有调用到 `/tmp/ipt_calls.log`
- `cmd_add` (tcp/ipv4) 后:
- mock 日志包含 4 条命令 (PREROUTING/POSTROUTING/FORWARD 请求/回程) 且参数正确
- storage 中新增 1 条UUID 与 mock 注释一致
- `cmd_add` (both/both) 后mock 日志包含 16 条命令
- `cmd_delete` 后mock 日志包含对应 `-D` 命令storage 中记录被移除
- `cmd_add` 中途失败 (mock 注入错误)确认回滚storage 不写入,已执行的 iptables `-A` 对应 `-D` 被调用
`tests/test_env_check.sh`:
- 构造 PATH sandbox 让 `iptables` / `dpkg` 不可见
- 断言 `env_check_all` 识别出正确的缺失项数量
- 模拟 sysctl 为 0断言写入 drop-in 并标记需要 `sysctl --system`
- 用户拒绝修复:断言退出码 3
### 6.2 集成测试 (Integration, 需要 rootWSL/容器/VM 均可)
`tests/test_integration.sh`:
1. **准备**:确保 iptables/ip6tables/iptables-persistent 存在,备份当前规则 `iptables-save > /tmp/ipt.bak`。
2. **端到端规则生命周期**
- 以非交互模式 (传入 stdin 预置输入或新增 `--batch` 入口) 添加规则 `tcp 65432 → 127.0.0.1:22`
- 断言 `iptables -t nat -L PREROUTING -n` 含 `MGMT:` 注释与预期参数
- 执行 `curl -sS --max-time 2 127.0.0.1:65432` 或 `nc -zv`,应命中 22 端口服务
- 删除规则,断言 iptables 中对应条目消失
3. **持久化**
- 添加规则 → `netfilter-persistent save` → 检查 `/etc/iptables/rules.v4` 包含 `MGMT:` 注释
- `netfilter-persistent flush && netfilter-persistent reload`,规则恢复
4. **IPv6**:同上流程使用 `::1`/`2001:db8::1`。
5. **仅管理自身范围**:手动添加一条无 `MGMT:` 注释的 iptables 规则 → 列表中**不出现**,删除所有管理规则后该条**仍存在**。
6. **清理**`iptables-restore < /tmp/ipt.bak`。
测试脚本必须**可重入**:中途失败也清理残留。
### 6.3 手工验收 (最小清单)
- [ ] 干净 Debian 13 VM`./iptables-forward.sh` 首次启动能识别缺失并一键修复
- [ ] 在 VM A 上转发 `8080 → VM B:80` (HTTP 容器),从第三台主机访问 `A:8080` 能正常看到 B 的页面
- [ ] 重启 VM A规则依然有效
- [ ] 删除规则后访问 `A:8080` 失败
- [ ] 列表中的健康列能正确反映 iptables 与 db 的同步状态
- [ ] 中文显示无乱码、盒线对齐
- [ ] 非 root 启动得到明确提示
---
## 7. 阶段化实施计划 (按轮次排队)
> 每阶段完成后应处于**可独立运行**的状态。阶段之间可以分轮次交给 CodexPotter / Claude Code 执行。
### 阶段 1 · 骨架 + 环境检查
**入口提示词**
> 依据 `plan_iptables_forward.md` 第 3、4.1、4.2、4.7 节实现:
> - 目录结构与空文件骨架
> - `lib/common.sh` 的颜色/盒线/prompt/validate_* 全部函数 (无外部依赖)
> - `lib/env_check.sh` 完整环境检测与自动安装
> - `iptables-forward.sh` 的启动流程 (到 `env_check_all` 为止,菜单先打 TODO)
>
> 同步完成 `tests/lib/assert.sh`、`tests/test_common.sh`、`tests/test_env_check.sh`,并确保 `tests/run_all.sh --skip-integration` 全绿。
> 参考规范CLAUDE.md 第 3 节代码治理。
**退出条件**
- `bash iptables-forward.sh` 在缺 iptables 的容器中能列出缺失并询问修复
- 非 root 运行立即退出并提示
- `tests/run_all.sh --skip-integration` 通过
### 阶段 2 · 存储层 + iptables 封装 + 基础 CRUD
**入口提示词**
> 依据 `plan_iptables_forward.md` 第 4.3、4.4、4.5 节实现 `storage.sh`、`iptables_ops.sh`、`rules_mgr.sh` 中的 `cmd_list / cmd_add / cmd_delete`。
> 菜单接入真实实现,暂不接持久化 (`persist_save` 留空)。
> 同步完成 `tests/mocks/iptables-mock.sh`、`tests/test_storage.sh`、`tests/test_rules_unit.sh`。
> 校验:所有 unit 测试通过;手工在 VM 里加一条 tcp/ipv4 规则并验证 `iptables -t nat -L -n` 中出现对应条目。
**退出条件**
- 菜单 1/2/3 可用
- 单元测试覆盖正路径、错误路径、回滚路径
- `iptables -t nat -L -n -v` 能看到带 `MGMT:` 注释的规则
### 阶段 3 · 持久化 + IPv6
**入口提示词**
> 依据 `plan_iptables_forward.md` 第 4.6、2.1 节,完成 `persist.sh` 并接到 `cmd_add/cmd_delete` 末尾。
> 将 `iptables_ops.sh` 对 IPv6 的分支完整打通 (`ip6tables` 二进制、`[..]` 目标写法)。
> 补齐 `tests/test_integration.sh` 的步骤 3、4 (持久化与 IPv6)。
**退出条件**
- `netfilter-persistent save` 被自动触发,`/etc/iptables/rules.v{4,6}` 含 `MGMT:` 注释
- 重启后规则仍有效 (手工验证)
- 集成测试在 root 环境下全绿
### 阶段 4 · UI 美化 + 菜单打磨
**入口提示词**
> 依据 `plan_iptables_forward.md` 第 5 节样例,把所有交互界面按样例输出:
> - 主菜单含状态行 (规则数 / 持久化状态 / 运行时错误指示)
> - 列表渲染成表格,中文对齐考虑宽字符 (汉字占 2 列)
> - 添加表单带「预览」与二次确认
> - 错误提示红色,成功绿色,警告黄色
> 不得改变功能行为,仅改 UI 层;测试仍然全绿。
**退出条件**
- 终端宽度 < 60 时优雅降级 (不渲染盒线,改纯文本)
- 中文与 ASCII 混排对齐 (宽字符计算 via `awk` 或 locale `wc -L`)
### 阶段 5 · 查漏补缺 + 文档
**入口提示词**
> 审阅 `plan_iptables_forward.md` 与当前代码:
> 1. 对照第 1.1 节 Must 列表逐项核对实现与测试
> 2. 列出测试空白并补齐 (尤其回滚、并发、非法输入)
> 3. 更新 `README.md`:安装、运行、故障排查、卸载
> 4. 编写 `install.sh` (link 到 /usr/local/bin/iptables-forward, 不拷贝源码)
> 5. 所有脚本加 `shellcheck` 校验零警告 (对无法避免的使用 `# shellcheck disable=SCxxxx reason=...`)
**退出条件**
- `shellcheck lib/*.sh iptables-forward.sh install.sh` 零警告
- `tests/run_all.sh` 全绿
- README 可指导零知识用户完成安装与使用
### 阶段 6 · 精简 (simplify)
**入口提示词**
> 运行 `/simplify`。重点审查:
> - 冗余的 if 分支、重复的字符串格式化
> - 不必要的 echo → printf 转换
> - 局部工具函数抽取 (如重复的 confirm 弹窗)
> - 移除 over-engineering (回看 CLAUDE.md 3.3)
**退出条件**
- 代码体量明显下降但测试仍全绿
- 保留的每个函数/文件都有明确职责
---
## 8. 风险与回滚
| 风险 | 影响 | 缓解 |
|------|------|------|
| `iptables-nft` vs `iptables-legacy` 并存 | `save/reload` 后端不一致 | 仅用发行版默认,不切换;在 README 声明 |
| `iptables-persistent` 安装时 debconf 交互 | 卡住脚本 | `debconf-set-selections` 预置答案 |
| `sysctl` 修改永久生效导致测试环境污染 | 误改宿主 | 写 drop-in 而非 `/etc/sysctl.conf`;集成测试 teardown 时清理 |
| `ufw`/`firewalld` 存在 | 规则被覆盖 | 启动时检测并打黄色警告,不阻断 |
| 删除时 iptables 与 db 不一致 | 残留/孤儿规则 | `cmd_list` 显示健康列;提供"扫描修复"隐藏命令 (Phase 5 可选) |
| 并发两个脚本实例 | rules.db 竞争 | `flock /var/lib/iptables-forward/.lock` 包裹所有写操作 |
| 用户输入 IPv6 但填入 IPv4 地址 | 规则创建失败 | 校验 IP 族与字符串一致性;不一致直接拒绝 |
---
## 9. 验收标准 (Definition of Done)
1. 清洁 Debian 13 系统上首次运行:检测→自动安装→进入菜单,**全程中文、美观**
2. 能添加 TCP/UDP/both × IPv4/IPv6/both 的任意组合,立即生效
3. 重启系统后规则仍在,列表健康状态为 `[✓]`
4. 删除时只删本脚本加的规则,**绝不误伤外部规则**
5. `tests/run_all.sh` 全绿 (含集成层, root 下)
6. `shellcheck` 零警告
7. README 能指导新手从零开始完成一条转发并验证生效
8. 源码总行数 (不含测试/文档) 控制在 **≤ 1500 行**;超过需说明
---
## 10. 附录
### 10.1 最终生成的 iptables 规则示例 (参考)
对 `uuid=a1b2c3d4, proto=tcp, lport=8080, tip=192.168.1.100, tport=80, ipver=4`:
```bash
iptables -t nat -A PREROUTING -p tcp --dport 8080 \
-j DNAT --to-destination 192.168.1.100:80 \
-m comment --comment "MGMT:a1b2c3d4"
iptables -t nat -A POSTROUTING -p tcp -d 192.168.1.100 --dport 80 \
-j MASQUERADE \
-m comment --comment "MGMT:a1b2c3d4"
iptables -A FORWARD -p tcp -d 192.168.1.100 --dport 80 \
-m conntrack --ctstate NEW,ESTABLISHED,RELATED \
-j ACCEPT \
-m comment --comment "MGMT:a1b2c3d4"
iptables -A FORWARD -p tcp -s 192.168.1.100 --sport 80 \
-m conntrack --ctstate ESTABLISHED,RELATED \
-j ACCEPT \
-m comment --comment "MGMT:a1b2c3d4"
```
### 10.2 卸载指引
```bash
# 删除所有本脚本规则
sudo iptables-save | grep -v 'MGMT:' | sudo iptables-restore
sudo ip6tables-save | grep -v 'MGMT:' | sudo ip6tables-restore
sudo netfilter-persistent save
# 清理状态
sudo rm -rf /var/lib/iptables-forward
sudo rm -f /etc/sysctl.d/99-iptables-forward.conf
sudo rm -f /usr/local/bin/iptables-forward
# 可选:卸载包
sudo apt-get remove --purge iptables-persistent
```
### 10.3 参考资料
- Debian iptables-persistent 1.0.23 源 [apt-cache show, 2026-04-17]
- Linux netfilter DNAT/MASQUERADE 最佳实践 [external search, 2026-04-17]
- CLAUDE.md 全局协议 (本项目 3.1/3.3/3.6 约束)