# 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:"` 标识 | | 存储 | `/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:"` + 精确 `-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

--dport \ -j DNAT --to-destination : \ -m comment --comment "MGMT:" # 2) POSTROUTING MASQUERADE — 返程包伪装源地址 $CMD -t nat -A POSTROUTING -p

-d --dport \ -j MASQUERADE \ -m comment --comment "MGMT:" # 3) FORWARD ACCEPT — 绕过 FORWARD DROP 策略 $CMD -A FORWARD -p

-d --dport \ -m conntrack --ctstate NEW,ESTABLISHED,RELATED \ -j ACCEPT \ -m comment --comment "MGMT:" # 4) FORWARD 回程 ACCEPT — 允许 DNAT/MASQUERADE 后的回包继续转发 $CMD -A FORWARD -p

-s --sport \ -m conntrack --ctstate ESTABLISHED,RELATED \ -j ACCEPT \ -m comment --comment "MGMT:" ``` 其中 `$CMD` 为 `iptables`(v4) 或 `ip6tables`(v6)。`` 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 ` → 0/1 - `validate_ipv6 ` → 0/1 - `validate_port ` → 0/1 (1–65535) - `validate_proto ` → 0/1 (tcp/udp/both) - `validate_ipver ` → 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 "||…"` — 追加一行 - `storage_list` — 输出全部行 - `storage_get ` — 输出指定行,未找到返回 1 - `storage_delete ` — 原子替换 (写入临时文件后 `mv`) - `storage_parse ` — 从行中抽取字段值 ### 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, 需要 root;WSL/容器/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 约束)