Redsocks:修订间差异

来自MediaWiki
跳转到导航 跳转到搜索
Admin​(留言 | 贡献)
创建页面,内容为“<syntaxhighlight lang="bash" line="1"> #!/usr/bin/env bash set -euo pipefail ### ================= 基本配置 ================= REDSOCKS_CONF="/etc/redsocks.conf" REDSOCKS_BIN="/usr/sbin/redsocks" # 源码版可能是 /usr/local/bin/redsocks REDSOCKS_PORT=12345 CHAIN="NETPROXY" MARK="0x1" STATE_DIR="/run/netproxy" IPTABLES_BACKUP="$STATE_DIR/iptables.bak" ### ================= 工具函数 ================= die() { echo "[ERROR] $*" >&2 exit 1…”
 
Admin​(留言 | 贡献)
无编辑摘要
标签:2017年版源代码编辑
第1行: 第1行:
<syntaxhighlight lang="bash" line="1">
= Redsocks 透明代理安装配置 =
#!/usr/bin/env bash
set -euo pipefail


### ================= 基本配置 =================
  == 概述 ==
REDSOCKS_CONF="/etc/redsocks.conf"
REDSOCKS_BIN="/usr/sbin/redsocks"    # 源码版可能是 /usr/local/bin/redsocks
REDSOCKS_PORT=12345


CHAIN="NETPROXY"
  本文用于在麒麟、Ubuntu 或 Debian 系统上部署基于 '''systemd + redsocks + iptables''' 的透明 TCP 代理。
MARK="0x1"


STATE_DIR="/run/netproxy"
  流量路径如下:
IPTABLES_BACKUP="$STATE_DIR/iptables.bak"


### ================= 工具函数 =================
  <pre>
die() {
  本机 TCP 流量
      │
      ▼
  iptables OUTPUT
      │
      ▼
  NETPROXY
      │
      ▼
  redsocks 127.0.0.1:12345
      │
      ▼
  SOCKS5 10.8.30.135:10810
      │
      ▼
  目标服务器
  </pre>
 
  '''警告:'''启用服务后会接管本机几乎全部 IPv4 TCP 流量。若通过 SSH 远程操作,可能导致 SSH 连接中断。建议通过本地终端执行,或者提前配
  置管理网段放行规则。
 
  == 部署参数 ==
 
  {| class="wikitable"
  ! 配置项
  ! 配置值
  |-
  | 上游代理类型
  | SOCKS5
  |-
  | 上游代理地址
  | <code>10.8.30.135:10810</code>
  |-
  | redsocks 本地地址
  | <code>127.0.0.1:12345</code>
  |-
  | iptables 链
  | <code>NETPROXY</code>
  |-
  | systemd 服务
  | <code>proxy.service</code>
  |-
  | 管理脚本
  | <code>/opt/netproxy/netproxy.sh</code>
  |-
  | redsocks 配置
  | <code>/etc/redsocks.conf</code>
  |-
  | 防火墙备份
  | <code>/run/netproxy/iptables.bak</code>
  |}
 
  == 1. 检查上游 SOCKS5 ==
 
  先检查到上游代理的路由:
 
  <pre>
  ip route get 10.8.30.135
  </pre>
 
  通过上游 SOCKS5 代理执行一次访问测试:
 
  <pre>
  curl \
    --socks5-hostname 10.8.30.135:10810 \
    --connect-timeout 5 \
    --max-time 15 \
    -I https://example.com
  </pre>
 
  如果测试失败,不要继续启用透明代理。应先检查:
 
  * 上游代理地址和端口是否正确。
  * 本机到 <code>10.8.30.135</code> 的网络是否可达。
  * 防火墙是否允许访问 TCP 端口 <code>10810</code>。
  * 上游服务是否确实为 SOCKS5 服务。
 
  == 2. 安装依赖 ==
 
  <pre>
  sudo apt-get update
  sudo apt-get install -y redsocks iptables
  </pre>
 
  检查安装结果:
 
  <pre>
  /usr/sbin/redsocks -v
  iptables --version
  </pre>
 
  系统软件包自带一个 <code>redsocks.service</code>。自定义服务不能与它同时管理 redsocks,因此需要禁用:
 
  <pre>
  sudo systemctl disable --now redsocks.service
  </pre>
 
  确认系统服务状态:
 
  <pre>
  systemctl status redsocks.service --no-pager
  </pre>
 
  预期状态为:
 
  <pre>
  inactive (dead)
  </pre>
 
  == 3. 创建代理管理脚本 ==
 
  创建程序目录:
 
  <pre>
  sudo install -d -o root -g root -m 0755 /opt/netproxy
  </pre>
 
  编辑管理脚本:
 
  <pre>
  sudoedit /opt/netproxy/netproxy.sh
  </pre>
 
  写入以下完整内容:
 
  <pre>
  #!/usr/bin/env bash
  set -euo pipefail
 
  ### ================= 基本配置 =================
 
  REDSOCKS_CONF="/etc/redsocks.conf"
  REDSOCKS_BIN="/usr/sbin/redsocks"
  REDSOCKS_PORT=12345
 
  CHAIN="NETPROXY"
  MARK="0x1"
 
  STATE_DIR="/run/netproxy"
  IPTABLES_BACKUP="${STATE_DIR}/iptables.bak"
 
  ### ================= 工具函数 =================
 
  die() {
     echo "[ERROR] $*" >&2
     echo "[ERROR] $*" >&2
     exit 1
     exit 1
}
  }
 
  need_root() {
    [[ ${EUID} -eq 0 ]] || die "Must run as root"
  }


