• 首页
  • 微语
  • 关于
  • 搜索
  • 夜间模式
    ©2025  枕书 Theme by OneBlog
    搜索
    标签
    默认分类

    用 Phantun 给 Hy2 做 FakeTCP 伪装(附一键脚本)

    2025.12.15 / 18 阅读 / 0 评论 / 31137 字
    默认分类

    用 Phantun 给 Hy2 做 FakeTCP 伪装(附一键脚本)

    阅读 18 评论 0 发表于2025.12.15

    这篇简单记一下自己用 Phantun 给 Hy2 做 FakeTCP 伪装的过程,顺便放一个「一键脚本」,后面换机器的时候直接跑脚本即可,不必每次都得翻文档查命令。

    场景大概是:

    • 落地机:Hy2 服务端 + Phantun 服务端
    • 中转机:Phantun 客户端
    • 本地:Hy2 客户端连中转机的 UDP 端口

    一、部署 Phantun 二进制

    这里以 x86_64 + glibc(Debian/Ubuntu) 为例,其他架构/Alpine 自行换对应的 zip 文件名。

    1. 下载到 /usr/local/bin

    cd /usr/local/bin

    2. 从 GitHub Releases 下载

    当前版本示例:v0.8.1,x86\_64 glibc 对应文件名:

    phantun_x86_64-unknown-linux-gnu.zip

    下载:

    wget https://github.com/dndx/phantun/releases/download/v0.8.1/phantun_x86_64-unknown-linux-gnu.zip

    3. 解压 + 加执行权限

    apt install unzip -y        # 如果系统没有 unzip
    unzip phantun_x86_64-unknown-linux-gnu.zip
    chmod +x phantun_server phantun_client

    二、手动伪装 Hy2 的 UDP 流量

    下面先用最基础的方式手动跑一遍(不考虑持久化),方便理解整个链路。

    假设:

    • 落地机已经跑好了 Hy2 服务端:

      • 地址:127.0.0.1
      • 端口:51431
    • 中转机稍后会通过 FakeTCP 连到这个端口。

    2.1 服务端(server)配置

    1)启动 phantun\_server

    在落地机上执行:

    RUST_LOG=info phantun_server --local 51431 --remote 127.0.0.1:51431 &

    含义:

    • --local 51431:对外暴露的 FakeTCP 端口
    • --remote 127.0.0.1:51431:实际丢给 Hy2 的 UDP 端口

    2)开启 IP 转发

    echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf
    sysctl -p /etc/sysctl.conf

    3)确认外网网卡

    ip route
    # 看这一行:
    # default via x.x.x.x dev ens17

    假设外网网卡是 ens17。

    4)DNAT 伪装规则

    把来自外网的 TCP 51431 转到 phantun 的 TUN 对端 192.168.201.2:

    iptables -t nat -A PREROUTING -p tcp -i ens17 --dport 51431 \
      -j DNAT --to-destination 192.168.201.2

    5)放行 Hy2 的 UDP 端口

    iptables -A INPUT -p udp --dport 51431 -j ACCEPT
    netfilter-persistent save   # Debian/Ubuntu 上持久化规则

    2.2 客户端(client,中转机)配置

    假设中转机是 Alpine,外网网卡为 eth0。

    1)开启 IP 转发

    echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
    sysctl -p /etc/sysctl.conf

    2)给 phantun 的 TUN 做 SNAT

    iptables -t nat -A POSTROUTING -o eth0 -s 192.168.200.2 -j MASQUERADE
    192.168.200.2 是 phantun 客户端默认的 TUN IP。

    3)启动 phantun\_client

    RUST_LOG=info \
    /usr/local/bin/phantun_client \
      --local 0.0.0.0:51431 \
      --remote 落地机IP:51431

    到这一步:

    • 本地 Hy2 客户端连:中转机 IP:51431(UDP)
    • 中转机 phantun\_client → 用 FakeTCP 连落地机的 51431
    • 落地机 phantun\_server → 再把流量转给本机 Hy2

    缺点也很明显:没有持久化,重启就没了,命令中断就挂。


    三、一键菜单脚本(支持多客户端实例)

    为了省事,写了一个「phanyun 一键配置脚本」(名字随便,脚本里创建的命令是 phantun):

    • 支持 Debian / Ubuntu / Alpine
    • 自动安装 phantun
    • 自动检测外网网卡
    • 自动开启 IP 转发、检测 /dev/net/tun
    • 服务端菜单:

      • 一键配置/修改服务端
      • 添加伪装端口
      • 删除伪装端口(选择 1,2,3…)
    • 客户端菜单:

      • 配置/修改主通道
      • 添加新的转发实例(本地 UDP ↔ 远程 FakeTCP)
      • 删除转发实例(同样是选择 1,2,3…)
    • 其它:

      • 查看当前配置和 iptables 规则
      • 重启所有 phantun 服务
      • 一键卸载 phantun + 规则 + 服务
      • 自动创建 /usr/local/bin/phantun 快捷命令,以后直接输入 phantun 即可打开菜单

    下面是完整脚本,可以直接保存使用。

    3.1 脚本代码

    #!/bin/sh
    set -e
    
    PHANTUN_VERSION="v0.8.1"
    CONFIG_FILE="/etc/phantun/phantun.conf"
    
    RED="$(printf '\033[31m')"
    GREEN="$(printf '\033[32m')"
    YELLOW="$(printf '\033[33m')"
    BLUE="$(printf '\033[34m')"
    CYAN="$(printf '\033[36m')"
    RESET="$(printf '\033[0m')"
    
    log_info()  { printf "%s[INFO]%s  %s\n"  "$BLUE"  "$RESET" "$*"; }
    log_ok()    { printf "%s[OK]%s    %s\n"  "$GREEN" "$RESET" "$*"; }
    log_warn()  { printf "%s[WARN]%s  %s\n" "$YELLOW" "$RESET" "$*"; }
    log_error() { printf "%s[ERR]%s   %s\n"  "$RED"  "$RESET" "$*" >&2; }
    
    ensure_root() {
      if [ "$(id -u)" != "0" ]; then
        log_error "请用 root 运行此脚本"
        exit 1
      fi
    }
    
    detect_os() {
      if command -v apt >/dev/null 2>&1 && command -v systemctl >/dev/null 2>&1; then
        OS_TYPE="debian"
      elif command -v apk >/dev/null 2>&1 && command -v rc-update >/dev/null 2>&1; then
        OS_TYPE="alpine"
      else
        OS_TYPE="unknown"
      fi
    }
    
    auto_detect_iface() {
      IFACE_DETECTED="$(ip route 2>/dev/null | awk '/default/ {print $5; exit}')"
      if [ -n "$IFACE_DETECTED" ]; then
        echo "$IFACE_DETECTED"
      else
        log_error "无法自动检测出口网卡"
        exit 1
      fi
    }
    
    ensure_ip_forward() {
      CURRENT="$(sysctl -n net.ipv4.ip_forward 2>/dev/null || echo 0)"
      if [ "$CURRENT" != "1" ]; then
        log_info "开启 IPv4 转发"
        if ! grep -q 'net.ipv4.ip_forward=1' /etc/sysctl.conf 2>/dev/null; then
          echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf
        fi
        sysctl -w net.ipv4.ip_forward=1 >/dev/null 2>&1 || true
        sysctl -p /etc/sysctl.conf >/dev/null 2>&1 || true
      fi
      log_ok "IPv4 转发已开启"
    }
    
    ensure_tun_device() {
      log_info "检查 /dev/net/tun"
      if [ ! -e /dev/net/tun ]; then
        modprobe tun 2>/dev/null || true
        if [ ! -e /dev/net/tun ]; then
          mkdir -p /dev/net 2>/dev/null || true
          mknod /dev/net/tun c 10 200 2>/dev/null || true
          chmod 600 /dev/net/tun 2>/dev/null || true
        fi
      fi
      if [ ! -e /dev/net/tun ]; then
        log_error "/dev/net/tun 不存在,当前环境不支持 TUN"
        exit 1
      fi
      log_ok "/dev/net/tun 正常"
    }
    
    detect_arch_suffix() {
      ARCH="$(uname -m)"
      FLAVOR="$1"
      case "$ARCH" in
        x86_64)
          if [ "$FLAVOR" = "gnu" ]; then
            echo "x86_64-unknown-linux-gnu"
          else
            echo "x86_64-unknown-linux-musl"
          fi
          ;;
        aarch64|arm64)
          if [ "$FLAVOR" = "gnu" ]; then
            echo "aarch64-unknown-linux-gnu"
          else
            echo "aarch64-unknown-linux-musl"
          fi
          ;;
        *)
          log_error "未支持的架构: $ARCH"
          exit 1
          ;;
      esac
    }
    
    install_phantun_debian() {
      BIN_DIR="/usr/local/bin"
      ARCH_SUFFIX="$(detect_arch_suffix gnu)"
      ZIP_PATH="${BIN_DIR}/phantun_${ARCH_SUFFIX}.zip"
      URL="https://github.com/dndx/phantun/releases/download/${PHANTUN_VERSION}/phantun_${ARCH_SUFFIX}.zip"
      log_info "安装依赖 (apt)"
      export DEBIAN_FRONTEND=noninteractive
      apt update -y >/dev/null
      apt install -y wget unzip ca-certificates iptables iptables-persistent iproute2 >/dev/null
      update-ca-certificates >/dev/null 2>&1 || true
      if command -v phantun_server >/dev/null 2>&1; then
        log_ok "检测到 phantun 已安装"
        return
      fi
      log_info "下载 phantun: ${URL}"
      mkdir -p "$BIN_DIR"
      cd "$BIN_DIR"
      wget -O "$ZIP_PATH" "$URL"
      unzip -o "$ZIP_PATH"
      chmod +x phantun_server phantun_client
      rm -f "$ZIP_PATH"
      log_ok "phantun 已安装到 ${BIN_DIR}"
    }
    
    install_phantun_alpine() {
      BIN_DIR="/usr/local/bin"
      ARCH_SUFFIX="$(detect_arch_suffix musl)"
      ZIP_PATH="${BIN_DIR}/phantun_${ARCH_SUFFIX}.zip"
      URL="https://github.com/dndx/phantun/releases/download/${PHANTUN_VERSION}/phantun_${ARCH_SUFFIX}.zip"
      log_info "安装依赖 (apk)"
      apk update >/dev/null
      apk add --no-cache wget unzip ca-certificates iptables ip6tables iptables-openrc openrc iproute2 >/dev/null
      update-ca-certificates >/dev/null 2>&1 || true
      if command -v phantun_client >/dev/null 2>&1; then
        log_ok "检测到 phantun 已安装"
        return
      fi
      log_info "下载 phantun: ${URL}"
      mkdir -p "$BIN_DIR"
      cd "$BIN_DIR"
      wget -O "$ZIP_PATH" "$URL"
      unzip -o "$ZIP_PATH"
      chmod +x phantun_server phantun_client
      rm -f "$ZIP_PATH"
      log_ok "phantun 已安装到 ${BIN_DIR}"
    }
    
    save_server_config() {
      mkdir -p /etc/phantun
      cat >"$CONFIG_FILE" <<EOF
    ROLE=server
    LISTEN_PORT=$LISTEN_PORT
    BACKEND_ADDR=$BACKEND_ADDR
    BACKEND_PORT=$BACKEND_PORT
    WAN_IFACE=$WAN_IFACE
    EOF
    }
    
    save_client_config() {
      mkdir -p /etc/phantun
      cat >"$CONFIG_FILE" <<EOF
    ROLE=client
    REMOTE_ADDR=$REMOTE_ADDR
    REMOTE_PORT=$REMOTE_PORT
    LOCAL_PORT=$LOCAL_PORT
    WAN_IFACE=$WAN_IFACE
    EOF
    }
    
    load_config() {
      if [ ! -f "$CONFIG_FILE" ]; then
        return 1
      fi
      ROLE=""
      LISTEN_PORT=""
      BACKEND_ADDR=""
      BACKEND_PORT=""
      REMOTE_ADDR=""
      REMOTE_PORT=""
      LOCAL_PORT=""
      WAN_IFACE=""
      while IFS='=' read -r key val; do
        case "$key" in
          ROLE|LISTEN_PORT|BACKEND_ADDR|BACKEND_PORT|REMOTE_ADDR|REMOTE_PORT|LOCAL_PORT|WAN_IFACE)
            eval "$key=\"\$val\""
            ;;
        esac
      done < "$CONFIG_FILE"
      if [ -n "$ROLE" ]; then
        return 0
      else
        return 1
      fi
    }
    
    ensure_shortcut() {
      SCRIPT_PATH="$0"
      if command -v readlink >/dev/null 2>&1; then
        SCRIPT_PATH="$(readlink -f "$0" 2>/dev/null || echo "$0")"
      fi
      TARGET="/usr/local/bin/phantun"
      if [ ! -e "$TARGET" ]; then
        ln -s "$SCRIPT_PATH" "$TARGET" 2>/dev/null || true
        chmod +x "$SCRIPT_PATH" 2>/dev/null || true
        if command -v phantun >/dev/null 2>&1; then
          log_ok "已创建快捷命令: phantun"
        fi
      fi
    }
    
    setup_server_main() {
      printf "%s\n" "${CYAN}当前模式: 服务端${RESET}"
      while :; do
        printf "请输入 FakeTCP 监听端口: "
        read LISTEN_PORT
        [ -n "$LISTEN_PORT" ] && break
        log_warn "端口不能为空"
      done
      while :; do
        printf "请输入 Hy2 后端 IP (回车默认 127.0.0.1): "
        read BACKEND_ADDR
        [ -z "$BACKEND_ADDR" ] && BACKEND_ADDR="127.0.0.1"
        [ -n "$BACKEND_ADDR" ] && break
      done
      while :; do
        printf "请输入 Hy2 后端端口: "
        read BACKEND_PORT
        [ -n "$BACKEND_PORT" ] && break
        log_warn "端口不能为空"
      done
      WAN_IFACE="$(auto_detect_iface)"
    
      log_info "FakeTCP 监听端口: ${GREEN}${LISTEN_PORT}${RESET}"
      log_info "Hy2 后端: ${GREEN}${BACKEND_ADDR}:${BACKEND_PORT}${RESET}"
      log_info "出口网卡: ${GREEN}${WAN_IFACE}${RESET}"
    
      if [ "$OS_TYPE" = "debian" ]; then
        install_phantun_debian
      elif [ "$OS_TYPE" = "alpine" ]; then
        install_phantun_alpine
      else
        log_error "不支持的系统类型"
        exit 1
      fi
    
      ensure_tun_device
      ensure_ip_forward
    
      if [ "$OS_TYPE" = "debian" ]; then
        SERVICE_PATH="/etc/systemd/system/phantun-server.service"
        log_info "写入 systemd 服务: ${SERVICE_PATH}"
        cat >"$SERVICE_PATH" <<EOF
    [Unit]
    Description=Phantun Server
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=simple
    Environment=RUST_LOG=info
    ExecStart=/usr/local/bin/phantun_server --local ${LISTEN_PORT} --remote ${BACKEND_ADDR}:${BACKEND_PORT}
    Restart=always
    RestartSec=3
    User=root
    
    [Install]
    WantedBy=multi-user.target
    EOF
        systemctl daemon-reload
        systemctl enable --now phantun-server
        log_ok "phantun-server 已启动"
      else
        SERVICE_PATH="/etc/init.d/phantun-server"
        log_info "写入 OpenRC 服务: ${SERVICE_PATH}"
        cat >"$SERVICE_PATH" <<EOF
    #!/sbin/openrc-run
    description="Phantun server"
    command="/usr/local/bin/phantun_server"
    command_args="--local ${LISTEN_PORT} --remote ${BACKEND_ADDR}:${BACKEND_PORT}"
    command_background="yes"
    pidfile="/run/\${RC_SVCNAME}.pid"
    depend() { need net; }
    EOF
        chmod +x "$SERVICE_PATH"
        rc-update add phantun-server default >/dev/null 2>&1 || true
        rc-service phantun-server restart >/dev/null 2>&1 || rc-service phantun-server start >/dev/null 2>&1 || true
        log_ok "phantun-server 已启动"
      fi
    
      log_info "添加服务端 iptables 规则"
      iptables -t nat -A PREROUTING -p tcp -i "$WAN_IFACE" --dport "$LISTEN_PORT" -j DNAT --to-destination 192.168.201.2 2>/dev/null || true
      iptables -A FORWARD -i "$WAN_IFACE" -o tun0 -j ACCEPT 2>/dev/null || true
      iptables -A FORWARD -i tun0 -o "$WAN_IFACE" -j ACCEPT 2>/dev/null || true
      iptables -A INPUT -p udp --dport "$BACKEND_PORT" -j ACCEPT 2>/dev/null || true
    
      if [ "$OS_TYPE" = "debian" ]; then
        netfilter-persistent save >/dev/null 2>&1 || true
      else
        if command -v rc-update >/dev/null 2>&1 && [ -x /etc/init.d/iptables ]; then
          rc-update add iptables default >/dev/null 2>&1 || true
          /etc/init.d/iptables save >/dev/null 2>&1 || true
        fi
      fi
    
      save_server_config
      log_ok "服务端配置已保存到 ${CONFIG_FILE}"
    }
    
    setup_client_main() {
      printf "%s\n" "${CYAN}当前模式: 客户端主通道${RESET}"
      while :; do
        printf "请输入远程服务器 IP: "
        read REMOTE_ADDR
        [ -n "$REMOTE_ADDR" ] && break
        log_warn "IP 不能为空"
      done
      while :; do
        printf "请输入远程 FakeTCP 端口: "
        read REMOTE_PORT
        [ -n "$REMOTE_PORT" ] && break
        log_warn "端口不能为空"
      done
      while :; do
        printf "请输入本地 UDP 端口 (Hy2 客户端连接此端口): "
        read LOCAL_PORT
        [ -n "$LOCAL_PORT" ] && break
        log_warn "端口不能为空"
      done
      WAN_IFACE="$(auto_detect_iface)"
    
      log_info "远程 FakeTCP: ${GREEN}${REMOTE_ADDR}:${REMOTE_PORT}${RESET}"
      log_info "本地 UDP: ${GREEN}0.0.0.0:${LOCAL_PORT}${RESET}"
      log_info "出口网卡: ${GREEN}${WAN_IFACE}${RESET}"
    
      if [ "$OS_TYPE" = "debian" ]; then
        install_phantun_debian
      elif [ "$OS_TYPE" = "alpine" ]; then
        install_phantun_alpine
      else
        log_error "不支持的系统类型"
        exit 1
      fi
    
      ensure_tun_device
      ensure_ip_forward
    
      if [ "$OS_TYPE" = "debian" ]; then
        SERVICE_PATH="/etc/systemd/system/phantun-client.service"
        log_info "写入 systemd 客户端主服务: ${SERVICE_PATH}"
        cat >"$SERVICE_PATH" <<EOF
    [Unit]
    Description=Phantun Client Main
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=simple
    Environment=RUST_LOG=info
    ExecStart=/usr/local/bin/phantun_client --local 0.0.0.0:${LOCAL_PORT} --remote ${REMOTE_ADDR}:${REMOTE_PORT}
    Restart=always
    RestartSec=3
    User=root
    
    [Install]
    WantedBy=multi-user.target
    EOF
        systemctl daemon-reload
        systemctl enable --now phantun-client
        log_ok "phantun-client 主通道已启动"
      else
        SERVICE_PATH="/etc/init.d/phantun-client"
        log_info "写入 OpenRC 客户端主服务: ${SERVICE_PATH}"
        cat >"$SERVICE_PATH" <<EOF
    #!/sbin/openrc-run
    description="Phantun client main"
    command="/usr/local/bin/phantun_client"
    command_args="--local 0.0.0.0:${LOCAL_PORT} --remote ${REMOTE_ADDR}:${REMOTE_PORT}"
    command_background="yes"
    pidfile="/run/\${RC_SVCNAME}.pid"
    depend() { need net; }
    EOF
        chmod +x "$SERVICE_PATH"
        rc-update add phantun-client default >/dev/null 2>&1 || true
        rc-service phantun-client restart >/dev/null 2>&1 || rc-service phantun-client start >/dev/null 2>&1 || true
        log_ok "phantun-client 主通道已启动"
      fi
    
      log_info "检查/添加 MASQUERADE 规则"
      if ! iptables -t nat -S POSTROUTING 2>/dev/null | grep -q "192.168.200.2"; then
        iptables -t nat -A POSTROUTING -o "$WAN_IFACE" -s 192.168.200.2 -j MASQUERADE 2>/dev/null || true
      fi
    
      if [ "$OS_TYPE" = "debian" ]; then
        netfilter-persistent save >/dev/null 2>&1 || true
      else
        if command -v rc-update >/dev/null 2>&1 && [ -x /etc/init.d/iptables ]; then
          rc-update add iptables default >/dev/null 2>&1 || true
          /etc/init.d/iptables save >/dev/null 2>&1 || true
        fi
      fi
    
      save_client_config
      log_ok "客户端主通道配置已保存到 ${CONFIG_FILE}"
    }
    
    add_client_instance() {
      printf "%s\n" "${CYAN}客户端: 添加新的转发实例${RESET}"
      while :; do
        printf "请输入远程服务器 IP: "
        read REMOTE_ADDR
        [ -n "$REMOTE_ADDR" ] && break
        log_warn "IP 不能为空"
      done
      while :; do
        printf "请输入远程 FakeTCP 端口: "
        read REMOTE_PORT
        [ -n "$REMOTE_PORT" ] && break
        log_warn "端口不能为空"
      done
      while :; do
        printf "请输入本地 UDP 端口 (该实例监听此端口): "
        read LOCAL_PORT
        [ -n "$LOCAL_PORT" ] && break
        log_warn "端口不能为空"
      done
    
      ensure_tun_device
      ensure_ip_forward
    
      if [ "$OS_TYPE" = "debian" ]; then
        SERVICE_NAME="phantun-client-${LOCAL_PORT}.service"
        SERVICE_PATH="/etc/systemd/system/${SERVICE_NAME}"
        log_info "写入 systemd 客户端实例: ${SERVICE_PATH}"
        cat >"$SERVICE_PATH" <<EOF
    [Unit]
    Description=Phantun Client ${LOCAL_PORT}
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=simple
    Environment=RUST_LOG=info
    ExecStart=/usr/local/bin/phantun_client --local 0.0.0.0:${LOCAL_PORT} --remote ${REMOTE_ADDR}:${REMOTE_PORT}
    Restart=always
    RestartSec=3
    User=root
    
    [Install]
    WantedBy=multi-user.target
    EOF
        systemctl daemon-reload
        systemctl enable --now "phantun-client-${LOCAL_PORT}.service"
        log_ok "客户端实例 phantun-client-${LOCAL_PORT} 已启动"
      else
        SERVICE_NAME="phantun-client-${LOCAL_PORT}"
        SERVICE_PATH="/etc/init.d/${SERVICE_NAME}"
        log_info "写入 OpenRC 客户端实例: ${SERVICE_PATH}"
        cat >"$SERVICE_PATH" <<EOF
    #!/sbin/openrc-run
    description="Phantun client ${LOCAL_PORT}"
    command="/usr/local/bin/phantun_client"
    command_args="--local 0.0.0.0:${LOCAL_PORT} --remote ${REMOTE_ADDR}:${REMOTE_PORT}"
    command_background="yes"
    pidfile="/run/\${RC_SVCNAME}.pid"
    depend() { need net; }
    EOF
        chmod +x "$SERVICE_PATH"
        rc-update add "$SERVICE_NAME" default >/dev/null 2>&1 || true
        rc-service "$SERVICE_NAME" restart >/dev/null 2>&1 || rc-service "$SERVICE_NAME" start >/dev/null 2>&1 || true
        log_ok "客户端实例 ${SERVICE_NAME} 已启动"
      fi
    
      WAN_IFACE="$(auto_detect_iface)"
      if ! iptables -t nat -S POSTROUTING 2>/dev/null | grep -q "192.168.200.2"; then
        log_info "添加 MASQUERADE 规则"
        iptables -t nat -A POSTROUTING -o "$WAN_IFACE" -s 192.168.200.2 -j MASQUERADE 2>/dev/null || true
      fi
    
      if [ "$OS_TYPE" = "debian" ]; then
        netfilter-persistent save >/dev/null 2>&1 || true
      else
        if command -v rc-update >/dev/null 2>&1 && [ -x /etc/init.d/iptables ]; then
          rc-update add iptables default >/dev/null 2>&1 || true
          /etc/init.d/iptables save >/dev/null 2>&1 || true
        fi
      fi
    
      log_info "该客户端实例本地监听: 0.0.0.0:${LOCAL_PORT}"
    }
    
    delete_client_instances() {
      printf "%s\n" "${CYAN}客户端: 删除转发实例${RESET}"
      TMP="/tmp/phantun_cli_inst_$$"
      : >"$TMP"
      INDEX=0
    
      if [ "$OS_TYPE" = "debian" ]; then
        for unit in /etc/systemd/system/phantun-client-*.service; do
          [ -f "$unit" ] || continue
          INDEX=$((INDEX+1))
          echo "$unit" >>"$TMP"
          LINE="$(grep -E '^ExecStart=' "$unit" 2>/dev/null | head -n1 || true)"
          LPORT="$(echo "$LINE" | sed -n 's/.*--local 0.0.0.0:\([0-9]*\).*/\1/p')"
          RADDR="$(echo "$LINE" | sed -n 's/.*--remote \([^ ]*\).*/\1/p')"
          if [ -n "$LPORT" ] && [ -n "$RADDR" ]; then
            printf "  %s) 本地 UDP: %s -> 远程: %s (%s)\n" "$INDEX" "$LPORT" "$RADDR" "$(basename "$unit")"
          else
            printf "  %s) %s\n" "$INDEX" "$(basename "$unit")"
          fi
        done
      else
        for script in /etc/init.d/phantun-client-*; do
          [ -f "$script" ] || continue
          BASE="$(basename "$script")"
          [ "$BASE" = "phantun-client" ] && continue
          INDEX=$((INDEX+1))
          echo "$script" >>"$TMP"
          LINE="$(grep -E '^command_args=' "$script" 2>/dev/null | head -n1 || true)"
          LPORT="$(echo "$LINE" | sed -n 's/.*--local 0.0.0.0:\([0-9]*\).*/\1/p')"
          RADDR="$(echo "$LINE" | sed -n 's/.*--remote \([^ ]*\).*/\1/p')"
          if [ -n "$LPORT" ] && [ -n "$RADDR" ]; then
            printf "  %s) 本地 UDP: %s -> 远程: %s (%s)\n" "$INDEX" "$LPORT" "$RADDR" "$BASE"
          else
            printf "  %s) %s\n" "$INDEX" "$BASE"
          fi
        done
      fi
    
      if [ "$INDEX" -eq 0 ]; then
        log_warn "未检测到任何额外客户端实例"
        rm -f "$TMP"
        return
      fi
    
      printf "请输入要删除的序号(支持多个,用逗号分隔,如 1,2,3),回车取消: "
      read SEL
      if [ -z "$SEL" ]; then
        log_warn "未选择任何实例"
        rm -f "$TMP"
        return
      fi
    
      OLDIFS="$IFS"
      IFS=','
      for idx in $SEL; do
        idx_trim="$(echo "$idx" | tr -d ' ')"
        [ -n "$idx_trim" ] || continue
        PATH_LINE="$(sed -n "${idx_trim}p" "$TMP" 2>/dev/null || true)"
        if [ -z "$PATH_LINE" ]; then
          log_warn "序号 ${idx_trim} 无效"
          continue
        fi
        if [ "$OS_TYPE" = "debian" ]; then
          SVC="$(basename "$PATH_LINE")"
          systemctl disable --now "$SVC" >/dev/null 2>&1 || true
          rm -f "$PATH_LINE"
          systemctl daemon-reload >/dev/null 2>&1 || true
          log_ok "已删除客户端实例: ${SVC}"
        else
          SVC="$(basename "$PATH_LINE")"
          rc-service "$SVC" stop >/dev/null 2>&1 || true
          rc-update del "$SVC" >/dev/null 2>&1 || true
          rm -f "$PATH_LINE"
          log_ok "已删除客户端实例: ${SVC}"
        fi
      done
      IFS="$OLDIFS"
      rm -f "$TMP"
    }
    
    add_extra_port() {
      printf "%s\n" "${CYAN}服务端: 添加伪装端口${RESET}"
      if ! load_config || [ "$ROLE" != "server" ]; then
        log_warn "当前未配置为服务端,无法添加伪装端口"
        return
      fi
      if [ -z "$WAN_IFACE" ]; then
        WAN_IFACE="$(auto_detect_iface)"
      fi
      log_info "出口网卡: ${GREEN}${WAN_IFACE}${RESET}"
      while :; do
        printf "请输入要新增伪装的 TCP 端口: "
        read EXTRA_PORT
        [ -n "$EXTRA_PORT" ] && break
        log_warn "端口不能为空"
      done
      iptables -t nat -A PREROUTING -p tcp -i "$WAN_IFACE" --dport "$EXTRA_PORT" -j DNAT --to-destination 192.168.201.2 2>/dev/null || true
      if [ "$OS_TYPE" = "debian" ]; then
        netfilter-persistent save >/dev/null 2>&1 || true
      else
        if command -v rc-update >/dev/null 2>&1 && [ -x /etc/init.d/iptables ]; then
          rc-update add iptables default >/dev/null 2>&1 || true
          /etc/init.d/iptables save >/dev/null 2>&1 || true
        fi
      fi
      log_ok "已为端口 ${EXTRA_PORT} 添加伪装 (DNAT -> 192.168.201.2)"
    }
    
    delete_ports() {
      printf "%s\n" "${CYAN}服务端: 删除伪装端口${RESET}"
      if ! command -v iptables >/dev/null 2>&1; then
        log_warn "未检测到 iptables"
        return
      fi
      RULES="$(iptables -t nat -S PREROUTING 2>/dev/null | grep 192.168.201.2 2>/dev/null || true)"
      if [ -z "$RULES" ]; then
        log_warn "未检测到指向 192.168.201.2 的伪装端口"
        return
      fi
      TMP="/tmp/phantun_dnat_$$"
      echo "$RULES" >"$TMP"
      log_info "当前可删除的伪装端口:"
      nl -ba "$TMP" | while read num line; do
        PORT="$(echo "$line" | sed -n 's/.*--dport \([0-9]*\).*/\1/p')"
        if [ -n "$PORT" ]; then
          printf "  %s) 端口 %s\n" "$num" "$PORT"
        else
          printf "  %s) 规则 %s\n" "$num" "$line"
        fi
      done
      printf "请输入要删除的序号(支持多个,用逗号分隔,如 1,2,3),回车取消: "
      read SEL
      if [ -z "$SEL" ]; then
        log_warn "未选择任何端口"
        rm -f "$TMP"
        return
      fi
      OLDIFS="$IFS"
      IFS=','
      for idx in $SEL; do
        idx_trim="$(echo "$idx" | tr -d ' ')"
        [ -n "$idx_trim" ] || continue
        LINE="$(sed -n "${idx_trim}p" "$TMP" 2>/dev/null || true)"
        if [ -z "$LINE" ]; then
          log_warn "序号 ${idx_trim} 无效"
          continue
        fi
        CMD="$(echo "$LINE" | sed 's/^-A /-D /')"
        iptables -t nat $CMD 2>/dev/null && log_ok "已删除: ${LINE}" || log_warn "删除失败: ${LINE}"
      done
      IFS="$OLDIFS"
      rm -f "$TMP"
      if [ "$OS_TYPE" = "debian" ]; then
        netfilter-persistent save >/dev/null 2>&1 || true
      else
        if command -v rc-update >/dev/null 2>&1 && [ -x /etc/init.d/iptables ]; then
          rc-update add iptables default >/dev/null 2>&1 || true
          /etc/init.d/iptables save >/dev/null 2>&1 || true
        fi
      fi
    }
    
    show_config() {
      printf "%s\n" "${CYAN}当前配置与状态:${RESET}"
      if load_config; then
        printf "主配置角色: %s\n" "$ROLE"
        if [ "$ROLE" = "server" ]; then
          printf "FakeTCP 监听端口: %s\n" "$LISTEN_PORT"
          printf "Hy2 后端: %s:%s\n" "$BACKEND_ADDR" "$BACKEND_PORT"
          printf "出口网卡: %s\n" "$WAN_IFACE"
        elif [ "$ROLE" = "client" ]; then
          printf "主通道远程 FakeTCP: %s:%s\n" "$REMOTE_ADDR" "$REMOTE_PORT"
          printf "主通道本地 UDP 端口: %s\n" "$LOCAL_PORT"
          printf "出口网卡: %s\n" "$WAN_IFACE"
        fi
      else
        log_warn "未找到主配置文件: ${CONFIG_FILE}"
      fi
    
      if [ "$OS_TYPE" = "debian" ]; then
        COUNT=0
        for unit in /etc/systemd/system/phantun-client-*.service; do
          [ -f "$unit" ] || continue
          if [ "$COUNT" -eq 0 ]; then
            printf "%s\n" "${GREEN}额外客户端实例:${RESET}"
          fi
          COUNT=$((COUNT+1))
          LINE="$(grep -E '^ExecStart=' "$unit" 2>/dev/null | head -n1 || true)"
          LPORT="$(echo "$LINE" | sed -n 's/.*--local 0.0.0.0:\([0-9]*\).*/\1/p')"
          RADDR="$(echo "$LINE" | sed -n 's/.*--remote \([^ ]*\).*/\1/p')"
          if [ -n "$LPORT" ] && [ -n "$RADDR" ]; then
            printf "  本地 UDP: %s -> 远程: %s (%s)\n" "$LPORT" "$RADDR" "$(basename "$unit")"
          else
            printf "  %s\n" "$(basename "$unit")"
          fi
        done
      else
        COUNT=0
        for script in /etc/init.d/phantun-client-*; do
          [ -f "$script" ] || continue
          BASE="$(basename "$script")"
          [ "$BASE" = "phantun-client" ] && continue
          if [ "$COUNT" -eq 0 ]; then
            printf "%s\n" "${GREEN}额外客户端实例:${RESET}"
          fi
          COUNT=$((COUNT+1))
          LINE="$(grep -E '^command_args=' "$script" 2>/dev/null | head -n1 || true)"
          LPORT="$(echo "$LINE" | sed -n 's/.*--local 0.0.0.0:\([0-9]*\).*/\1/p')"
          RADDR="$(echo "$LINE" | sed -n 's/.*--remote \([^ ]*\).*/\1/p')"
          if [ -n "$LPORT" ] && [ -n "$RADDR" ]; then
            printf "  本地 UDP: %s -> 远程: %s (%s)\n" "$LPORT" "$RADDR" "$BASE"
          else
            printf "  %s\n" "$BASE"
          fi
        done
      fi
    
      if command -v iptables >/dev/null 2>&1; then
        DNAT_PORTS="$(iptables -t nat -S PREROUTING 2>/dev/null | grep 192.168.201.2 2>/dev/null | sed -n 's/.*--dport \([0-9]*\).*/\1/p' || true)"
        if [ -n "$DNAT_PORTS" ]; then
          printf "%s\n" "${GREEN}当前 DNAT 到 192.168.201.2 的伪装端口:${RESET}"
          echo "$DNAT_PORTS" | sort -u | while read p; do [ -n "$p" ] && echo "  TCP 端口: $p"; done
        else
          log_warn "未检测到指向 192.168.201.2 的 DNAT 规则"
        fi
        MASQ_RULES="$(iptables -t nat -S POSTROUTING 2>/dev/null | grep 192.168.200.2 2>/dev/null || true)"
        if [ -n "$MASQ_RULES" ]; then
          printf "%s\n" "${GREEN}当前针对 192.168.200.2 的 MASQUERADE 规则:${RESET}"
          echo "$MASQ_RULES"
        else
          log_warn "未检测到针对 192.168.200.2 的 MASQUERADE 规则"
        fi
      else
        log_warn "系统中未检测到 iptables,无法检测伪装规则"
      fi
    }
    
    restart_all_services() {
      printf "%s\n" "${CYAN}重启所有 phantun 服务${RESET}"
      if [ "$OS_TYPE" = "debian" ]; then
        if systemctl list-unit-files 2>/dev/null | grep -q phantun-server.service; then
          systemctl restart phantun-server >/dev/null 2>&1 && log_ok "已重启 phantun-server" || log_warn "重启 phantun-server 失败"
        fi
        if systemctl list-unit-files 2>/dev/null | grep -q phantun-client.service; then
          systemctl restart phantun-client >/dev/null 2>&1 && log_ok "已重启 phantun-client 主通道" || log_warn "重启 phantun-client 主通道失败"
        fi
        for unit in /etc/systemd/system/phantun-client-*.service; do
          [ -f "$unit" ] || continue
          SVC="$(basename "$unit")"
          systemctl restart "$SVC" >/dev/null 2>&1 && log_ok "已重启 ${SVC}" || log_warn "重启 ${SVC} 失败"
        done
      elif [ "$OS_TYPE" = "alpine" ]; then
        if [ -f /etc/init.d/phantun-server ]; then
          rc-service phantun-server restart >/dev/null 2>&1 && log_ok "已重启 phantun-server" || log_warn "重启 phantun-server 失败"
        fi
        if [ -f /etc/init.d/phantun-client ]; then
          rc-service phantun-client restart >/dev/null 2>&1 && log_ok "已重启 phantun-client 主通道" || log_warn "重启 phantun-client 主通道失败"
        fi
        for script in /etc/init.d/phantun-client-*; do
          [ -f "$script" ] || continue
          BASE="$(basename "$script")"
          [ "$BASE" = "phantun-client" ] && continue
          rc-service "$BASE" restart >/dev/null 2>&1 && log_ok "已重启 ${BASE}" || log_warn "重启 ${BASE} 失败"
        done
      else
        log_error "未知系统类型,无法重启服务"
      fi
    }
    
    uninstall_phantun() {
      printf "%s\n" "${CYAN}卸载 phantun 与伪装规则${RESET}"
      load_config || true
    
      if [ "$OS_TYPE" = "debian" ]; then
        if systemctl list-unit-files 2>/dev/null | grep -q phantun-server.service; then
          systemctl disable --now phantun-server >/dev/null 2>&1 || true
          rm -f /etc/systemd/system/phantun-server.service
        fi
        if systemctl list-unit-files 2>/dev/null | grep -q phantun-client.service; then
          systemctl disable --now phantun-client >/dev/null 2>&1 || true
          rm -f /etc/systemd/system/phantun-client.service
        fi
        for unit in /etc/systemd/system/phantun-client-*.service; do
          [ -f "$unit" ] || continue
          SVC="$(basename "$unit")"
          systemctl disable --now "$SVC" >/dev/null 2>&1 || true
          rm -f "$unit"
        done
        systemctl daemon-reload >/dev/null 2>&1 || true
      elif [ "$OS_TYPE" = "alpine" ]; then
        if [ -f /etc/init.d/phantun-server ]; then
          rc-service phantun-server stop >/dev/null 2>&1 || true
          rc-update del phantun-server >/dev/null 2>&1 || true
          rm -f /etc/init.d/phantun-server
        fi
        if [ -f /etc/init.d/phantun-client ]; then
          rc-service phantun-client stop >/dev/null 2>&1 || true
          rc-update del phantun-client >/dev/null 2>&1 || true
          rm -f /etc/init.d/phantun-client
        fi
        for script in /etc/init.d/phantun-client-*; do
          [ -f "$script" ] || continue
          BASE="$(basename "$script")"
          [ "$BASE" = "phantun-client" ] && continue
          rc-service "$BASE" stop >/dev/null 2>&1 || true
          rc-update del "$BASE" >/dev/null 2>&1 || true
          rm -f "$script"
        done
      fi
    
      if command -v iptables >/dev/null 2>&1; then
        iptables -t nat -S PREROUTING 2>/dev/null | grep 192.168.201.2 2>/dev/null | while read -r line; do
          iptables -t nat $(echo "$line" | sed 's/^-A /-D /') >/dev/null 2>&1 || true
        done
        iptables -t nat -S POSTROUTING 2>/dev/null | grep 192.168.200.2 2>/dev/null | while read -r line; do
          iptables -t nat $(echo "$line" | sed 's/^-A /-D /') >/dev/null 2>&1 || true
        done
        if [ "$OS_TYPE" = "debian" ]; then
          netfilter-persistent save >/dev/null 2>&1 || true
        else
          if command -v rc-update >/dev/null 2>&1 && [ -x /etc/init.d/iptables ]; then
            rc-update add iptables default >/dev/null 2>&1 || true
            /etc/init.d/iptables save >/dev/null 2>&1 || true
          fi
        fi
      fi
    
      rm -f /usr/local/bin/phantun_server /usr/local/bin/phantun_client /usr/local/bin/phantun 2>/dev/null || true
      rm -f "$CONFIG_FILE" 2>/dev/null || true
      rmdir /etc/phantun 2>/dev/null || true
    
      log_ok "已卸载 phantun 及相关服务和伪装规则"
    }
    
    server_menu() {
      while true; do
        printf "\n%s\n" "${CYAN}====== 服务端管理菜单 ======${RESET}"
        printf "  1) 一键配置/修改 服务端\n"
        printf "  2) 添加伪装端口\n"
        printf "  3) 删除伪装端口\n"
        printf "  4) 返回主菜单\n"
        printf "请输入数字: "
        read CH
        case "$CH" in
          1) setup_server_main ;;
          2) add_extra_port ;;
          3) delete_ports ;;
          4) break ;;
          *) log_warn "无效选择" ;;
        esac
      done
    }
    
    client_menu() {
      while true; do
        printf "\n%s\n" "${CYAN}====== 客户端管理菜单 ======${RESET}"
        printf "  1) 配置/修改 客户端主通道\n"
        printf "  2) 添加新的转发实例\n"
        printf "  3) 删除转发实例\n"
        printf "  4) 返回主菜单\n"
        printf "请输入数字: "
        read CH
        case "$CH" in
          1) setup_client_main ;;
          2) add_client_instance ;;
          3) delete_client_instances ;;
          4) break ;;
          *) log_warn "无效选择" ;;
        esac
      done
    }
    
    main_menu() {
      while true; do
        printf "\n%s\n" "${CYAN}========== phantun 一键配置脚本 ==========${RESET}"
        printf "  1) 进入 服务端 管理菜单\n"
        printf "  2) 进入 客户端 管理菜单\n"
        printf "  3) 查看当前配置和状态\n"
        printf "  4) 重启所有 phantun 服务\n"
        printf "  5) 卸载 phantun 及伪装\n"
        printf "  6) 退出\n"
        printf "请输入数字: "
        read CH
        case "$CH" in
          1) server_menu ;;
          2) client_menu ;;
          3) show_config ;;
          4) restart_all_services ;;
          5) uninstall_phantun ;;
          6) exit 0 ;;
          *) log_warn "无效选择" ;;
        esac
      done
    }
    
    ensure_root
    detect_os
    ensure_shortcut
    if [ "$OS_TYPE" = "unknown" ]; then
      log_error "未知系统,仅支持 Debian/Ubuntu 和 Alpine"
      exit 1
    fi
    main_menu

    3.2 使用方式

    1. 保存脚本:
    cd /root
    nano phantun-menu.sh   # 或 vi phantun-menu.sh
    # 把上面的脚本完整粘进去保存
    1. 加执行权限:
    chmod +x phantun-menu.sh
    1. 首次运行(会顺便创建 phantun 快捷命令):
    ./phantun-menu.sh

    之后就可以直接敲:

    phantun
    • 选「服务端菜单」,在落地机上配置 Hy2 伪装端口
    • 选「客户端菜单」,在中转机上配置主通道和多个转发实例
    本文著作权归作者 [ Miku ] 享有,未经作者书面授权,禁止转载,封面图片来源于 [ 互联网 ] ,本文仅供个人学习、研究和欣赏使用。如有异议,请联系博主及时处理。
    — END —
    首页微语关于
    Copyright©2025  All Rights Reserved.  Load:0.026 s
    Theme by OneBlog V3.6.4
    夜间模式

    开源不易,请尊重作者版权,保留基本的版权信息。