## 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

  ## 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 -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
  sudo systemd-analyze verify /etc/systemd/system/proxy.service

  ## 6. 加载并启动服务

  > 执行后会立即接管本机 TCP 流量。                                                                                                    

  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. 验证部署结果

  检查 redsocks 和规则:

  sudo /opt/netproxy/netproxy.sh status

  检查监听端口:

  sudo ss -ltnp 'sport = :12345'

  预期监听:

  127.0.0.1:12345

  检查完整规则顺序:

  sudo iptables -t nat -S OUTPUT
  sudo iptables -t nat -S NETPROXY
  sudo iptables -t mangle -S OUTPUT

  查看运行日志:

  sudo journalctl -u proxy.service -n 100 --no-pager

  持续观察:

  sudo journalctl -u proxy.service -f

  进行 TCP 测试:

  curl --connect-timeout 5 --max-time 15 -I https://example.com

  注意:UDP、IPv6、ICMP 和经过本机转发的流量不会被该方案代理。

  ## 8. 修改上游代理

  编辑服务文件:

  sudoedit /etc/systemd/system/proxy.service

  修改:

  ExecStart=/opt/netproxy/netproxy.sh start 10.8.30.135:10810

  然后重新加载并重启:

  sudo systemctl daemon-reload
  sudo systemctl restart proxy.service
  sudo /opt/netproxy/netproxy.sh status

  ## 9. 停止与取消开机启动

  sudo systemctl disable --now proxy.service

  确认规则已清理或恢复:

  sudo iptables -t nat -S | grep NETPROXY || true
  sudo iptables -t mangle -S | grep 12345 || true
  pgrep -a -x redsocks || true

  需要注意:这个部署版本停止时会恢复启动前保存的整份 iptables 快照。如果服务运行期间其他程序修改过防火墙,停止服务可能覆盖那些修改。生
  产环境建议后续改成“只删除 NETPROXY 自己的规则”,避免全量恢复。