need_root() {
  ensure_dependencies() {
     [[ $EUID -eq 0 ]] || die "Must run as root"
     [[ -x "${REDSOCKS_BIN}" ]] ||
}
      die "redsocks not found: ${REDSOCKS_BIN}"


ensure_dirs() {
    command -v iptables >/dev/null ||
     mkdir -p "$STATE_DIR"
      die "iptables not found"
}
 
    command -v iptables-save >/dev/null ||
      die "iptables-save not found"
 
    command -v iptables-restore >/dev/null ||
      die "iptables-restore not found"
  }
 
  ensure_dirs() {
     install -d -o root -g root -m 0755 "${STATE_DIR}"
  }
 
  parse_proxy() {
    [[ $# -eq 1 ]] || die "Missing proxy address"
 
    [[ "$1" =~ ^([^:]+):([0-9]+)$ ]] ||
      die "Invalid proxy format, expected ip:port"


parse_proxy() {
    [[ "$1" =~ ^([^:]+):([0-9]+)$ ]] || die "Invalid proxy format: ip:port"
     PROXY_IP="${BASH_REMATCH[1]}"
     PROXY_IP="${BASH_REMATCH[1]}"
     PROXY_PORT="${BASH_REMATCH[2]}"
     PROXY_PORT="${BASH_REMATCH[2]}"
}


### ================= redsocks =================
    if ((PROXY_PORT < 1 || PROXY_PORT > 65535)); then
write_redsocks_conf() {
      die "Invalid proxy port: ${PROXY_PORT}"
    cat > "$REDSOCKS_CONF" <<EOF
     fi
base {
  }
    log_info = on;
    log = "syslog:daemon";
    daemon = on;
     redirector = iptables;
}


redsocks {
  ### ================= redsocks =================
    local_ip = 127.0.0.1;
    local_port = $REDSOCKS_PORT;
    ip = $PROXY_IP;
    port = $PROXY_PORT;
    type = socks5;
}
EOF
}


start_redsocks() {
  write_redsocks_conf() {
     pkill redsocks 2>/dev/null || true
     cat >"${REDSOCKS_CONF}" &lt;&lt;EOF
    "$REDSOCKS_BIN" -c "$REDSOCKS_CONF"
  base {
}
      log_info = on;
      log = "syslog:daemon";
      daemon = on;
      redirector = iptables;
  }


stop_redsocks() {
  redsocks {
    pkill redsocks 2>/dev/null || true
      local_ip = 127.0.0.1;
}
      local_port = ${REDSOCKS_PORT};
      ip = ${PROXY_IP};
      port = ${PROXY_PORT};
      type = socks5;
  }
  EOF


### ================= iptables =================
     chmod 0644 "${REDSOCKS_CONF}"
iptables_save() {
  }
     iptables-save > "$IPTABLES_BACKUP"
}


iptables_restore() {
  start_redsocks() {
     [[ -f "$IPTABLES_BACKUP" ]] && iptables-restore < "$IPTABLES_BACKUP"
     # 本服务独占 redsocks,避免系统自带实例产生冲突。
}
    pkill -x redsocks 2>/dev/null || true


iptables_apply() {
    "${REDSOCKS_BIN}" -t -c "${REDSOCKS_CONF}"
    # nat 链
     "${REDSOCKS_BIN}" -c "${REDSOCKS_CONF}"
    iptables -t nat -N $CHAIN 2>/dev/null || true
  }
     iptables -t nat -F $CHAIN


    # 已标记流量直接放行(防回环)
  stop_redsocks() {
     iptables -t nat -A $CHAIN -m mark --mark $MARK -j RETURN
     pkill -x redsocks 2>/dev/null || true
  }


    # 本地 & 私网放行
  ### ================= iptables =================
    iptables -t nat -A $CHAIN -d 127.0.0.0/8 -j RETURN


    # 排除代理服务器自身(关键)
  iptables_save() {
     iptables -t nat -A $CHAIN -d "$PROXY_IP" -j RETURN
     iptables-save >"${IPTABLES_BACKUP}"
    chmod 0600 "${IPTABLES_BACKUP}"
  }


     # TCP 全部重定向
  iptables_restore() {
     iptables -t nat -A $CHAIN -p tcp -j REDIRECT --to-ports $REDSOCKS_PORT
     [[ -f "${IPTABLES_BACKUP}" ]] || return 1
     iptables-restore &lt;"${IPTABLES_BACKUP}"
  }


    # 挂载到 OUTPUT(只影响本机)
  iptables_apply() {
     iptables -t nat -C OUTPUT -p tcp -j $CHAIN 2>/dev/null || \
     iptables -t nat -N "${CHAIN}" 2>/dev/null || true
        iptables -t nat -A OUTPUT -p tcp -j $CHAIN
    iptables -t nat -F "${CHAIN}"


     # mangle:给 redsocks 出口流量打标记
     # 放行已标记的 redsocks 返回流量,避免循环代理。
     iptables -t mangle -C OUTPUT -p tcp --sport $REDSOCKS_PORT -j MARK --set-mark $MARK 2>/dev/null || \
     iptables -t nat -A "${CHAIN}" \
        iptables -t mangle -A OUTPUT -p tcp --sport $REDSOCKS_PORT -j MARK --set-mark $MARK
      -m mark --mark "${MARK}" -j RETURN
}


iptables_clear() {
    # 回环流量不代理。
     iptables -t nat -D OUTPUT -p tcp -j $CHAIN 2>/dev/null || true
     iptables -t nat -A "${CHAIN}" \
    iptables -t nat -F $CHAIN 2>/dev/null || true
      -d 127.0.0.0/8 -j RETURN
    iptables -t nat -X $CHAIN 2>/dev/null || true


     iptables -t mangle -D OUTPUT -p tcp --sport $REDSOCKS_PORT -j MARK --set-mark $MARK 2>/dev/null || true
    # 上游 SOCKS5 服务器必须直连,避免代理回环。
}
     iptables -t nat -A "${CHAIN}" \
      -d "${PROXY_IP}" -j RETURN


### ================= 命令实现 =================
    # 其余本机 IPv4 TCP 流量重定向到 redsocks。
cmd_start() {
    iptables -t nat -A "${CHAIN}" \
      -p tcp -j REDIRECT --to-ports "${REDSOCKS_PORT}"
 
    # 只处理本机产生的连接,不处理转发流量。
    iptables -t nat -C OUTPUT \
      -p tcp -j "${CHAIN}" 2>/dev/null ||
      iptables -t nat -A OUTPUT \
        -p tcp -j "${CHAIN}"
 
    # 标记 redsocks 本地返回流量。
    iptables -t mangle -C OUTPUT \
      -p tcp --sport "${REDSOCKS_PORT}" \
      -j MARK --set-mark "${MARK}" 2>/dev/null ||
      iptables -t mangle -A OUTPUT \
        -p tcp --sport "${REDSOCKS_PORT}" \
        -j MARK --set-mark "${MARK}"
  }
 
  iptables_clear() {
    iptables -t nat -D OUTPUT \
      -p tcp -j "${CHAIN}" 2>/dev/null || true
 
    iptables -t nat -F "${CHAIN}" 2>/dev/null || true
    iptables -t nat -X "${CHAIN}" 2>/dev/null || true
 
    iptables -t mangle -D OUTPUT \
      -p tcp --sport "${REDSOCKS_PORT}" \
      -j MARK --set-mark "${MARK}" 2>/dev/null || true
  }
 
  ### ================= 命令实现 =================
 
  cmd_start() {
     parse_proxy "$1"
     parse_proxy "$1"
    ensure_dependencies
     ensure_dirs
     ensure_dirs
     iptables_save
     iptables_save
     write_redsocks_conf
     write_redsocks_conf
     start_redsocks
     start_redsocks
    iptables_apply
    echo "[OK] netproxy started via $PROXY_IP:$PROXY_PORT"
}


cmd_stop() {
    if ! iptables_apply; then
      stop_redsocks
      iptables_restore || iptables_clear
      die "Failed to apply iptables rules"
    fi
 
    echo "[OK] netproxy started via ${PROXY_IP}:${PROXY_PORT}"
  }
 
  cmd_stop() {
     stop_redsocks
     stop_redsocks
    iptables_restore || iptables_clear
    rm -rf "$STATE_DIR"
    echo "[OK] netproxy stopped and restored"
}


cmd_status() {
    if ! iptables_restore; then
      iptables_clear
    fi
 
    rm -f "${IPTABLES_BACKUP}"
    rmdir "${STATE_DIR}" 2>/dev/null || true
 
    echo "[OK] netproxy stopped and firewall restored"
  }
 
  cmd_status() {
     echo "=== redsocks ==="
     echo "=== redsocks ==="
     pgrep redsocks >/dev/null && echo "running" || echo "stopped"
     if pgrep -x redsocks >/dev/null; then
      echo "running"
      pgrep -a -x redsocks
    else
      echo "stopped"
    fi
 
    echo
    echo "=== listen port ==="
    ss -ltn | grep ":${REDSOCKS_PORT} " ||
      echo "port ${REDSOCKS_PORT} not listening"


     echo
     echo
     echo "=== iptables nat ==="
     echo "=== iptables nat ==="
     iptables -t nat -S | grep "$CHAIN" || echo "no netproxy nat rules"
     iptables -t nat -S | grep "${CHAIN}" ||
      echo "no netproxy nat rules"


     echo
     echo
     echo "=== iptables mangle ==="
     echo "=== iptables mangle ==="
     iptables -t mangle -S | grep "$REDSOCKS_PORT" || echo "no netproxy mangle rules"
     iptables -t mangle -S |
}
      grep -- "--sport ${REDSOCKS_PORT}" ||
      echo "no netproxy mangle rules"
  }


### ================= 主入口 =================
  ### ================= 主入口 =================
need_root


case "${1:-}" in
  need_root
 
  case "${1:-}" in
     start)
     start)
        [[ $# -eq 2 ]] || die "Usage: $0 start ip:port"
      [[ $# -eq 2 ]] ||
        cmd_start "$2"
        die "Usage: $0 start ip:port"
        ;;
      cmd_start "$2"
      ;;
     stop)
     stop)
         cmd_stop
      [[ $# -eq 1 ]] ||
        ;;
         die "Usage: $0 stop"
      cmd_stop
      ;;
     status)
     status)
         cmd_status
      [[ $# -eq 1 ]] ||
        ;;
         die "Usage: $0 status"
      cmd_status
      ;;
     *)
     *)
        echo "Usage:"
      echo "Usage:"
        echo "  $0 start ip:port"
      echo "  $0 start ip:port"
        echo "  $0 stop"
      echo "  $0 stop"
        echo "  $0 status"
      echo "  $0 status"
        exit 1
      exit 1
        ;;
      ;;
esac
  esac
  </pre>
 
  设置文件权限:
 
  <pre>
  sudo chown root:root /opt/netproxy/netproxy.sh
  sudo chmod 0755 /opt/netproxy/netproxy.sh
  </pre>
 
  检查 Bash 语法:
 
  <pre>
  bash -n /opt/netproxy/netproxy.sh
  </pre>
 
  命令没有输出即表示语法检查通过。
 
  == 4. 可选:配置直连网段 ==
 
  当前脚本除回环地址和上游代理外,会代理所有本机 IPv4 TCP 流量,包括内网地址。
 
  如果需要保持管理网段直连,在 <code>iptables_apply()</code> 函数中、“上游 SOCKS5 服务器必须直连”规则之后加入:
 
  <pre>
  iptables -t nat -A "${CHAIN}" \
    -d 192.168.220.0/24 -j RETURN
  </pre>
 
  也可以根据实际环境放行常见私有网段:
 
  <pre>
  iptables -t nat -A "${CHAIN}" -d 10.0.0.0/8 -j RETURN
  iptables -t nat -A "${CHAIN}" -d 172.16.0.0/12 -j RETURN
  iptables -t nat -A "${CHAIN}" -d 192.168.0.0/16 -j RETURN
  </pre>
 
  如果内网业务本来就需要通过 SOCKS5 代理访问,则不要添加对应的放行规则。
 
  == 5. 创建 systemd 服务 ==
 
  编辑服务文件:
 
  <pre>
  sudoedit /etc/systemd/system/proxy.service
  </pre>
 
  写入以下内容:
 
  <pre>
  [Unit]
  Description=Proxy Service (Redsocks)
  Wants=network-online.target
  After=network-online.target
  Conflicts=redsocks.service
 
  [Service]
  Type=forking
  ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.135:10810
  ExecStop=/opt/netproxy/netproxy.sh stop
  Restart=on-failure
  RestartSec=5s
  TimeoutStartSec=30s
  TimeoutStopSec=30s
 
  [Install]
  WantedBy=multi-user.target
  </pre>
 
  设置文件权限:
 
  <pre>
  sudo chown root:root /etc/systemd/system/proxy.service
  sudo chmod 0644 /etc/systemd/system/proxy.service
  </pre>
 
  检查 systemd 配置:
 
  <pre>
  sudo systemd-analyze verify /etc/systemd/system/proxy.service
  </pre>
 
  == 6. 加载并启动服务 ==
 
  '''警告:'''执行以下命令后会立即接管本机 IPv4 TCP 流量。
 
  重新加载 systemd:
 
  <pre>
  sudo systemctl daemon-reload
  </pre>
 
  设置开机启动并立即启动服务:
 
  <pre>
  sudo systemctl enable --now proxy.service
  </pre>
 
  检查服务状态:
 
  <pre>
  systemctl is-enabled proxy.service
  systemctl is-active proxy.service
  systemctl status proxy.service --no-pager
  </pre>
 
  预期结果:
 
  <pre>
  enabled
  active
  </pre>
 
  == 7. 验证部署结果 ==
 
  === 7.1 检查 redsocks 和 iptables ===
 
  <pre>
  sudo /opt/netproxy/netproxy.sh status
  </pre>
 
  预期输出类似:
 
  <pre>
  === redsocks ===
  running
 
  === listen port ===
  LISTEN ... 127.0.0.1:12345 ...
 
  === iptables nat ===
  -N NETPROXY
  -A OUTPUT -p tcp -j NETPROXY
  -A NETPROXY -m mark --mark 0x1 -j RETURN
  -A NETPROXY -d 127.0.0.0/8 -j RETURN
  -A NETPROXY -d 10.8.30.135/32 -j RETURN
  -A NETPROXY -p tcp -j REDIRECT --to-ports 12345
 
  === iptables mangle ===
  -A OUTPUT -p tcp -m tcp --sport 12345 -j MARK --set-xmark 0x1/0xffffffff
  </pre>
 
  === 7.2 检查监听端口 ===
 
  <pre>
  sudo ss -ltnp 'sport = :12345'
  </pre>
 
  预期监听地址:
 
  <pre>
  127.0.0.1:12345
  </pre>
 
  === 7.3 检查完整规则顺序 ===
 
  <pre>
  sudo iptables -t nat -S OUTPUT
  sudo iptables -t nat -S NETPROXY
  sudo iptables -t mangle -S OUTPUT
  </pre>
 
  如果本机还部署了其他透明代理,例如 <code>SSLPROXY</code>,应特别检查不同代理链在 <code>OUTPUT</code> 中的顺序。
 
  === 7.4 查看日志 ===
 
  查看最近100条日志:
 
  <pre>
  sudo journalctl -u proxy.service -n 100 --no-pager
  </pre>
 
  持续观察日志:
 
  <pre>
  sudo journalctl -u proxy.service -f
  </pre>
 
  === 7.5 测试 TCP 访问 ===
 
  <pre>
  curl --connect-timeout 5 --max-time 15 -I https://example.com
  </pre>
 
  能够正常返回 HTTP 响应头,且 redsocks 日志中出现对应连接,说明透明代理工作正常。
 
  == 8. 修改上游代理 ==
 
  编辑服务文件:
 
  <pre>
  sudoedit /etc/systemd/system/proxy.service
  </pre>
 
  修改以下配置:
 
  <pre>
  ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.135:10810
  </pre>
 
  例如,将上游代理修改为 <code>10.8.30.136:10811</code>:
 
  <pre>
  ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.136:10811
  </pre>
 
  重新加载配置并重启:
 
  <pre>
  sudo systemctl daemon-reload
  sudo systemctl restart proxy.service
  sudo /opt/netproxy/netproxy.sh status
  </pre>
 
  == 9. 停止服务 ==
 
  停止服务:
 
  <pre>
  sudo systemctl stop proxy.service
  </pre>
 
  停止后检查:
 
  <pre>
  sudo /opt/netproxy/netproxy.sh status
  </pre>
 
  == 10. 取消开机启动 ==
 
  <pre>
  sudo systemctl disable --now proxy.service
  </pre>
 
  确认 NETPROXY 规则已清理:
 
  <pre>
  sudo iptables -t nat -S | grep NETPROXY || true
  sudo iptables -t mangle -S | grep 12345 || true
  pgrep -a -x redsocks || true
  </pre>
 
  == 11. 卸载自定义代理 ==
 
  先停止并禁用服务:
 
  <pre>
  sudo systemctl disable --now proxy.service
  </pre>
 
  删除 systemd 服务和管理脚本:
 
  <pre>
  sudo rm /etc/systemd/system/proxy.service
  sudo rm /opt/netproxy/netproxy.sh
  sudo rmdir /opt/netproxy
  sudo systemctl daemon-reload
  sudo systemctl reset-failed
  </pre>
 
  如果需要恢复系统自带的 redsocks 服务:
 
  <pre>
  sudo systemctl enable --now redsocks.service
  </pre>
 
  == 注意事项 ==


</syntaxhighlight>
  * 该方案只代理本机产生的 IPv4 TCP 流量。
  * UDP、ICMP、IPv6 和转发流量不会经过该代理。
  * DNS 使用 UDP 时仍会直接访问 DNS 服务器。
  * QUIC、HTTP/3 等 UDP 协议不会经过 redsocks。
  * <code>pkill -x redsocks</code> 会停止系统中所有名为 redsocks 的进程。
  * 系统自带的 <code>redsocks.service</code> 应保持禁用,避免双实例冲突。
  * 上游 SOCKS5 地址必须在 <code>NETPROXY</code> 中直接放行,否则会形成代理回环。
  * 如果通过 SSH 部署,应提前放行管理地址或管理网段。
  * 当前停止逻辑会恢复启动前保存的整份 iptables 快照。
  * 如果服务运行期间其他程序修改了防火墙,停止服务可能覆盖这些修改。
  * 生产环境建议只清理 <code>NETPROXY</code> 自己创建的规则,避免全量恢复 iptables。
  * 不要混用 <code>iptables</code> 和 <code>iptables-legacy</code>,应确认其他安全软件使用的防火墙后端。

2026年8月12日 (三) 03:28的版本

Redsocks 透明代理安装配置

 == 概述 ==
 本文用于在麒麟、Ubuntu 或 Debian 系统上部署基于 systemd + redsocks + iptables 的透明 TCP 代理。
 流量路径如下:
  本机 TCP 流量
      │
      ▼
  iptables OUTPUT
      │
      ▼
  NETPROXY
      │
      ▼
  redsocks 127.0.0.1:12345
      │
      ▼
  SOCKS5 10.8.30.135:10810
      │
      ▼
  目标服务器
  
 警告:启用服务后会接管本机几乎全部 IPv4 TCP 流量。若通过 SSH 远程操作,可能导致 SSH 连接中断。建议通过本地终端执行,或者提前配
 置管理网段放行规则。
 == 部署参数 ==
配置项 配置值
上游代理类型 SOCKS5
上游代理地址 10.8.30.135:10810
redsocks 本地地址 127.0.0.1:12345
iptables 链 NETPROXY
systemd 服务 proxy.service
管理脚本 /opt/netproxy/netproxy.sh
redsocks 配置 /etc/redsocks.conf
防火墙备份 /run/netproxy/iptables.bak
 == 1. 检查上游 SOCKS5 ==
 先检查到上游代理的路由:
  ip route get 10.8.30.135
  
 通过上游 SOCKS5 代理执行一次访问测试:
  curl \
    --socks5-hostname 10.8.30.135:10810 \
    --connect-timeout 5 \
    --max-time 15 \
    -I https://example.com
  
 如果测试失败,不要继续启用透明代理。应先检查:
 * 上游代理地址和端口是否正确。
 * 本机到 10.8.30.135 的网络是否可达。
 * 防火墙是否允许访问 TCP 端口 10810。
 * 上游服务是否确实为 SOCKS5 服务。
 == 2. 安装依赖 ==
  sudo apt-get update
  sudo apt-get install -y redsocks iptables
  
 检查安装结果:
  /usr/sbin/redsocks -v
  iptables --version
  
 系统软件包自带一个 redsocks.service。自定义服务不能与它同时管理 redsocks,因此需要禁用:
  sudo systemctl disable --now redsocks.service
  
 确认系统服务状态:
  systemctl status redsocks.service --no-pager
  
 预期状态为:
  inactive (dead)
  
 == 3. 创建代理管理脚本 ==
 创建程序目录:
  sudo install -d -o root -g root -m 0755 /opt/netproxy
  
 编辑管理脚本:
  sudoedit /opt/netproxy/netproxy.sh
  
 写入以下完整内容:
  #!/usr/bin/env bash
  set -euo pipefail

  ### ================= 基本配置 =================

  REDSOCKS_CONF="/etc/redsocks.conf"
  REDSOCKS_BIN="/usr/sbin/redsocks"
  REDSOCKS_PORT=12345

  CHAIN="NETPROXY"
  MARK="0x1"

  STATE_DIR="/run/netproxy"
  IPTABLES_BACKUP="${STATE_DIR}/iptables.bak"

  ### ================= 工具函数 =================

  die() {
    echo "[ERROR] $*" >&2
    exit 1
  }

  need_root() {
    [[ ${EUID} -eq 0 ]] || die "Must run as root"
  }

  ensure_dependencies() {
    [[ -x "${REDSOCKS_BIN}" ]] ||
      die "redsocks not found: ${REDSOCKS_BIN}"

    command -v iptables >/dev/null ||
      die "iptables not found"

    command -v iptables-save >/dev/null ||
      die "iptables-save not found"

    command -v iptables-restore >/dev/null ||
      die "iptables-restore not found"
  }

  ensure_dirs() {
    install -d -o root -g root -m 0755 "${STATE_DIR}"
  }

  parse_proxy() {
    [[ $# -eq 1 ]] || die "Missing proxy address"

    [[ "$1" =~ ^([^:]+):([0-9]+)$ ]] ||
      die "Invalid proxy format, expected ip:port"

    PROXY_IP="${BASH_REMATCH[1]}"
    PROXY_PORT="${BASH_REMATCH[2]}"

    if ((PROXY_PORT < 1 || PROXY_PORT > 65535)); then
      die "Invalid proxy port: ${PROXY_PORT}"
    fi
  }

  ### ================= redsocks =================

  write_redsocks_conf() {
    cat >"${REDSOCKS_CONF}" <<EOF
  base {
      log_info = on;
      log = "syslog:daemon";
      daemon = on;
      redirector = iptables;
  }

  redsocks {
      local_ip = 127.0.0.1;
      local_port = ${REDSOCKS_PORT};
      ip = ${PROXY_IP};
      port = ${PROXY_PORT};
      type = socks5;
  }
  EOF

    chmod 0644 "${REDSOCKS_CONF}"
  }

  start_redsocks() {
    # 本服务独占 redsocks,避免系统自带实例产生冲突。
    pkill -x redsocks 2>/dev/null || true

    "${REDSOCKS_BIN}" -t -c "${REDSOCKS_CONF}"
    "${REDSOCKS_BIN}" -c "${REDSOCKS_CONF}"
  }

  stop_redsocks() {
    pkill -x redsocks 2>/dev/null || true
  }

  ### ================= iptables =================

  iptables_save() {
    iptables-save >"${IPTABLES_BACKUP}"
    chmod 0600 "${IPTABLES_BACKUP}"
  }

  iptables_restore() {
    [[ -f "${IPTABLES_BACKUP}" ]] || return 1
    iptables-restore <"${IPTABLES_BACKUP}"
  }

  iptables_apply() {
    iptables -t nat -N "${CHAIN}" 2>/dev/null || true
    iptables -t nat -F "${CHAIN}"

    # 放行已标记的 redsocks 返回流量,避免循环代理。
    iptables -t nat -A "${CHAIN}" \
      -m mark --mark "${MARK}" -j RETURN

    # 回环流量不代理。
    iptables -t nat -A "${CHAIN}" \
      -d 127.0.0.0/8 -j RETURN

    # 上游 SOCKS5 服务器必须直连,避免代理回环。
    iptables -t nat -A "${CHAIN}" \
      -d "${PROXY_IP}" -j RETURN

    # 其余本机 IPv4 TCP 流量重定向到 redsocks。
    iptables -t nat -A "${CHAIN}" \
      -p tcp -j REDIRECT --to-ports "${REDSOCKS_PORT}"

    # 只处理本机产生的连接,不处理转发流量。
    iptables -t nat -C OUTPUT \
      -p tcp -j "${CHAIN}" 2>/dev/null ||
      iptables -t nat -A OUTPUT \
        -p tcp -j "${CHAIN}"

    # 标记 redsocks 本地返回流量。
    iptables -t mangle -C OUTPUT \
      -p tcp --sport "${REDSOCKS_PORT}" \
      -j MARK --set-mark "${MARK}" 2>/dev/null ||
      iptables -t mangle -A OUTPUT \
        -p tcp --sport "${REDSOCKS_PORT}" \
        -j MARK --set-mark "${MARK}"
  }

  iptables_clear() {
    iptables -t nat -D OUTPUT \
      -p tcp -j "${CHAIN}" 2>/dev/null || true

    iptables -t nat -F "${CHAIN}" 2>/dev/null || true
    iptables -t nat -X "${CHAIN}" 2>/dev/null || true

    iptables -t mangle -D OUTPUT \
      -p tcp --sport "${REDSOCKS_PORT}" \
      -j MARK --set-mark "${MARK}" 2>/dev/null || true
  }

  ### ================= 命令实现 =================

  cmd_start() {
    parse_proxy "$1"
    ensure_dependencies
    ensure_dirs

    iptables_save
    write_redsocks_conf
    start_redsocks

    if ! iptables_apply; then
      stop_redsocks
      iptables_restore || iptables_clear
      die "Failed to apply iptables rules"
    fi

    echo "[OK] netproxy started via ${PROXY_IP}:${PROXY_PORT}"
  }

  cmd_stop() {
    stop_redsocks

    if ! iptables_restore; then
      iptables_clear
    fi

    rm -f "${IPTABLES_BACKUP}"
    rmdir "${STATE_DIR}" 2>/dev/null || true

    echo "[OK] netproxy stopped and firewall restored"
  }

  cmd_status() {
    echo "=== redsocks ==="
    if pgrep -x redsocks >/dev/null; then
      echo "running"
      pgrep -a -x redsocks
    else
      echo "stopped"
    fi

    echo
    echo "=== listen port ==="
    ss -ltn | grep ":${REDSOCKS_PORT} " ||
      echo "port ${REDSOCKS_PORT} not listening"

    echo
    echo "=== iptables nat ==="
    iptables -t nat -S | grep "${CHAIN}" ||
      echo "no netproxy nat rules"

    echo
    echo "=== iptables mangle ==="
    iptables -t mangle -S |
      grep -- "--sport ${REDSOCKS_PORT}" ||
      echo "no netproxy mangle rules"
  }

  ### ================= 主入口 =================

  need_root

  case "${1:-}" in
    start)
      [[ $# -eq 2 ]] ||
        die "Usage: $0 start ip:port"
      cmd_start "$2"
      ;;
    stop)
      [[ $# -eq 1 ]] ||
        die "Usage: $0 stop"
      cmd_stop
      ;;
    status)
      [[ $# -eq 1 ]] ||
        die "Usage: $0 status"
      cmd_status
      ;;
    *)
      echo "Usage:"
      echo "  $0 start ip:port"
      echo "  $0 stop"
      echo "  $0 status"
      exit 1
      ;;
  esac
  
 设置文件权限:
  sudo chown root:root /opt/netproxy/netproxy.sh
  sudo chmod 0755 /opt/netproxy/netproxy.sh
  
 检查 Bash 语法:
  bash -n /opt/netproxy/netproxy.sh
  
 命令没有输出即表示语法检查通过。
 == 4. 可选:配置直连网段 ==
 当前脚本除回环地址和上游代理外,会代理所有本机 IPv4 TCP 流量,包括内网地址。
 如果需要保持管理网段直连,在 iptables_apply() 函数中、“上游 SOCKS5 服务器必须直连”规则之后加入:
  iptables -t nat -A "${CHAIN}" \
    -d 192.168.220.0/24 -j RETURN
  
 也可以根据实际环境放行常见私有网段:
  iptables -t nat -A "${CHAIN}" -d 10.0.0.0/8 -j RETURN
  iptables -t nat -A "${CHAIN}" -d 172.16.0.0/12 -j RETURN
  iptables -t nat -A "${CHAIN}" -d 192.168.0.0/16 -j RETURN
  
 如果内网业务本来就需要通过 SOCKS5 代理访问,则不要添加对应的放行规则。
 == 5. 创建 systemd 服务 ==
 编辑服务文件:
  sudoedit /etc/systemd/system/proxy.service
  
 写入以下内容:
  [Unit]
  Description=Proxy Service (Redsocks)
  Wants=network-online.target
  After=network-online.target
  Conflicts=redsocks.service

  [Service]
  Type=forking
  ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.135:10810
  ExecStop=/opt/netproxy/netproxy.sh stop
  Restart=on-failure
  RestartSec=5s
  TimeoutStartSec=30s
  TimeoutStopSec=30s

  [Install]
  WantedBy=multi-user.target
  
 设置文件权限:
  sudo chown root:root /etc/systemd/system/proxy.service
  sudo chmod 0644 /etc/systemd/system/proxy.service
  
 检查 systemd 配置:
  sudo systemd-analyze verify /etc/systemd/system/proxy.service
  
 == 6. 加载并启动服务 ==
 警告:执行以下命令后会立即接管本机 IPv4 TCP 流量。
 重新加载 systemd:
  sudo systemctl daemon-reload
  
 设置开机启动并立即启动服务:
  sudo systemctl enable --now proxy.service
  
 检查服务状态:
  systemctl is-enabled proxy.service
  systemctl is-active proxy.service
  systemctl status proxy.service --no-pager
  
 预期结果:
  enabled
  active
  
 == 7. 验证部署结果 ==
 === 7.1 检查 redsocks 和 iptables ===
  sudo /opt/netproxy/netproxy.sh status
  
 预期输出类似:
  === redsocks ===
  running

  === listen port ===
  LISTEN ... 127.0.0.1:12345 ...

  === iptables nat ===
  -N NETPROXY
  -A OUTPUT -p tcp -j NETPROXY
  -A NETPROXY -m mark --mark 0x1 -j RETURN
  -A NETPROXY -d 127.0.0.0/8 -j RETURN
  -A NETPROXY -d 10.8.30.135/32 -j RETURN
  -A NETPROXY -p tcp -j REDIRECT --to-ports 12345

  === iptables mangle ===
  -A OUTPUT -p tcp -m tcp --sport 12345 -j MARK --set-xmark 0x1/0xffffffff
  
 === 7.2 检查监听端口 ===
  sudo ss -ltnp 'sport = :12345'
  
 预期监听地址:
  127.0.0.1:12345
  
 === 7.3 检查完整规则顺序 ===
  sudo iptables -t nat -S OUTPUT
  sudo iptables -t nat -S NETPROXY
  sudo iptables -t mangle -S OUTPUT
  
 如果本机还部署了其他透明代理,例如 SSLPROXY,应特别检查不同代理链在 OUTPUT 中的顺序。
 === 7.4 查看日志 ===
 查看最近100条日志:
  sudo journalctl -u proxy.service -n 100 --no-pager
  
 持续观察日志:
  sudo journalctl -u proxy.service -f
  
 === 7.5 测试 TCP 访问 ===
  curl --connect-timeout 5 --max-time 15 -I https://example.com
  
 能够正常返回 HTTP 响应头,且 redsocks 日志中出现对应连接,说明透明代理工作正常。
 == 8. 修改上游代理 ==
 编辑服务文件:
  sudoedit /etc/systemd/system/proxy.service
  
 修改以下配置:
  ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.135:10810
  
 例如,将上游代理修改为 10.8.30.136:10811:
  ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.136:10811
  
 重新加载配置并重启:
  sudo systemctl daemon-reload
  sudo systemctl restart proxy.service
  sudo /opt/netproxy/netproxy.sh status
  
 == 9. 停止服务 ==
 停止服务:
  sudo systemctl stop proxy.service
  
 停止后检查:
  sudo /opt/netproxy/netproxy.sh status
  
 == 10. 取消开机启动 ==
  sudo systemctl disable --now proxy.service
  
 确认 NETPROXY 规则已清理:
  sudo iptables -t nat -S | grep NETPROXY || true
  sudo iptables -t mangle -S | grep 12345 || true
  pgrep -a -x redsocks || true
  
 == 11. 卸载自定义代理 ==
 先停止并禁用服务:
  sudo systemctl disable --now proxy.service
  
 删除 systemd 服务和管理脚本:
  sudo rm /etc/systemd/system/proxy.service
  sudo rm /opt/netproxy/netproxy.sh
  sudo rmdir /opt/netproxy
  sudo systemctl daemon-reload
  sudo systemctl reset-failed
  
 如果需要恢复系统自带的 redsocks 服务:
  sudo systemctl enable --now redsocks.service
  
 == 注意事项 ==
 * 该方案只代理本机产生的 IPv4 TCP 流量。
 * UDP、ICMP、IPv6 和转发流量不会经过该代理。
 * DNS 使用 UDP 时仍会直接访问 DNS 服务器。
 * QUIC、HTTP/3 等 UDP 协议不会经过 redsocks。
 * pkill -x redsocks 会停止系统中所有名为 redsocks 的进程。
 * 系统自带的 redsocks.service 应保持禁用,避免双实例冲突。
 * 上游 SOCKS5 地址必须在 NETPROXY 中直接放行,否则会形成代理回环。
 * 如果通过 SSH 部署,应提前放行管理地址或管理网段。
 * 当前停止逻辑会恢复启动前保存的整份 iptables 快照。
 * 如果服务运行期间其他程序修改了防火墙,停止服务可能覆盖这些修改。
 * 生产环境建议只清理 NETPROXY 自己创建的规则,避免全量恢复 iptables。
 * 不要混用 iptables 和 iptables-legacy,应确认其他安全软件使用的防火墙后端。