diff --git a/README.md b/README.md index 0c8161b..7bf0a3d 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,222 @@ # IPTables-Management -IPTables转发管理脚本 \ No newline at end of file +一个基于 Bash 的中文交互式 IPTables 端口转发管理工具,面向 Debian 12/13。 + +- 启动时自动做环境自检。 +- 仅管理本工具创建的 `MGMT:` 规则。 +- 支持 TCP / UDP / both,支持 IPv4 / IPv6 / both。 +- 支持 `iptables-persistent` / `netfilter-persistent save` 持久化。 +- 附带单元测试与真实 iptables 集成测试。 + +## 目录结构 + +```text +. +├── iptables-forward.sh # 主入口 +├── install.sh # 创建 /usr/local/bin/iptables-forward 符号链接 +├── lib/ # 业务模块 +├── tests/ # 测试与 mock +└── plan_iptables_forward.md # 实施方案 +``` + +## 运行要求 + +- Debian 12/13 +- Bash 4+ +- root 或 sudo +- `iptables` +- `ip6tables` +- `iptables-persistent`(提供 `netfilter-persistent`) + +> 首次运行若缺依赖,脚本会列出缺失项并询问是否自动安装。 + +## 安装 + +### 直接运行 + +```bash +sudo ./iptables-forward.sh +``` + +### 安装到 PATH + +```bash +sudo ./install.sh +sudo iptables-forward +``` + +默认会创建: + +```text +/usr/local/bin/iptables-forward -> /path/to/IPTables-Management/iptables-forward.sh +``` + +## 使用说明 + +### 交互模式 + +```bash +sudo ./iptables-forward.sh +``` + +主菜单提供: + +- 查看所有转发规则 +- 添加新的转发规则 +- 删除现有转发规则 +- 查看系统环境状态 +- 立即保存到磁盘 +- 退出 + +### 批处理模式 + +用于自动化测试或脚本调用: + +```bash +sudo ./iptables-forward.sh --batch add [desc] +sudo ./iptables-forward.sh --batch delete +sudo ./iptables-forward.sh --batch list +sudo ./iptables-forward.sh --batch save +``` + +参数说明: + +- `proto`: `tcp` / `udp` / `both` +- `ipver`: `4` / `6` / `both` +- `target_ip`: + - `ipver=4` 时传单个 IPv4 + - `ipver=6` 时传单个 IPv6 + - `ipver=both` 时传 `IPv4,IPv6`,例如 `127.0.0.1,::1` + +示例: + +```bash +sudo ./iptables-forward.sh --batch add tcp 8080 192.168.1.100 80 4 "web" +sudo ./iptables-forward.sh --batch add both 5353 127.0.0.1,::1 53 both "dns" +``` + +成功时标准输出会返回新规则 UUID。 + +## 存储与持久化 + +规则元数据默认保存在: + +```text +/var/lib/iptables-forward/rules.db +``` + +格式为一行一条: + +```text +uuid=a1b2c3d4|proto=tcp|lport=8080|tip=192.168.1.100|tport=80|ipver=4|desc=web|created=2026-04-17T10:00:00+0800 +``` + +添加/删除规则时会自动调用: + +```bash +netfilter-persistent save +``` + +以便把规则保存到: + +```text +/etc/iptables/rules.v4 +/etc/iptables/rules.v6 +``` + +## 测试 + +### 运行全部测试 + +```bash +tests/run_all.sh +``` + +### 跳过集成测试 + +```bash +tests/run_all.sh --skip-integration +``` + +测试覆盖: + +- `tests/test_common.sh`:输入校验 +- `tests/test_storage.sh`:规则存储 +- `tests/test_env_check.sh`:环境检查与修复 +- `tests/test_rules_unit.sh`:mock iptables 下的增删回滚 +- `tests/test_integration.sh`:真实 iptables 生命周期测试 + +`tests/test_integration.sh` 的执行策略: + +- root 环境下直接执行 +- 非 root 但支持 `unshare -Urn` 时,会进入隔离网络命名空间执行 +- 两者都不满足时会输出 `SKIP` + +## 手工验收建议 + +建议按 `plan_iptables_forward.md` 再做以下实机验证: + +1. 在干净 Debian 12/13 上首次启动,确认自动安装流程可用。 +2. 准备一台实际后端服务主机,验证从第三方主机访问转发端口时流量确实命中目标服务。 +3. 重启系统后确认规则仍存在,且菜单中状态仍为健康。 +4. 删除规则后再次验证外部访问失败。 + +## 故障排查 + +### 1. 提示必须使用 root + +脚本必须以 root 执行: + +```bash +sudo ./iptables-forward.sh +``` + +### 2. 自动安装失败 + +可手动安装依赖后重试: + +```bash +sudo apt-get update +sudo apt-get install -y iptables iptables-persistent +``` + +### 3. 持久化保存失败 + +确认以下命令可执行: + +```bash +command -v netfilter-persistent +sudo netfilter-persistent save +``` + +### 4. 系统使用 nft 后端 + +Debian 12/13 默认常见为 `iptables-nft`。本项目不自动切换到 legacy 后端,而是依赖发行版默认配置。 + +### 5. 其它防火墙工具干扰 + +若系统启用了 `ufw` 或 `firewalld`,可能覆盖或影响转发规则。脚本会给出黄色警告,但不会自动关闭这些服务。 + +## 卸载 + +### 删除 PATH 链接 + +```bash +sudo ./install.sh --uninstall +``` + +### 删除脚本管理的规则与状态 + +```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 +``` + +### 可选:卸载持久化包 + +```bash +sudo apt-get remove --purge iptables-persistent +``` diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..2281a97 --- /dev/null +++ b/install.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +SOURCE_SCRIPT="${SCRIPT_DIR}/iptables-forward.sh" +TARGET_BIN=${INSTALL_TARGET:-/usr/local/bin/iptables-forward} + +usage() { + cat <&2 + exit 2 + fi +} + +install_link() { + [[ -f ${SOURCE_SCRIPT} ]] || { + printf '未找到入口脚本: %s\n' "${SOURCE_SCRIPT}" >&2 + exit 1 + } + mkdir -p "$(dirname -- "${TARGET_BIN}")" + ln -sfn "${SOURCE_SCRIPT}" "${TARGET_BIN}" + chmod 755 "${SOURCE_SCRIPT}" + printf '已创建链接: %s -> %s\n' "${TARGET_BIN}" "${SOURCE_SCRIPT}" +} + +uninstall_link() { + if [[ -L ${TARGET_BIN} || -e ${TARGET_BIN} ]]; then + rm -f "${TARGET_BIN}" + printf '已删除链接: %s\n' "${TARGET_BIN}" + else + printf '未发现已安装链接: %s\n' "${TARGET_BIN}" + fi +} + +main() { + case ${1:-install} in + --help|-h) + usage + ;; + install) + require_root + install_link + ;; + --uninstall|uninstall) + require_root + uninstall_link + ;; + *) + usage >&2 + exit 1 + ;; + esac +} + +main "$@" diff --git a/lib/common.sh b/lib/common.sh index ea80a9e..53bd30b 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -18,18 +18,12 @@ if [[ ${IPF_COLOR_ENABLED} == 1 ]]; then CLR_GREEN=$'\033[32m' CLR_YELLOW=$'\033[33m' CLR_BLUE=$'\033[34m' - CLR_CYAN=$'\033[36m' - CLR_BOLD=$'\033[1m' - CLR_DIM=$'\033[2m' CLR_RESET=$'\033[0m' else CLR_RED='' CLR_GREEN='' CLR_YELLOW='' CLR_BLUE='' - CLR_CYAN='' - CLR_BOLD='' - CLR_DIM='' CLR_RESET='' fi