diff --git a/dev/README.md b/dev/README.md index 720756d..955b5bf 100644 --- a/dev/README.md +++ b/dev/README.md @@ -59,10 +59,10 @@ iwr -useb https://ghproxy.net/https://raw.githubusercontent.com/sky22333/shell/m #### 一键修改root密码: ``` -bash <(curl -sSL https://github.com/sky22333/shell/raw/main/dev/root.sh) +bash <(curl -sSL https://raw.githubusercontent.com/sky22333/shell/main/dev/root.sh) ``` ``` -bash <(curl -sSL https://cdn.jsdelivr.net/gh/sky22333/shell@main/dev/root.sh) +bash <(curl -sSL https://cdn.jsdmirror.com/gh/sky22333/shell@main/dev/root.sh) ``` > 部分机器修改不生效,请打开查找`/etc/ssh/sshd_config.d/xxxx.conf`类似文件 > diff --git a/dev/cf-setup.ps1 b/dev/cf-setup.ps1 index 16a568a..3d8bcd3 100644 --- a/dev/cf-setup.ps1 +++ b/dev/cf-setup.ps1 @@ -74,7 +74,7 @@ function Test-AdminRights { Write-Host "====== CloudFlared Tunnel Setup Tool ======" -ForegroundColor Cyan Write-Host "Initializing..." -ForegroundColor Yellow -$cloudflaredUrl = "https://github.com/cloudflare/cloudflared/releases/download/2025.8.0/cloudflared-windows-amd64.exe" +$cloudflaredUrl = "https://github.com/cloudflare/cloudflared/releases/download/2025.11.1/cloudflared-windows-amd64.exe" $installDir = "$env:ProgramData\cloudflared" $cloudflaredBin = Join-Path $installDir "cloudflared.exe" $logPath = Join-Path $installDir "cloudflared.log" diff --git a/dev/cf-tunnel-mac b/dev/cf-tunnel-mac index e67da6a..0a1af7b 100644 --- a/dev/cf-tunnel-mac +++ b/dev/cf-tunnel-mac @@ -17,9 +17,9 @@ ARCH=$(uname -m) if [[ "$OS_TYPE" == "Darwin" ]]; then # macOS 配置 if [[ "$ARCH" == "arm64" ]]; then - CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.8.0/cloudflared-darwin-arm64.tgz" + CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.11.1/cloudflared-darwin-arm64.tgz" else - CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.8.0/cloudflared-darwin-amd64.tgz" + CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.11.1/cloudflared-darwin-amd64.tgz" fi CLOUDFLARED_BIN="/usr/local/bin/cloudflared" SERVICE_PATH="$HOME/Library/LaunchAgents/com.cloudflare.cloudflared.plist" @@ -28,9 +28,9 @@ if [[ "$OS_TYPE" == "Darwin" ]]; then else # Linux 配置 if [[ "$ARCH" == "aarch64" || "$ARCH" == "arm64" ]]; then - CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.8.0/cloudflared-linux-arm64" + CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.11.1/cloudflared-linux-arm64" else - CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.8.0/cloudflared-linux-amd64" + CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.11.1/cloudflared-linux-amd64" fi CLOUDFLARED_BIN="/usr/local/bin/cloudflared" SERVICE_PATH="/etc/systemd/system/cloudflared-tunnel.service" diff --git a/dev/cf-tunnel.sh b/dev/cf-tunnel.sh index f39380a..5c2acc7 100644 --- a/dev/cf-tunnel.sh +++ b/dev/cf-tunnel.sh @@ -11,9 +11,9 @@ NC='\033[0m' # 清除颜色 LOC=$(curl -s https://www.cloudflare.com/cdn-cgi/trace | grep 'loc=' | cut -d= -f2) if [[ "$LOC" == "CN" ]]; then - CLOUDFLARED_URL="https://gh-proxy.com/https://github.com/cloudflare/cloudflared/releases/download/2025.9.1/cloudflared-linux-amd64" + CLOUDFLARED_URL="https://gh-proxy.com/https://github.com/cloudflare/cloudflared/releases/download/2025.11.1/cloudflared-linux-amd64" else - CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.9.1/cloudflared-linux-amd64" + CLOUDFLARED_URL="https://github.com/cloudflare/cloudflared/releases/download/2025.11.1/cloudflared-linux-amd64" fi CLOUDFLARED_BIN="/usr/local/bin/cloudflared" diff --git a/dev/check_ntpdate.sh b/dev/check_ntpdate.sh index e906eb4..bb4311b 100644 --- a/dev/check_ntpdate.sh +++ b/dev/check_ntpdate.sh @@ -1,12 +1,8 @@ #!/bin/bash -# 封装脚本过期函数 check_ntpdate() { - # 设置过期时间 local expire_date="2025-10-10 12:00:00" - # date -d "$(curl -sI https://www.bing.com | grep -i '^date:' | cut -d' ' -f2-)" +'%Y-%m-%d %H:%M:%S UTC+8' - # 获取时间戳(从 https://www.cloudflare.com/cdn-cgi/trace 获取) timestamp=$(curl -s https://www.cloudflare.com/cdn-cgi/trace | grep -oP 'ts=\K\d+') # 如果获取时间戳失败,则停止运行脚本 @@ -18,12 +14,10 @@ check_ntpdate() { # 转换时间戳为 YYYY-MM-DD HH:MM:SS 格式(北京时间) current_time=$(TZ="Asia/Shanghai" date -d @$timestamp "+%Y-%m-%d %H:%M:%S") - # 判断当前时间是否超过过期日期 if [[ "$current_time" > "$expire_date" ]]; then echo "当前脚本已过期,请联系开发者。" exit 1 fi } -# 调用函数执行检查 check_ntpdate diff --git a/k8s/README.md b/k8s/README.md index 35031db..b3256cd 100644 --- a/k8s/README.md +++ b/k8s/README.md @@ -52,31 +52,6 @@ apt update && apt install -y helm helm version ``` -## 安装traefik - -traefik 是反向代理和证书管理工具: - -```bash -# 添加 Traefik Helm 仓库 -helm repo add traefik https://traefik.github.io/charts -helm repo update - -# 创建 traefik 命名空间 -kubectl create namespace traefik - -# 安装 Traefik -helm install traefik traefik/traefik \ - --namespace traefik --create-namespace \ - --set deployment.replicas=1 \ - --set service.type=LoadBalancer \ - --set ports.websecure.tls=true \ - --set ingressClass.enabled=true \ - --set ingressClass.isDefaultClass=true - -# 验证 Traefik 安装 -kubectl get pods -n traefik -``` - ## 常用操作命令 ```bash diff --git a/l2tp/README.md b/l2tp/README.md index 76505a1..5cb8874 100644 --- a/l2tp/README.md +++ b/l2tp/README.md @@ -19,7 +19,6 @@ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" -o l2tp $env:GOOS="linux"; $env:GOARCH="amd64"; $env:CGO_ENABLED="0"; go build -ldflags="-s -w" -o l2tp ``` - ### 卸载 ``` # 停止服务 @@ -41,65 +40,4 @@ ps aux | egrep 'xl2tpd|strongswan|pptpd' | grep -v grep 3x-ui则使用`tunnel`入站,打开`Follow Redirect`,打开`Sockopt`中的`TProxy`,然后同样的使用源IP路由到指定出站。 -**然后使用`iptables`在系统层面拦截`10.10.10.0/24`网段访问公网的流量,交给 Sing-box 处理,按照以下步骤配置** - -1:配置 Linux 内核策略路由,将打标流量重定向到本地。 -``` -# 配置策略路由:凡是防火墙标记 (fwmark) 为 1 的流量,查路由表 100 -/bin/ip rule add fwmark 1 table 100 - -# 配置路由表 100:将所有流量重定向到本地回环接口 -/bin/ip route add local 0.0.0.0/0 dev lo table 100 -``` - -2:新建一个链 SINGBOX -``` -iptables -t mangle -N SINGBOX -``` - -3:绕过局域网和私有地址(不代理内部通信) -``` -iptables -t mangle -A SINGBOX -d 0.0.0.0/8 -j RETURN -iptables -t mangle -A SINGBOX -d 10.0.0.0/8 -j RETURN -iptables -t mangle -A SINGBOX -d 127.0.0.0/8 -j RETURN -iptables -t mangle -A SINGBOX -d 169.254.0.0/16 -j RETURN -iptables -t mangle -A SINGBOX -d 172.16.0.0/12 -j RETURN -iptables -t mangle -A SINGBOX -d 192.168.0.0/16 -j RETURN -iptables -t mangle -A SINGBOX -d 224.0.0.0/4 -j RETURN -iptables -t mangle -A SINGBOX -d 240.0.0.0/4 -j RETURN -``` - -4:核心拦截规则:仅拦截来自 L2TP 网段`10.10.10.0/24`的流量,TProxy 端口为`12345` -``` -iptables -t mangle -A SINGBOX -s 10.10.10.0/24 -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1 -iptables -t mangle -A SINGBOX -s 10.10.10.0/24 -p udp -j TPROXY --on-port 12345 --tproxy-mark 1 -``` - -5:应用到 PREROUTING 链 -``` -iptables -t mangle -A PREROUTING -j SINGBOX -``` - -6:不允许公网访问透明代理端口 -``` -iptables -I INPUT -p tcp --dport 12345 -j DROP -iptables -I INPUT -p udp --dport 12345 -j DROP -``` - -#### 清理流量规则(按顺序执行) -``` -# 清理 iptables 规则 -iptables -t mangle -D PREROUTING -j SINGBOX -iptables -t mangle -F SINGBOX -iptables -t mangle -X SINGBOX -``` -``` -# 清理策略路由和路由表 -/bin/ip route del local 0.0.0.0/0 dev lo table 100 -/bin/ip rule del fwmark 1 table 100 -``` -``` -# 放行透明代理端口 -iptables -D INPUT -p tcp --dport 12345 -j DROP -iptables -D INPUT -p udp --dport 12345 -j DROP -``` +然后使用`iptables`在系统层面拦截`10.10.10.0/24`网段访问公网的流量,交给 Sing-box 处理。 \ No newline at end of file diff --git a/proxy/README.md b/proxy/README.md index 34b175e..00f1140 100644 --- a/proxy/README.md +++ b/proxy/README.md @@ -4,11 +4,11 @@ bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release ``` - 一键安装L2TP +国外安装 ``` -bash <(curl -sSL https://github.com/sky22333/shell/raw/main/proxy/l2tp.sh) +bash <(curl -sSL https://raw.githubusercontent.com/sky22333/shell/main/proxy/l2tp.sh) ``` - -- singbox全家桶脚本 -``` -bash <(curl -sSL https://github.com/sky22333/shell/raw/main/proxy/singbox.sh) +国内安装 ``` +bash <(curl -sSL https://cdn.jsdmirror.com/gh/sky22333/shell@main/proxy/l2tp.sh) +``` \ No newline at end of file diff --git a/proxy/singbox.sh b/proxy/singbox.sh deleted file mode 100644 index b60b2f8..0000000 --- a/proxy/singbox.sh +++ /dev/null @@ -1,6151 +0,0 @@ -#!/bin/bash -# 自用修改版脚本,sing-box全协议脚本,鸣谢:https://github.com/Devmiston/sing-box - -RED='\033[0;31m' -GREEN='\033[0;32m' -CYAN='\033[0;36m' -YELLOW='\033[0;33m' -NC='\033[0m' - -disable_option=false -enable_ech=false -listen_port="" -override_port="" -start_port="" -end_port="" -ip_v4="" -ip_v6="" -record_content="" -record_type="" -record_name="" -obfs_password="" -domain="" -domain_name="" -up_mbps="" -down_mbps="" -certificate_path="" -private_key_path="" -public_key="" -private_key="" -multiplex_config="" -brutal_config="" -warp_output_file="" -ech_key=() -ech_config=() -user_names=() -user_passwords=() -user_uuids=() -ss_passwords=() -stls_passwords=() -short_ids=() - -# SingBox版本控制 - 留空使用最新版本,指定版本如:"1.12.4" -SINGBOX_VERSION="" - -# 检查必需依赖并自动安装 -function check_dependencies() { - local missing_deps=() - - # 检查wget - if ! command -v wget >/dev/null 2>&1; then - missing_deps+=("wget") - fi - - # 检查jq - if ! command -v jq >/dev/null 2>&1; then - missing_deps+=("jq") - fi - - if [[ ${#missing_deps[@]} -eq 0 ]]; then - return 0 - fi - - echo "检测到缺少必需依赖: ${missing_deps[*]}" - echo "正在尝试自动安装..." - - # 检测包管理器并安装 - if command -v apt >/dev/null 2>&1; then - apt update >/dev/null 2>&1 - apt install -y "${missing_deps[@]}" >/dev/null 2>&1 - elif command -v yum >/dev/null 2>&1; then - yum install -y "${missing_deps[@]}" >/dev/null 2>&1 - elif command -v dnf >/dev/null 2>&1; then - dnf install -y "${missing_deps[@]}" >/dev/null 2>&1 - elif command -v pacman >/dev/null 2>&1; then - pacman -S --noconfirm "${missing_deps[@]}" >/dev/null 2>&1 - else - echo -e "${RED}未检测到支持的包管理器,请手动安装: ${missing_deps[*]}${NC}" - exit 1 - fi - - # 验证安装结果 - for dep in "${missing_deps[@]}"; do - if ! command -v "$dep" >/dev/null 2>&1; then - echo -e "${RED}安装 $dep 失败,请手动安装${NC}" - exit 1 - fi - done - - echo -e "${GREEN}依赖安装完成${NC}" -} - -# 检查防火墙以及放行端口 -function check_firewall_configuration() { - local os_name=$(uname -s) - local firewall="" - local ports=("$listen_port" "$override_port" 80) - local proto_list=("tcp" "udp") - - if [[ $os_name == "Linux" ]]; then - if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "Status: active"; then - firewall="ufw" - elif command -v ip6tables >/dev/null 2>&1 && ip6tables -S | grep -q "INPUT -j DROP"; then - firewall="iptables" - elif command -v iptables >/dev/null 2>&1 && iptables -S | grep -q "INPUT -j DROP"; then - firewall="iptables" - elif systemctl is-active --quiet netfilter-persistent; then - firewall="iptables" - elif systemctl is-active --quiet iptables.service; then - firewall="iptables" - elif command -v firewalld >/dev/null 2>&1 && firewall-cmd --state | grep -q "running"; then - firewall="firewalld" - fi - fi - - if [[ -z $firewall ]]; then - echo "No firewall configuration detected or firewall is not enabled, skipping firewall configuration." - return - fi - - echo "Checking firewall configuration for: $firewall..." - - case $firewall in - ufw) - ufw status | grep -q "Status: active" || ufw enable >/dev/null 2>&1 - for port in "${ports[@]}"; do - for proto in "${proto_list[@]}"; do - ufw status | grep -q " $port/$proto" || ufw allow "$port/$proto" >/dev/null 2>&1 - done - done - ;; - iptables) - for port in "${ports[@]}"; do - for proto in "${proto_list[@]}"; do - # IPv4 - iptables -C INPUT -p "$proto" --dport "$port" -j ACCEPT 2>/dev/null \ - || iptables -A INPUT -p "$proto" --dport "$port" -j ACCEPT >/dev/null 2>&1 - # IPv6 - ip6tables -C INPUT -p "$proto" --dport "$port" -j ACCEPT 2>/dev/null \ - || ip6tables -A INPUT -p "$proto" --dport "$port" -j ACCEPT >/dev/null 2>&1 - done - done - [[ -e /etc/iptables/rules.v4 ]] && iptables-save > /etc/iptables/rules.v4 - [[ -e /etc/iptables/rules.v6 ]] && ip6tables-save > /etc/iptables/rules.v6 - [[ -e /etc/sysconfig/iptables ]] && iptables-save > /etc/sysconfig/iptables - [[ -e /etc/sysconfig/ip6tables ]] && ip6tables-save > /etc/sysconfig/ip6tables - ;; - firewalld) - for port in "${ports[@]}"; do - for proto in "${proto_list[@]}"; do - firewall-cmd --zone=public --list-ports | grep -q "$port/$proto" \ - || firewall-cmd --zone=public --add-port="$port/$proto" --permanent >/dev/null 2>&1 - done - done - firewall-cmd --reload - ;; - esac - - echo "Firewall configuration has been updated." -} - -# 检查sing-box所需的文件夹及配置文件 -function create_sing_box_folders() { - local folders=("/usr/local/etc/sing-box" "/etc/ssl/private") - - for folder in "${folders[@]}"; do - if [[ ! -d "$folder" ]]; then - mkdir -p "$folder" - [[ "$folder" == "/usr/local/etc/sing-box" ]] && touch "$folder/config.json" - fi - done -} - -# 检查juicity所需的文件夹及配置文件 -function create_juicity_folder() { - local folders=("/usr/local/etc/juicity" "/etc/ssl/private") - - for folder in "${folders[@]}"; do - if [[ ! -d "$folder" ]]; then - mkdir -p "$folder" - [[ "$folder" == "/usr/local/etc/juicity" ]] && touch "$folder/config.json" - fi - done -} - -# 检查clash配置文件是否存在 -function ensure_clash_yaml() { - local clash_yaml="/usr/local/etc/sing-box/clash.yaml" - - if [[ ! -e "$clash_yaml" ]]; then - touch "$clash_yaml" - fi -} - -# 检查sing-box配置文件是否存在 -function check_config_file_existence() { - local config_file="/usr/local/etc/sing-box/config.json" - - if [[ ! -f "$config_file" ]]; then - echo -e "${RED}sing-box 配置文件不存在,请先搭建节点!${NC}" - exit 1 - fi -} - -# 生成naive客户端随机文件名 -function generate_naive_random_filename() { - local dir="/usr/local/etc/sing-box" - local filename="" - - while true; do - random_value=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 5 | head -n 1) - filename="naive_client_${random_value}.json" - - if [[ ! -e "${dir}/${filename}" ]]; then - touch "${dir}/${filename}" - naive_client_filename="${dir}/${filename}" - break - fi - done -} - -# 安装sing-box -function install_sing_box() { - if [[ -f "/usr/local/bin/sing-box" && -f "/usr/local/etc/sing-box/config.json" ]]; then - return 1 - else - get_local_ip - configure_dns64 - select_sing_box_install_option - configure_sing_box_service - create_sing_box_folders - fi -} - -# 配置DNS64 -function configure_dns64() { - if [[ -n $ip_v4 ]]; then - return - fi - - if [[ -n $ip_v6 ]]; then - echo "Check that the machine is IPv6 single-stack network, configure DNS64..." - sed -i '/^nameserver /s/^/#/' /etc/resolv.conf - echo "nameserver 2a00:1098:2b::1" >> /etc/resolv.conf - echo "nameserver 2a01:4f9:c010:3f02::1" >> /etc/resolv.conf - echo "nameserver 2a01:4f8:c2c:123f::1" >> /etc/resolv.conf - echo "DNS64 configuration is complete." - fi -} - -# 配置BBR -function enable_bbr() { - if grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf; then - echo "BBR is already enabled, skipping configuration." - return - fi - - while true; do - read -p "是否开启 BBR (Y/N,默认N)? " -i "N" response - response=${response:-"N"} - - if [[ $response == "y" || $response == "Y" ]]; then - echo "Enable BBR..." - echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf - echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf - sysctl -p > /dev/null - echo "BBR has been enabled" - break - elif [[ $response == "n" || $response == "N" ]]; then - echo "BBR will not be enabled." - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done -} - -# 选择sing-box的安装方式 -function select_sing_box_install_option() { - while true; do - echo "请选择 sing-box 的安装方式(默认1):" - echo "1). 下载安装 sing-box(Latest 版本)" - echo "2). 下载安装 sing-box(Beta 版本)" - - read -p "请选择 [1-2]: " install_option - install_option="${install_option:-1}" - - case $install_option in - 1) - install_latest_sing_box - break - ;; - 2) - install_Pre_release_sing_box - break - ;; - *) - echo -e "${RED}无效的选择,请重新输入!${NC}" - ;; - esac - done -} - - - -# 获取 sing-box 下载链接(支持版本控制) -function get_singbox_download_url() { - local arch=$(uname -m) - local version="$1" - local download_url - - if [[ -z "$version" ]]; then - # 原有逻辑:获取latest版本 - local url="https://api.github.com/repos/SagerNet/sing-box/releases/latest" - case $arch in - x86_64|amd64) - download_url=$(curl -s $url | grep -o "https://github.com[^\"']*linux-amd64.tar.gz") - ;; - armv7l) - download_url=$(curl -s $url | grep -o "https://github.com[^\"']*linux-armv7.tar.gz") - ;; - aarch64|arm64) - download_url=$(curl -s $url | grep -o "https://github.com[^\"']*linux-arm64.tar.gz") - ;; - amd64v3) - download_url=$(curl -s $url | grep -o "https://github.com[^\"']*linux-amd64v3.tar.gz") - ;; - s390x) - download_url=$(curl -s $url | grep -o "https://github.com[^\"']*linux-s390x.tar.gz") - ;; - *) - echo -e "${RED}不支持的架构:$arch${NC}" >&2 - return 1 - ;; - esac - else - # 固定版本逻辑:构造特定版本的下载链接 - case $arch in - x86_64|amd64) - download_url="https://github.com/SagerNet/sing-box/releases/download/v${version}/sing-box-${version}-linux-amd64.tar.gz" - ;; - armv7l) - download_url="https://github.com/SagerNet/sing-box/releases/download/v${version}/sing-box-${version}-linux-armv7.tar.gz" - ;; - aarch64|arm64) - download_url="https://github.com/SagerNet/sing-box/releases/download/v${version}/sing-box-${version}-linux-arm64.tar.gz" - ;; - amd64v3) - download_url="https://github.com/SagerNet/sing-box/releases/download/v${version}/sing-box-${version}-linux-amd64v3.tar.gz" - ;; - s390x) - download_url="https://github.com/SagerNet/sing-box/releases/download/v${version}/sing-box-${version}-linux-s390x.tar.gz" - ;; - *) - echo -e "${RED}不支持的架构:$arch${NC}" >&2 - return 1 - ;; - esac - fi - - echo "$download_url" -} - -# 安装最新版本的 sing-box -function install_latest_sing_box() { - local download_url=$(get_singbox_download_url "$SINGBOX_VERSION") - - if [[ $? -ne 0 ]] || [[ -z "$download_url" ]]; then - echo -e "${RED}无法获取下载链接${NC}" - return 1 - fi - - # 对于固定版本,验证URL是否存在 - if [[ -n "$SINGBOX_VERSION" ]]; then - if ! curl --output /dev/null --silent --head --fail "$download_url"; then - echo -e "${RED}指定版本 $SINGBOX_VERSION 不存在或下载链接无效${NC}" - return 1 - fi - echo "Downloading Sing-Box version $SINGBOX_VERSION..." - else - echo "Downloading Sing-Box..." - fi - - wget -qO sing-box.tar.gz "$download_url" 2>&1 >/dev/null - if [[ $? -ne 0 ]]; then - echo -e "${RED}下载失败${NC}" - return 1 - fi - - tar -xzf sing-box.tar.gz -C /usr/local/bin --strip-components=1 - rm sing-box.tar.gz - chmod +x /usr/local/bin/sing-box - echo "Sing-Box installed successfully." -} - -# 安装预发布版本的 sing-box -function install_Pre_release_sing_box() { - local arch=$(uname -m) - local url="https://api.github.com/repos/SagerNet/sing-box/releases" - local download_url - - case $arch in - x86_64|amd64) - download_url=$(curl -s "$url" | jq -r '.[] | select(.prerelease == true) | .assets[] | select(.browser_download_url | contains("linux-amd64.tar.gz")) | .browser_download_url' | head -n 1) - ;; - armv7l) - download_url=$(curl -s "$url" | jq -r '.[] | select(.prerelease == true) | .assets[] | select(.browser_download_url | contains("linux-armv7.tar.gz")) | .browser_download_url' | head -n 1) - ;; - aarch64|arm64) - download_url=$(curl -s "$url" | jq -r '.[] | select(.prerelease == true) | .assets[] | select(.browser_download_url | contains("linux-arm64.tar.gz")) | .browser_download_url' | head -n 1) - ;; - amd64v3) - download_url=$(curl -s "$url" | jq -r '.[] | select(.prerelease == true) | .assets[] | select(.browser_download_url | contains("linux-amd64v3.tar.gz")) | .browser_download_url' | head -n 1) - ;; - s390x) - download_url=$(curl -s "$url" | jq -r '.[] | select(.prerelease == true) | .assets[] | select(.browser_download_url | contains("linux-s390x.tar.gz")) | .browser_download_url' | head -n 1) - ;; - *) - echo -e "${RED}不支持的架构:$arch${NC}" - return 1 - ;; - esac - - if [[ -n "$download_url" ]]; then - echo "Downloading Sing-Box..." - wget -qO sing-box.tar.gz "$download_url" 2>&1 >/dev/null - tar -xzf sing-box.tar.gz -C /usr/local/bin --strip-components=1 - rm sing-box.tar.gz - chmod +x /usr/local/bin/sing-box - - echo "Sing-Box installed successfully." - else - echo -e "${RED}Unable to get pre-release download link for Sing-Box.${NC}" - return 1 - fi -} - -# 安装最新版本的 juicity -function install_latest_juicity() { - local arch=$(uname -m) - - case $arch in - "arm64") - arch_suffix="arm64" - ;; - "armv5") - arch_suffix="armv5" - ;; - "armv6") - arch_suffix="armv6" - ;; - "armv7") - arch_suffix="armv7" - ;; - "mips") - arch_suffix="mips32" - ;; - "mipsel") - arch_suffix="mips32le" - ;; - "mips64") - arch_suffix="mips64" - ;; - "mips64el") - arch_suffix="mips64le" - ;; - "riscv64") - arch_suffix="riscv64" - ;; - "i686") - arch_suffix="x86_32" - ;; - "x86_64") - if [[ -n "$(grep avx2 /proc/cpuinfo)" ]]; then - arch_suffix="x86_64_v3_avx2" - else - arch_suffix="x86_64_v2_sse" - fi - ;; - *) - echo "Unsupported architecture: $arch" - return 1 - ;; - esac - - local github_api_url="https://api.github.com/repos/juicity/juicity/releases/latest" - local download_url=$(curl -s "$github_api_url" | grep "browser_download_url.*$arch_suffix.zip\"" | cut -d '"' -f 4) - local temp_dir=$(mktemp -d) - local install_path="/usr/local/bin/juicity-server" - - echo "Downloading the latest version of juicity-server..." - wget -P "$temp_dir" "$download_url" >/dev/null 2>&1 - unzip "$temp_dir/*.zip" -d "$temp_dir" >/dev/null 2>&1 - mv "$temp_dir/juicity-server" "$install_path" >/dev/null 2>&1 - chmod +x /usr/local/bin/juicity-server - - echo "juicity-server has been downloaded." - rm -rf "$temp_dir" -} - -# 配置 sing-box 启动服务 -function configure_sing_box_service() { - echo "Configuring sing-box startup service..." - - local service_file="/etc/systemd/system/sing-box.service" - if [[ -f $service_file ]]; then - rm "$service_file" - fi - - local service_config='[Unit] -Description=sing-box service -Documentation=https://sing-box.sagernet.org -After=network.target nss-lookup.target - -[Service] -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH -AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH -ExecStart=/usr/local/bin/sing-box run -c /usr/local/etc/sing-box/config.json -ExecReload=/bin/kill -HUP $MAINPID -Restart=on-failure -RestartSec=10s -LimitNOFILE=infinity - -[Install] -WantedBy=multi-user.target' - - echo "$service_config" >"$service_file" - echo "sing-box startup service has been configured." -} - -# 配置 juicity 启动服务 -function configure_juicity_service() { - echo "Configuring juicity startup service..." - - local service_file="/etc/systemd/system/juicity.service" - if [[ -f $service_file ]]; then - rm "$service_file" - fi - - local service_config='[Unit] -Description=juicity-server Service -Documentation=https://github.com/juicity/juicity -After=network.target nss-lookup.target - -[Service] -Type=simple -User=root -Environment=QUIC_GO_ENABLE_GSO=true -ExecStart=/usr/local/bin/juicity-server run -c /usr/local/etc/juicity/config.json --disable-timestamp -Restart=on-failure -LimitNPROC=512 -LimitNOFILE=infinity - -[Install] -WantedBy=multi-user.target' - - echo "$service_config" >"$service_file" - echo "juicity startup service has been configured." -} - -# 配置监听端口 -function set_listen_port() { - while true; do - read -p "请输入监听端口 (默认8443): " new_listen_port - new_listen_port=${new_listen_port:-8443} - - if [[ $new_listen_port =~ ^[1-9][0-9]{0,4}$ && $new_listen_port -le 65535 ]]; then - check_result=$(netstat -tulpn | grep -E "\b${new_listen_port}\b") - if [[ -z "$check_result" ]]; then - echo "监听端口:$new_listen_port" - break - else - echo -e "${RED}错误:端口已被占用,请选择其他端口!${NC}" >&2 - fi - else - echo -e "${RED}错误:端口范围1-65535,请重新输入!${NC}" >&2 - fi - done - - listen_port="$new_listen_port" -} - -# 配置用户名 -function set_user_name() { - while true; do - read -p "请输入用户名 (默认随机生成): " new_user_name - - if [[ -z "$new_user_name" ]]; then - new_user_name=$(sing-box generate rand --base64 6 2>/dev/null || openssl rand -base64 5) - echo "用户名:$new_user_name" - break - elif [[ ! -z "$new_user_name" ]]; then - break - fi - done - - user_names+=("$new_user_name") -} - -# 配置用户密码 -function set_user_password() { - while true; do - read -p "请输入密码(默认随机生成): " new_user_password - - if [[ -z "$new_user_password" ]]; then - new_user_password=$(sing-box generate rand --base64 9 2>/dev/null || openssl rand -base64 9) - echo "密码:$new_user_password" - break - elif [[ ! -z "$new_user_password" ]]; then - break - fi - done - - user_passwords+=("$new_user_password") -} - -# 配置 Shadowsocks 密码 -function set_ss_password() { - while true; do - read -p "请输入 Shadowsocks 密码(默认随机生成): " ss_user_password - - if [[ -z $ss_user_password ]]; then - if [[ $encryption_choice == 1 || $encryption_choice == 2 ]]; then - ss_password=$(sing-box generate rand --base64 32) - echo "Shadowsocks 密码: $ss_password" - else - ss_password=$(sing-box generate rand --base64 16) - echo "Shadowsocks 密码: $ss_password" - fi - - ss_passwords+=("$ss_password") - break - - elif [[ $encryption_choice == 1 || $encryption_choice == 2 ]] && [[ ${#ss_user_password} -eq 32 ]]; then - ss_password="$ss_user_password" - echo "Shadowsocks 密码: $ss_password" - ss_passwords+=("$ss_password") - break - - elif [[ $encryption_choice != 1 && $encryption_choice != 2 ]] && [[ ${#ss_user_password} -eq 16 ]]; then - ss_password="$ss_user_password" - echo "Shadowsocks 密码: $ss_password" - ss_passwords+=("$ss_password") - break - - else - echo -e "${RED}错误:密码长度不符合要求,请重新输入!${NC}" - fi - done -} - -# 配置 ShadowTLS 密码 -function set_stls_password() { - while true; do - read -p "请输入 ShadowTLS 密码(默认随机生成): " stls_user_password - - if [[ -z $stls_user_password ]]; then - if [[ $encryption_choice == 1 || $encryption_choice == 2 ]]; then - stls_password=$(sing-box generate rand --base64 32) - echo "ShadowTLS 密码: $stls_password" - else - stls_password=$(sing-box generate rand --base64 16) - echo "ShadowTLS 密码: $stls_password" - fi - - stls_passwords+=("$stls_password") - break - - elif [[ $encryption_choice == 1 || $encryption_choice == 2 ]] && [[ ${#stls_user_password} -eq 32 ]]; then - stls_password="$stls_user_password" - echo "ShadowTLS 密码: $stls_password" - stls_passwords+=("$stls_password") - break - - elif [[ $encryption_choice != 1 && $encryption_choice != 2 ]] && [[ ${#stls_user_password} -eq 16 ]]; then - stls_password="$stls_user_password" - echo "ShadowTLS 密码: $stls_password" - stls_passwords+=("$stls_password") - break - - else - echo -e "${RED}错误:密码长度不符合要求,请重新输入!${NC}" - fi - done -} - -# 配置上行速率 -function set_up_speed() { - while true; do - read -p "请输入上行速率 (默认50): " new_up_mbps - new_up_mbps=${new_up_mbps:-50} - - if [[ $new_up_mbps =~ ^[0-9]+$ ]]; then - echo "上行速率:$new_up_mbps Mbps" - break - else - echo -e "${RED}错误:请输入数字作为上行速率!${NC}" - fi - done - - up_mbps="$new_up_mbps" -} - -# 配置下行速率 -function set_down_speed() { - while true; do - read -p "请输入下行速率 (默认100): " new_down_mbps - new_down_mbps=${new_down_mbps:-100} - - if [[ $new_down_mbps =~ ^[0-9]+$ ]]; then - echo "下行速率:$new_down_mbps Mbps" - break - else - echo -e "${RED}错误:请输入数字作为下行速率!${NC}" - fi - done - - down_mbps="$new_down_mbps" -} - -# 配置 UUID -function set_uuid() { - while true; do - read -p "请输入UUID(默认随机生成): " new_user_uuid - - if [[ -z "$new_user_uuid" ]]; then - new_user_uuid=$(sing-box generate uuid 2>/dev/null || cat /proc/sys/kernel/random/uuid) - fi - - if [[ $new_user_uuid =~ ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$ ]]; then - echo "UUID:$new_user_uuid" - break - else - echo -e "${RED}无效的UUID格式,请重新输入!${NC}" - fi - done - - user_uuids+=("$new_user_uuid") -} - -# 配置目标端口 -function set_override_port() { - while true; do - read -p "请输入目标端口 (默认8443): " new_override_port - new_override_port=${new_override_port:-8443} - - if [[ $new_override_port =~ ^[1-9][0-9]{0,4}$ && $new_override_port -le 65535 ]]; then - echo "目标端口: $new_override_port" - break - else - echo -e "${RED}错误:端口范围1-65535,请重新输入!${NC}" - fi - done - - override_port="$new_override_port" -} - -# 生成 tag -function generate_unique_tag() { - local config_file="/usr/local/etc/sing-box/config.json" - - while true; do - random_tag=$(head /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1) - tag_label="${random_tag}-in" - - if ! grep -qE "\"tag\":\\s*\"$tag_label\"(,|$)" "$config_file"; then - break - fi - done -} - -# 配置目标地址 -function set_override_address() { - while true; do - read -p "请输入目标地址(IP或域名): " target_address - - if [[ -z "$target_address" ]]; then - echo -e "${RED}错误:目标地址不能为空!${NC}" - continue - fi - - if ( [[ $target_address =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ $(grep -o '\.' <<< "$target_address" | wc -l) -eq 3 ]] ) || - ( [[ $target_address =~ ^[a-fA-F0-9:]+$ ]] && [[ $(grep -o ':' <<< "$target_address" | wc -l) -ge 2 ]] ); then - break - else - resolved_ips=$(host -t A "$target_address" | awk '/has address/ { print $4 }') - - if [[ -n "$resolved_ips" ]] && ( [[ "$resolved_ips" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] || [[ "$resolved_ips" =~ ^[a-fA-F0-9:]+$ ]] ); then - break - else - echo -e "${RED}错误:请输入有效的 IP 地址或域名!${NC}" - fi - fi - done -} - -# 配置 ServerName 列表 -function set_server_name() { - while true; do - read -p "请输入可用的 ServerName 列表 (默认为 nijigen-works.jp): " user_input - - if [[ -z "$user_input" ]]; then - server_name="nijigen-works.jp" - echo "ServerName:$server_name" - break - else - server_name="$user_input" - echo "ServerName:$server_name" - echo "Verifying server's TLS version support..." - - if command -v openssl >/dev/null 2>&1; then - local openssl_output=$(timeout 10s openssl s_client -connect "$server_name:443" -tls1_3 2>&1) - - if [[ $openssl_output == *"TLS_AES_256_GCM_SHA384"* || \ - $openssl_output == *"TLS_AES_128_GCM_SHA256"* || \ - $openssl_output == *"TLS_CHACHA20_POLY1305_SHA256"* || \ - $openssl_output == *"TLS_AES_128_CCM_SHA256"* || \ - $openssl_output == *"TLS_AES_128_CCM_8_SHA256"* ]]; then - break - else - echo -e "${RED}该网址不支持 TLS 1.3,请重新输入!${NC}" - fi - else - echo "OpenSSL is not installed, cannot verify TLS support." - break - fi - fi - done -} - -# 配置目标网站地址 -function set_target_server() { - while true; do - read -p "请输入目标网站地址(默认为 nijigen-works.jp): " user_input - - if [[ -z "$user_input" ]]; then - target_server="nijigen-works.jp" - echo "目标网址:$target_server" - break - else - target_server="$user_input" - echo "目标网址:$target_server" - echo "Verifying server's TLS version support..." - - if command -v openssl >/dev/null 2>&1; then - local openssl_output=$(timeout 10s openssl s_client -connect "$target_server:443" -tls1_3 2>&1) - - if [[ $openssl_output == *"TLS_AES_256_GCM_SHA384"* || \ - $openssl_output == *"TLS_AES_128_GCM_SHA256"* || \ - $openssl_output == *"TLS_CHACHA20_POLY1305_SHA256"* || \ - $openssl_output == *"TLS_AES_128_CCM_SHA256"* || \ - $openssl_output == *"TLS_AES_128_CCM_8_SHA256"* ]]; then - break - else - echo -e "${RED}该目标网站地址不支持 TLS 1.3,请重新输入!${NC}" - fi - else - echo "OpenSSL is not installed, cannot verify TLS support." - break - fi - fi - done -} - -# 获取本机IP地址 -function get_local_ip() { - local local_ip_v4 - local local_ip_v6 - - local_ip_v4=$(curl -s4 https://api.myip.com | grep -o '"ip":"[^"]*' | awk -F ':"' '{print $2}') - - if [[ -n "$local_ip_v4" ]]; then - ip_v4="$local_ip_v4" - else - local_ip_v4=$(curl -s4 icanhazip.com) - - if [[ -n "$local_ip_v4" ]]; then - ip_v4="$local_ip_v4" - fi - fi - - local_ip_v6=$(curl -s6 https://api.myip.com | grep -o '"ip":"[^"]*' | awk -F ':"' '{print $2}') - - if [[ -n "$local_ip_v6" ]]; then - ip_v6="$local_ip_v6" - else - local_ip_v6=$(curl -s6 icanhazip.com) - - if [[ -n "$local_ip_v6" ]]; then - ip_v6="$local_ip_v6" - fi - fi - - if [[ -z "$ip_v4" && -z "$ip_v6" ]]; then - echo -e "${RED}无法获取本机IP地址!${NC}" - fi -} - -# 获取ECH密钥 -function get_ech_keys() { - local input_file="/etc/ssl/private/ech.tmp" - local output_file="/etc/ssl/private/ech.pem" - - sing-box generate ech-keypair [--pq-signature-schemes-enabled] > "$input_file" - - IFS=$'\n' read -d '' -ra lines < "$input_file" - - exec 3>"$output_file" - in_ech_keys_section=false - in_ech_configs_section=false - - for line in "${lines[@]}"; do - if [[ "$line" == *"BEGIN ECH KEYS"* ]]; then - in_ech_keys_section=true - ech_key+=" \"$line\",\n" - elif [[ "$line" == *"END ECH KEYS"* ]]; then - in_ech_keys_section=false - ech_key+=" \"$line\"" - elif [[ "$line" == *"BEGIN ECH CONFIGS"* ]]; then - in_ech_configs_section=true - ech_config+=" \"$line\",\n" - elif [[ "$line" == *"END ECH CONFIGS"* ]]; then - in_ech_configs_section=false - ech_config+=" \"$line\"" - elif [[ "$in_ech_keys_section" == true ]]; then - ech_key+=" \"$line\",\n" - elif [[ "$in_ech_configs_section" == true ]]; then - ech_config+=" \"$line\",\n" - else - echo "\"$line\"," >&3 - fi - done - - exec 3>&- - rm "$input_file" -} - -# 配置域名,并验证其是否绑定本机IP -function get_domain() { - while true; do - read -p "请输入域名(关闭Cloudflare代理): " user_domain - - resolved_ipv4=$(dig +short A "$user_domain" 2>/dev/null) - resolved_ipv6=$(dig +short AAAA "$user_domain" 2>/dev/null) - - if [[ -z $user_domain ]]; then - echo -e "${RED}错误:域名不能为空,请重新输入!${NC}" - else - if [[ ("$resolved_ipv4" == "$ip_v4" && ! -z "$resolved_ipv4") || ("$resolved_ipv6" == "$ip_v6" && ! -z "$resolved_ipv6") ]]; then - break - else - if [[ -z "$resolved_ipv4" && -n "$ip_v4" ]]; then - resolved_ip_v4=$(ping -4 "$user_domain" -c 1 2>/dev/null | sed '1{s/[^(]*(//;s/).*//;q}') - if [[ ("$resolved_ip_v4" == "$ip_v4" && ! -z "$resolved_ip_v4") ]]; then - break - fi - fi - - if [[ -z "$resolved_ipv6" && -n "$ip_v6" ]]; then - resolved_ip_v6=$(ping -6 "$user_domain" -c 1 2>/dev/null | sed '1{s/[^(]*(//;s/).*//;q}') - if [[ ("$resolved_ip_v6" == "$ip_v6" && ! -z "$resolved_ip_v6") ]]; then - break - fi - fi - - echo -e "${RED}错误:域名未绑定本机IP,请重新输入!${NC}" - fi - fi - done - - domain="$user_domain" -} - -# 验证域名是否支持通过 CloudFlare 的 API 申请证书 -function verify_domain() { - new_domain=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_id" \ - -H "Authorization: Bearer $api_token" | jq -r '.result.name') - - if [[ $new_domain =~ \.(tk|ml|ga|gq|cf)$ ]]; then - echo -e "${RED}您的域名为$new_domain,该域名不支持使用 CloudFlare 的 API 申请证书,请选择其他方式申请证书!${NC}" - domain_supported=false - else - while true; do - read -p "请输入主域名前缀(若为空则使用主域名申请证书,不需要在 CloudFlare 添加 DNS 解析记录): " domain_prefix - - if [[ -z "$domain_prefix" ]]; then - domain="$new_domain" - record_name="$domain_prefix" - break - else - domain="$domain_prefix.$new_domain" - record_name="$domain_prefix" - break - fi - done - domain_supported=true - fi -} - -# 配置 DNS 记录 -function set_dns_record() { - if [[ -z "$record_name" ]]; then - name_value="@" - else - name_value="$record_name" - fi - - if [[ -n "$ip_v4" ]]; then - record_content="$ip_v4" - record_type="A" - elif [[ -z "$ip_v4" && -n "$ip_v6" ]]; then - record_content="$ip_v6" - record_type="AAAA" - fi - - curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_Zone_ID/dns_records" \ - -H "Authorization: Bearer $CF_Token" \ - -H "Content-Type: application/json" \ - --data "{\"type\":\"$record_type\",\"name\":\"$name_value\",\"content\":\"$record_content\",\"ttl\":120,\"proxied\":false}" >/dev/null -} - -# 获取 CloudFlare 的限制性 API 令牌 -function get_api_token() { - while true; do - read -p "请输入 CloudFlare 的限制性 API 令牌: " api_token - - if [[ ! $api_token =~ ^[A-Za-z0-9_-]{40}$ ]]; then - echo -e "${RED}API令牌格式不正确,请重新输入!${NC}" - else - export CF_Token="$api_token" - break - fi - done -} - -# 获取 CloudFlare 的区域 ID -function get_zone_id() { - while true; do - read -p "请输入 CloudFlare 的区域 ID: " zone_id - - if [[ ! $zone_id =~ ^[a-z0-9]{32}$ ]]; then - echo -e "${RED}CloudFlare 的区域 ID 格式不正确,请重新输入!${NC}" - else - export CF_Zone_ID="$zone_id" - break - fi - done -} - -# 获取 CloudFlare 的登录邮箱 -function get_api_email() { - while true; do - read -p "请输入 CloudFlare 的登录邮箱: " api_email - - if [[ ! $api_email =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$ ]]; then - echo -e "${RED}邮箱格式不正确,请重新输入!${NC}" - else - export CF_Email="$api_email" - break - fi - done -} - -# 配置伪装网址 -function set_fake_domain() { - while true; do - read -p "请输入伪装网址(默认: www.zcloudisk.com): " fake_domain - fake_domain=${fake_domain:-"www.zcloudisk.com"} - - if curl --output /dev/null --silent --head --fail "$fake_domain"; then - echo "伪装网址: $fake_domain" - break - else - echo -e "${RED}伪装网址无效或不可用,请重新输入!${NC}" - fi - done -} - -# 设置 PEM 证书位置 -function set_certificate_path() { - while true; do - read -p "请输入 PEM 证书位置: " certificate_path_input - - if [[ ! -f "$certificate_path_input" ]]; then - echo -e "${RED}错误:证书文件不存在,请重新输入!${NC}" - continue - fi - - certificate_file=$(basename "$certificate_path_input") - allowed_extensions=("crt" "pem") - - if [[ ! "${allowed_extensions[@]}" =~ "${certificate_file##*.}" ]]; then - echo -e "${RED}错误:不支持的证书格式,请配置.crt或.pem格式的证书文件!${NC}" - continue - fi - - certificate_path="$certificate_path_input" - break - done -} - -# 设置 PEM 私钥位置 -function set_private_key_path() { - while true; do - read -p "请输入 PEM 私钥位置: " private_key_path_input - - if [[ ! -f "$private_key_path_input" ]]; then - echo -e "${RED}错误:私钥文件不存在,请重新输入!${NC}" - continue - fi - - private_key_file=$(basename "$private_key_path_input") - allowed_extensions=("key" "pem") - - if [[ ! "${allowed_extensions[@]}" =~ "${private_key_file##*.}" ]]; then - echo -e "${RED}错误:不支持的私钥格式,请配置.key或.pem格式的私钥文件!${NC}" - continue - fi - - private_key_path="$private_key_path_input" - break - done -} - -# 申请 SSL 证书 -function apply_certificate() { - certificate_path="/etc/ssl/private/"$domain".crt" - private_key_path="/etc/ssl/private/"$domain".key" - local has_ipv4=false - local ca_servers=("letsencrypt" "zerossl") - local return_to_menu=false - - if [[ -n "$ip_v4" ]]; then - has_ipv4=true - fi - - echo "Requesting a certificate..." - curl -s https://get.acme.sh | sh -s email=example@gmail.com 2>&1 | tail -n 1 - alias acme.sh=~/.acme.sh/acme.sh - - for ca_server in "${ca_servers[@]}"; do - echo "Requesting a certificate from $ca_server..." - ~/.acme.sh/acme.sh --set-default-ca --server "$ca_server" - - if $has_ipv4; then - result=$(~/.acme.sh/acme.sh --issue -d "$domain" --standalone -k ec-256 2>&1) - else - result=$(~/.acme.sh/acme.sh --issue -d "$domain" --standalone -k ec-256 --listen-v6 2>&1) - fi - - if [[ $result == *"force"* ]]; then - if $has_ipv4; then - result=$(~/.acme.sh/acme.sh --issue -d "$domain" --standalone -k ec-256 --force 2>&1) - else - result=$(~/.acme.sh/acme.sh --issue -d "$domain" --standalone -k ec-256 --listen-v6 --force 2>&1) - fi - fi - - if [[ $result == *"log"* || $result == *"debug"* || $result == *"error"* ]]; then - echo -e "${RED}$result ${NC}" - continue - fi - - if [[ $? -eq 0 ]]; then - echo "Installing the certificate..." - ~/.acme.sh/acme.sh --install-cert -d "$domain" --ecc --key-file "$private_key_path" --fullchain-file "$certificate_path" - break - else - echo -e "${RED}Failed to obtain a certificate from $ca_server!${NC}" - return_to_menu=true - fi - done - - if [[ "$return_to_menu" == true ]]; then - echo -e "${RED}证书申请失败,请使用其它方法申请证书!${NC}" - return 1 - fi -} - -# 申请 API 证书 -function Apply_api_certificate() { - certificate_path="/etc/ssl/private/"$domain".crt" - private_key_path="/etc/ssl/private/"$domain".key" - local has_ipv4=false - local ca_servers=("letsencrypt" "zerossl") - - if [[ -n "$ip_v4" ]]; then - has_ipv4=true - fi - - echo "Requesting a certificate..." - curl -s https://get.acme.sh | sh -s email=example@gmail.com 2>&1 | tail -n 1 - alias acme.sh=~/.acme.sh/acme.sh - - for ca_server in "${ca_servers[@]}"; do - echo "Requesting a certificate from $ca_server..." - ~/.acme.sh/acme.sh --set-default-ca --server "$ca_server" - - if $has_ipv4; then - result=$(~/.acme.sh/acme.sh --issue --dns dns_cf -d "$domain" -k ec-256 2>&1) - else - result=$(~/.acme.sh/acme.sh --issue --dns dns_cf -d "$domain" -k ec-256 --listen-v6 2>&1) - fi - - if [[ $result == *"log"* || $result == *"debug"* || $result == *"error"* || $result == *"force"* ]]; then - echo -e "${RED}$result ${NC}" - return_to_menu=true - continue - fi - - if [[ $? -eq 0 ]]; then - echo "Installing the certificate..." - ~/.acme.sh/acme.sh --install-cert -d "$domain" --ecc --key-file "$private_key_path" --fullchain-file "$certificate_path" - break - else - echo -e "${RED}Failed to obtain a certificate from $ca_server!${NC}" - return_to_menu=true - fi - done - - if [[ "$return_to_menu" == true ]]; then - echo -e "${RED}证书申请失败,请使用其它方法申请证书!${NC}" - return 1 - fi -} - -# 重新申请证书 -function Reapply_certificates() { - local tls_info_file="/usr/local/etc/sing-box/tls_info.json" - local has_ipv4=false - - if [[ -n "$ip_v4" ]]; then - has_ipv4=true - fi - - if ! command -v acme.sh &>/dev/null; then - curl -s https://get.acme.sh | sh -s email=example@gmail.com - fi - - alias acme.sh=~/.acme.sh/acme.sh - echo "Setting CA server to Let's Encrypt..." - ~/.acme.sh/acme.sh --set-default-ca --server "letsencrypt" - - jq -c '.[]' "$tls_info_file" | while read -r tls_info; do - server_name=$(echo "$tls_info" | jq -r '.server_name') - key_path=$(echo "$tls_info" | jq -r '.key_path') - certificate_path=$(echo "$tls_info" | jq -r '.certificate_path') - - echo "Requesting certificate for $server_name..." - result=$( - if $has_ipv4; then - ~/.acme.sh/acme.sh --issue --dns dns_cf -d "$server_name" -k ec-256 --force - else - ~/.acme.sh/acme.sh --issue --dns dns_cf -d "$server_name" -k ec-256 --listen-v6 --force - fi - ) - - if [[ "$result" =~ "Cert success." ]]; then - echo "Certificate for $server_name has been applied using Cloudflare DNS verification." - else - echo "Cloudflare DNS verification failed for $server_name. Trying standalone verification..." - result=$( - if $has_ipv4; then - ~/.acme.sh/acme.sh --issue -d "$server_name" --standalone --force - else - ~/.acme.sh/acme.sh --issue -d "$server_name" --standalone --listen-v6 --force - fi - ) - if [[ "$result" =~ "BEGIN CERTIFICATE" && "$result" =~ "END CERTIFICATE" ]]; then - echo "Certificate for $server_name has been applied using Let's Encrypt CA." - else - echo "Failed to obtain certificate for $server_name using standalone verification as well." - return 1 - fi - fi - - ~/.acme.sh/acme.sh --install-cert -d "$server_name" --ecc --key-file "$key_path" --fullchain-file "$certificate_path" - echo "Certificate for $server_name has been installed." - done - - rm -f "$tls_info_file" -} - -# 生成公私钥 -function generate_private_key() { - while true; do - read -p "请输入私钥 (默认随机生成私钥): " local_private_key - - if [[ -z "$local_private_key" ]]; then - local keypair_output=$(sing-box generate reality-keypair) - local_private_key=$(echo "$keypair_output" | awk -F: '/PrivateKey/{gsub(/ /, "", $2); print $2}') - local_public_key=$(echo "$keypair_output" | awk -F: '/PublicKey/{gsub(/ /, "", $2); print $2}') - echo "private_key:$local_private_key" - echo "public_key:$local_public_key" - break - else - if [[ "$local_private_key" =~ ^[A-Za-z0-9_\-]{43}$ ]]; then - read -p "请输入公钥: " local_public_key - - if ! [[ "$local_public_key" =~ ^[A-Za-z0-9_\-]{43}$ ]]; then - echo -e "${RED}无效的公钥,请重新输入!${NC}" - else - break - fi - else - echo -e "${RED}无效的私钥,请重新输入!${NC}" - fi - fi - done - - public_key="$local_public_key" - private_key="$local_private_key" -} - -# 配置自签名证书 -function create_self_signed_cert() { - while true; do - read -p "请输入要用于自签名证书的域名(默认为 bing.com): " user_domain - domain_name=${user_domain:-"bing.com"} - - if curl --output /dev/null --silent --head --fail "$domain_name"; then - openssl req -x509 -nodes -newkey ec:<(openssl ecparam -name prime256v1) \ - -keyout /etc/ssl/private/$domain_name.key \ - -out /etc/ssl/private/$domain_name.crt \ - -subj "/CN=$domain_name" -days 36500 - - chmod 777 /etc/ssl/private/$domain_name.key - chmod 777 /etc/ssl/private/$domain_name.crt - break - else - echo -e "${RED}无效的域名或域名不可用,请输入有效的域名!${NC}" - fi - done - - certificate_path="/etc/ssl/private/$domain_name.crt" - private_key_path="/etc/ssl/private/$domain_name.key" -} - -# 获取 WARP 配置参数 -function generate_warp_info() { - local key priv_key pub_key temp_file ser_v4 ser_v6 ser_port local_v4 local_v6 publ_key res_value - - key=$(openssl genpkey -algorithm X25519 | openssl pkey -text -noout) - priv_key=$(echo "$key" | grep -A 3 "priv:" | tail -n +2 | tr -d ' \n:' | xxd -r -p | base64) - pub_key=$(echo "$key" | grep -A 3 "pub:" | tail -n +2 | tr -d ' \n:' | xxd -r -p | base64) - - temp_file=$(mktemp) - curl -sL --tlsv1.3 -X POST 'https://api.cloudflareclient.com/v0a2158/reg' \ - -H 'CF-Client-Version: a-8.3-1190' \ - -H 'Content-Type: application/json' \ - -d '{ - "key":"'${pub_key}'", - "tos":"'$(date +"%Y-%m-%dT%H:%M:%S.000Z")'" - }' > "$temp_file" - - ser_v4=$(jq -r '.config.peers[0].endpoint.v4' < "$temp_file" | sed 's/:0$//') - ser_v6=$(jq -r '.config.peers[0].endpoint.v6' < "$temp_file" | sed 's/:0$//') - ser_port=$(jq -r '.config.peers[0].endpoint.ports[0]' < "$temp_file") - local_v4=$(jq -r '.config.interface.addresses.v4 + "/32"' < "$temp_file") - local_v6=$(jq -r '.config.interface.addresses.v6 + "/128"' < "$temp_file") - publ_key=$(jq -r '.config.peers[0].public_key' < "$temp_file") - res_value=$(jq -r '.config.client_id' < "$temp_file" | base64 -d | xxd -p | tr -d '\n' | sed 's/../& /g' | tr ' ' '\n' | awk '{printf "%d, ", "0x"$1}' | sed 's/, $//' | sed 's/^/[/' | sed 's/$/]/') - - warp_output_file=$(mktemp --suffix=.json) - awk -v ser_v4="$ser_v4" -v ser_v6="$ser_v6" -v ser_port="$ser_port" -v local_v4="$local_v4" -v local_v6="$local_v6" -v priv_key="$priv_key" -v publ_key="$publ_key" -v res_value="$res_value" 'BEGIN { - print "{\n \"server\": {\n \"v4\": \"" ser_v4 "\",\n \"v6\": \"" ser_v6 "\"\n },\n \"server_port\": " ser_port ",\n \"local_address\": {\n \"v4\": \"" local_v4 "\",\n \"v6\": \"" local_v6 "\"\n },\n \"private_key\": \"" priv_key "\",\n \"public_key\": \"" publ_key "\",\n \"reserved\": " res_value ",\n \"mtu\": 1280\n}" - }' > "$warp_output_file" - rm "$temp_file" -} - -# 检测并安装 iptables 及相关服务 -function check_iptables_installed() { - local os_name=$(uname -s) - export PATH=$PATH:/usr/sbin:/sbin - - if [[ "$os_name" == "Linux" ]]; then - if [[ -f /etc/debian_version ]]; then - if ! command -v iptables &> /dev/null; then - echo "Installing iptables..." - DEBIAN_FRONTEND=noninteractive apt-get install -y iptables &> /dev/null - fi - - if ! command -v netfilter-persistent &> /dev/null; then - echo "Installing netfilter-persistent..." - DEBIAN_FRONTEND=noninteractive apt-get install -y netfilter-persistent &> /dev/null - fi - - if [[ ! -f /etc/init.d/iptables-persistent ]]; then - echo "Installing iptables-persistent..." - DEBIAN_FRONTEND=noninteractive apt-get install -y iptables-persistent &> /dev/null - fi - - [[ ! -f /etc/iptables/rules.v4 ]] && touch /etc/iptables/rules.v4 - [[ ! -f /etc/iptables/rules.v6 ]] && touch /etc/iptables/rules.v6 - netfilter-persistent save &> /dev/null - command -v nft &> /dev/null && echo "System uses nftables backend." - elif [[ -f /etc/redhat-release ]]; then - if ! command -v iptables &> /dev/null; then - echo "Installing iptables-services..." - if command -v dnf &> /dev/null; then - dnf install -y iptables-services - else - yum install -y iptables-services - fi - fi - - command -v service &> /dev/null && service iptables save &> /dev/null - command -v service &> /dev/null && service ip6tables save &> /dev/null - systemctl enable iptables &> /dev/null - systemctl enable ip6tables &> /dev/null - - command -v nft &> /dev/null && echo "System uses nftables backend." - fi - - sed -i '/^net.ipv4.ip_forward/d' /etc/sysctl.conf - sed -i '/^net.ipv6.conf.all.forwarding/d' /etc/sysctl.conf - echo -e "net.ipv4.ip_forward = 1\nnet.ipv6.conf.all.forwarding = 1\nnet.ipv6.conf.default.forwarding = 1" >> /etc/sysctl.conf - sysctl -p &> /dev/null - fi -} - - -# 设置端口范围 -function get_port_range() { - while true; do - read -p "请输入端口跳跃的起始端口 (默认:2080): " start_port - start_port=${start_port:-2080} - - if [[ $start_port =~ ^[1-9][0-9]{0,4}$ && $start_port -le 65535 ]]; then - break - else - echo -e "${RED}错误:端口范围 1-65535,请重新输入!${NC}" >&2 - fi - done - - while true; do - read -p "请输入端口跳跃的终止端口 (默认:3000): " end_port - end_port=${end_port:-3000} - - if [[ $end_port =~ ^[1-9][0-9]{0,4}$ && $end_port -le 65535 ]]; then - if [[ "$end_port" -le "$start_port" ]]; then - echo -e "${RED}错误:终止端口必须大于起始端口!${NC}" >&2 - return 1 - fi - break - else - echo -e "${RED}错误:端口范围 1-65535,请重新输入!${NC}" >&2 - fi - done -} - -# 是否开启端口跳跃 -function ask_enable_port_forwarding() { - while true; do - read -p "是否开启端口跳跃功能?(Y/N,默认为Y): " choice - - if [[ -z "$choice" || "$choice" == "y" || "$choice" == "Y" ]]; then - check_iptables_installed - get_port_range - set_port_forwarding - break - elif [[ "$choice" == "n" || "$choice" == "N" ]]; then - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done -} - -# 设置 iptables DNAT 规则 -function set_port_forwarding() { - local wan_iface - wan_iface=$(ip route | grep '^default' | awk '{print $5}') - if [[ -z "$wan_iface" ]]; then - echo "Error: Could not detect WAN interface." - return 1 - fi - - echo "Setting port forwarding from $start_port:$end_port to $listen_port on interface $wan_iface..." - - if command -v iptables &> /dev/null; then - iptables -t nat -A PREROUTING -i "$wan_iface" -p udp --dport "$start_port":"$end_port" -j DNAT --to-destination ":$listen_port" &> /dev/null - iptables -t nat -A POSTROUTING -p udp --dport $listen_port -j MASQUERADE &> /dev/null - fi - - if command -v ip6tables &> /dev/null; then - if ip6tables -t nat -L &> /dev/null; then - ip6tables -t nat -A PREROUTING -i "$wan_iface" -p udp --dport "$start_port":"$end_port" -j DNAT --to-destination ":$listen_port" &> /dev/null - ip6tables -t nat -A POSTROUTING -p udp --dport $listen_port -j MASQUERADE &> /dev/null - else - echo "IPv6 NAT not supported, skipping IPv6 port forwarding." - fi - fi - - if command -v nft &> /dev/null; then - nft list table ip nat &> /dev/null || nft add table ip nat - nft list table ip6 nat &> /dev/null || nft add table ip6 nat - fi - - if command -v netfilter-persistent &> /dev/null; then - netfilter-persistent save &> /dev/null - elif command -v service &> /dev/null; then - service iptables save &> /dev/null - service ip6tables save &> /dev/null - fi - - echo "Port forwarding setup completed." -} - -# 选择加密类型 -function select_encryption_method() { - while true; do - read -p "请选择加密方式(默认1): -1). 2022-blake3-chacha20-poly1305 -2). 2022-blake3-aes-256-gcm -3). 2022-blake3-aes-128-gcm -4). xchacha20-ietf-poly1305 -5). chacha20-ietf-poly1305 -6). aes-256-gcm -7). aes-192-gcm -8). aes-128-gcm -请选择[1-8]: " encryption_choice - - encryption_choice=${encryption_choice:-1} - - case $encryption_choice in - 1) - ss_method="2022-blake3-chacha20-poly1305" - ss_password=$(sing-box generate rand --base64 32) - shadowtls_password=$(sing-box generate rand --base64 32) - break - ;; - 2) - ss_method="2022-blake3-aes-256-gcm" - ss_password=$(sing-box generate rand --base64 32) - shadowtls_password=$(sing-box generate rand --base64 32) - break - ;; - 3) - ss_method="2022-blake3-aes-128-gcm" - ss_password=$(sing-box generate rand --base64 16) - shadowtls_password=$(sing-box generate rand --base64 16) - break - ;; - 4) - ss_method="xchacha20-ietf-poly1305" - ss_password=$(sing-box generate rand --base64 16) - shadowtls_password=$(sing-box generate rand --base64 16) - break - ;; - 5) - ss_method="chacha20-ietf-poly1305" - ss_password=$(sing-box generate rand --base64 16) - shadowtls_password=$(sing-box generate rand --base64 16) - break - ;; - 6) - ss_method="aes-256-gcm" - ss_password=$(sing-box generate rand --base64 16) - shadowtls_password=$(sing-box generate rand --base64 16) - break - ;; - 7) - ss_method="aes-192-gcm" - ss_password=$(sing-box generate rand --base64 16) - shadowtls_password=$(sing-box generate rand --base64 16) - break - ;; - 8) - ss_method="aes-128-gcm" - ss_password=$(sing-box generate rand --base64 16) - shadowtls_password=$(sing-box generate rand --base64 16) - break - ;; - *) - echo -e "${RED}错误:无效的选择,请重新输入!${NC}" - ;; - esac - done -} - -# 选择要解锁的项目 -function select_unlocked_items() { - while true; do - read -p "请选择要解锁的项目(支持多选): -1). ChatGPT -2). Netflix -3). Disney+ -4). YouTube -请选择[1-4]: " choices - - if [[ "$choices" =~ ^[1234]+$ ]]; then - selected=($(echo "$choices" | sed 's/./& /g')) - break - else - echo -e "${RED}错误:无效的选择,请重新输入!${NC}" - fi - done -} - -# 更新规则集 -function update_rule_set() { - for choice in "${selected[@]}"; do - case $choice in - 1) - rule_set+=("\"geosite-openai\"") - ;; - 2) - rule_set+=("\"geosite-netflix\"") - ;; - 3) - rule_set+=("\"geosite-disney\"") - ;; - 4) - rule_set+=("\"geosite-youtube\"") - ;; - *) - echo -e "${RED}无效的选择: $choice${NC}" - ;; - esac - done -} - -# 配置拥塞控制算法 -function select_congestion_control() { - local default_congestion_control="bbr" - - while true; do - read -p "请选择拥塞控制算法 (默认$default_congestion_control): -1). bbr -2). cubic -3). new_reno -请选择[1-3]: " congestion_control - - case $congestion_control in - 1) - congestion_control="bbr" - break - ;; - 2) - congestion_control="cubic" - break - ;; - 3) - congestion_control="new_reno" - break - ;; - "") - congestion_control=$default_congestion_control - break - ;; - *) - echo -e "${RED}错误:无效的选择,请重新输入!${NC}" - ;; - esac - done -} - -# 选择证书来源 -function select_certificate_option() { - local certificate_option - local domain_supported=false - local return_to_menu=false - - while true; do - read -p "请选择证书来源 (默认1): -1). 自签证书 -2). 监听80端口申请证书(standalone模式) -3). cloudflare API 申请证书(DNS API模式) -4). 自定义证书路径 -请选择[1-4]: " certificate_option - - certificate_option=${certificate_option:-1} - - case $certificate_option in - 1) - if $disable_option; then - echo -e "${RED}NaiveProxy节点不支持自签证书,请使用acme申请证书!${NC}" - continue - fi - check_firewall_configuration - create_self_signed_cert - break - ;; - 2) - get_local_ip - get_domain - check_firewall_configuration - apply_certificate - if [[ "$return_to_menu" == true ]]; then - return_to_menu=false - continue - fi - break - ;; - 3) - get_local_ip - get_api_token - get_zone_id - get_api_email - verify_domain - set_dns_record - check_firewall_configuration - if [[ "$domain_supported" == false ]]; then - continue - else - Apply_api_certificate - if [[ "$return_to_menu" == true ]]; then - return_to_menu=false - continue - fi - break - fi - ;; - 4) - get_local_ip - get_domain - check_firewall_configuration - set_certificate_path - set_private_key_path - break - ;; - *) - echo -e "${RED}错误:无效的选择,请重新输入!${NC}" - ;; - esac - done -} - -# 选择 VMess 节点类型 -function select_vmess_type() { - while true; do - read -p "请选择节点类型(默认1): -1). VMess+TCP -2). VMess+WebSocket -3). VMess+gRPC -4). VMess+HTTPUpgrade -5). VMess+TCP+TLS -6). VMess+WebSocket+TLS -7). VMess+H2C+TLS -8). VMess+gRPC+TLS -9). VMess+HTTPUpgrade+TLS -请选择 [1-9]: " node_type - - case $node_type in - "" | 1) - tls_enabled=false - break - ;; - 2) - transport_ws=true - tls_enabled=false - break - ;; - 3) - transport_grpc=true - tls_enabled=false - break - ;; - 4) - transport_httpupgrade=true - tls_enabled=false - break - ;; - 5) - tls_enabled=true - break - ;; - 6) - transport_ws=true - tls_enabled=true - break - ;; - 7) - transport_http=true - tls_enabled=true - break - ;; - 8) - transport_grpc=true - tls_enabled=true - break - ;; - 9) - transport_httpupgrade=true - tls_enabled=true - break - ;; - *) - echo -e "${RED}无效的选择,请重新输入!${NC}" - ;; - esac - done -} - -# 选择 VLESS 节点类型 -function select_vless_type() { - while true; do - read -p "请选择节点类型 (默认1): -1). VLESS+TCP -2). VLESS+WebSocket -3). VLESS+gRPC -4). VLESS+HTTPUpgrade -5). VLESS+Vision+REALITY -6). VLESS+H2C+REALITY -7). VLESS+gRPC+REALITY -请选择[1-7]: " flow_option - - case $flow_option in - "" | 1) - flow_type="" - break - ;; - 2) - flow_type="" - transport_ws=true - break - ;; - 3) - flow_type="" - transport_grpc=true - break - ;; - 4) - flow_type="" - transport_httpupgrade=true - break - ;; - 5) - flow_type="xtls-rprx-vision" - reality_enabled=true - break - ;; - 6) - flow_type="" - transport_http=true - reality_enabled=true - break - ;; - 7) - flow_type="" - transport_grpc=true - reality_enabled=true - break - ;; - *) - echo -e "${RED}错误的选项,请重新输入!${NC}" >&2 - ;; - esac - done -} - -# 选择 Trojan 节点类型 -function select_trojan_type() { - while true; do - read -p "请选择节点类型(默认1): -1). Trojan+TCP -2). Trojan+WebSocket -3). Trojan+gRPC -4). Trojan+HTTPUpgrade -5). Trojan+TCP+TLS -6). Trojan+WebSocket+TLS -7). Trojan+H2C+TLS -8). Trojan+gRPC+TLS -9). Trojan+HTTPUpgrade+TLS -请选择 [1-9]: " setup_type - - case $setup_type in - "" | 1) - tls_enabled=false - break - ;; - 2) - transport_ws=true - tls_enabled=false - break - ;; - 3) - transport_grpc=true - tls_enabled=false - break - ;; - 4) - transport_httpupgrade=true - tls_enabled=false - break - ;; - 5) - tls_enabled=true - break - ;; - 6) - transport_ws=true - tls_enabled=true - break - ;; - 7) - transport_http=true - tls_enabled=true - break - ;; - 8) - transport_grpc=true - tls_enabled=true - break - ;; - 9) - transport_httpupgrade=true - tls_enabled=true - break - ;; - *) - echo -e "${RED}无效的选择,请重新输入!${NC}" - ;; - esac - done -} - -# 设置 Short_Id -function set_short_id() { - while true; do - read -p "请输入 Short_Id (用于区分不同的客户端,默认随机生成): " short_id - - if [[ -z "$short_id" ]]; then - short_id=$(openssl rand -hex 8) - echo "Short_Id:$short_id" - break - elif [[ "$short_id" =~ ^[0-9a-fA-F]{2,16}$ ]]; then - echo "Short_Id:$short_id" - break - else - echo "错误:请输入两到八位的十六进制字符串!" - fi - done - - short_ids+=("$short_id") -} - -# 设置多个 Short_Id -function set_short_ids() { - while true; do - set_short_id - - for ((i=0; i<${#short_ids[@]}; i++)); do - short_id="${short_ids[$i]}" - done - - while true; do - read -p "是否继续添加 short id?(Y/N,默认N): " -e choice - - if [[ -z "$choice" ]]; then - choice="N" - fi - - if [[ "$choice" == "N" || "$choice" == "n" ]]; then - short_Ids+="\n \"$short_id\"" - return - elif [[ "$choice" == "Y" || "$choice" == "y" ]]; then - short_Ids+="\n \"$short_id\"," - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done - done -} - -# 添加多个用户到 TUIC 配置 -function tuic_multiple_users() { - while true; do - set_user_name - set_user_password - set_uuid - - for ((i=0; i<${#user_names[@]}; i++)); do - user_name="${user_names[$i]}" - user_uuid="${user_uuids[$i]}" - user_password="${user_passwords[$i]}" - done - - while true; do - read -p "是否继续添加用户?(Y/N,默认N): " -e add_multiple_users - - if [[ -z "$add_multiple_users" ]]; then - add_multiple_users="N" - fi - - if [[ "$add_multiple_users" == "N" || "$add_multiple_users" == "n" ]]; then - users+="\n {\n \"name\": \"$user_name\",\n \"uuid\": \"$user_uuid\",\n \"password\": \"$user_password\"\n }" - return - elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then - users+="\n {\n \"name\": \"$user_name\",\n \"uuid\": \"$user_uuid\",\n \"password\": \"$user_password\"\n }," - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done - done -} - -# 添加多个用户到 VMess 配置 -function vmess_multiple_users() { - while true; do - set_uuid - - for ((i=0; i<${#user_uuids[@]}; i++)); do - user_uuid="${user_uuids[$i]}" - done - - while true; do - read -p "是否继续添加用户?(Y/N,默认N): " -e add_multiple_users - - if [[ -z "$add_multiple_users" ]]; then - add_multiple_users="N" - fi - - if [[ "$add_multiple_users" == "N" || "$add_multiple_users" == "n" ]]; then - users+="\n {\n \"uuid\": \"$user_uuid\",\n \"alterId\": 0\n }" - return - elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then - users+="\n {\n \"uuid\": \"$user_uuid\",\n \"alterId\": 0\n }," - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done - done -} - -# 添加多个用户到 VLESS 配置 -function vless_multiple_users() { - while true; do - set_uuid - - for ((i=0; i<${#user_uuids[@]}; i++)); do - user_uuid="${user_uuids[$i]}" - done - - while true; do - read -p "是否继续添加用户?(Y/N,默认N): " -e add_multiple_users - - if [[ -z "$add_multiple_users" ]]; then - add_multiple_users="N" - fi - - if [[ "$add_multiple_users" == "N" || "$add_multiple_users" == "n" ]]; then - users+="\n {\n \"uuid\": \"$user_uuid\",\n \"flow\": \"$flow_type\"\n }" - return - elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then - users+="\n {\n \"uuid\": \"$user_uuid\",\n \"flow\": \"$flow_type\"\n }," - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done - done -} - -# 添加多个用户到 SOCKS、NaiveProxy 配置 -function socks_naive_multiple_users() { - while true; do - set_user_name - set_user_password - - for ((i=0; i<${#user_names[@]}; i++)); do - user_name="${user_names[$i]}" - user_password="${user_passwords[$i]}" - done - - while true; do - read -p "是否继续添加用户?(Y/N,默认N): " -e add_multiple_users - - if [[ -z "$add_multiple_users" ]]; then - add_multiple_users="N" - fi - - if [[ "$add_multiple_users" == "N" || "$add_multiple_users" == "n" ]]; then - users+="\n {\n \"username\": \"$user_name\",\n \"password\": \"$user_password\"\n }" - return - elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then - users+="\n {\n \"username\": \"$user_name\",\n \"password\": \"$user_password\"\n }," - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done - done -} - -# 添加多个用户到 AnyTLS 配置 -function anytls_multiple_users() { - while true; do - set_user_name - set_user_password - - for ((i=0; i<${#user_names[@]}; i++)); do - user_name="${user_names[$i]}" - user_password="${user_passwords[$i]}" - done - - while true; do - read -p "是否继续添加用户?(Y/N,默认N): " -e add_multiple_users - - if [[ -z "$add_multiple_users" ]]; then - add_multiple_users="N" - fi - - if [[ "$add_multiple_users" == "N" || "$add_multiple_users" == "n" ]]; then - users+="\n {\n \"name\": \"$user_name\",\n \"password\": \"$user_password\"\n }" - return - elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then - users+="\n {\n \"name\": \"$user_name\",\n \"password\": \"$user_password\"\n }," - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done - done -} - -# 添加多个用户到 Hysteria 配置 -function hysteria_multiple_users() { - while true; do - set_user_name - set_user_password - - for ((i=0; i<${#user_names[@]}; i++)); do - user_name="${user_names[$i]}" - user_password="${user_passwords[$i]}" - done - - while true; do - read -p "是否继续添加用户?(Y/N,默认N): " -e add_multiple_users - - if [[ -z "$add_multiple_users" ]]; then - add_multiple_users="N" - fi - - if [[ "$add_multiple_users" == "N" || "$add_multiple_users" == "n" ]]; then - users+="\n {\n \"name\": \"$user_name\",\n \"auth_str\": \"$user_password\"\n }" - return - elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then - users+="\n {\n \"name\": \"$user_name\",\n \"auth_str\": \"$user_password\"\n }," - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done - done -} - -# 添加多个用户到 Hysteria2 配置 -function hy2_multiple_users() { - while true; do - set_user_name - set_user_password - - for ((i=0; i<${#user_names[@]}; i++)); do - user_name="${user_names[$i]}" - user_password="${user_passwords[$i]}" - done - - while true; do - read -p "是否继续添加用户?(Y/N,默认N): " -e add_multiple_users - - if [[ -z "$add_multiple_users" ]]; then - add_multiple_users="N" - fi - - if [[ "$add_multiple_users" == "N" || "$add_multiple_users" == "n" ]]; then - users+="\n {\n \"name\": \"$user_name\",\n \"password\": \"$user_password\"\n }" - return - elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then - users+="\n {\n \"name\": \"$user_name\",\n \"password\": \"$user_password\"\n }," - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done - done -} - -# 添加多个用户到 Trojan 配置 -function trojan_multiple_users() { - while true; do - set_user_password - - for ((i=0; i<${#user_passwords[@]}; i++)); do - user_password="${user_passwords[$i]}" - done - - while true; do - read -p "是否继续添加用户?(Y/N,默认N): " -e add_multiple_users - - if [[ -z "$add_multiple_users" ]]; then - add_multiple_users="N" - fi - - if [[ "$add_multiple_users" == "N" || "$add_multiple_users" == "n" ]]; then - users+="\n {\n \"password\": \"$user_password\"\n }" - return - elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then - users+="\n {\n \"password\": \"$user_password\"\n }," - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done - done -} - -# 添加多个用户到 ShadowTLS 配置 -function shadowtls_multiple_users() { - while true; do - set_user_name - set_stls_password - - for ((i=0; i<${#user_names[@]}; i++)); do - user_name="${user_names[$i]}" - stls_password="${stls_passwords[$i]}" - done - - while true; do - read -p "是否继续添加用户?(Y/N,默认N): " -e add_multiple_users - - if [[ -z "$add_multiple_users" ]]; then - add_multiple_users="N" - fi - - if [[ "$add_multiple_users" == "N" || "$add_multiple_users" == "n" ]]; then - users+="\n {\n \"name\": \"$user_name\",\n \"password\": \"$stls_password\"\n }" - return - elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then - users+="\n {\n \"name\": \"$user_name\",\n \"password\": \"$stls_password\"\n }," - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done - done -} - -# 生成 transport 配置 -function generate_transport_config() { - if [[ "$transport_ws" = true ]]; then - read -p "请输入 ws 路径 (默认随机生成): " transport_path_input - transport_path=${transport_path_input:-/$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 8)} - - if [[ ! "$transport_path" =~ ^/ ]]; then - transport_path="/$transport_path" - fi - - transport_config="\n \"transport\": {\n \"type\": \"ws\",\n \"path\": \"$transport_path\",\n \"max_early_data\": 2048,\n \"early_data_header_name\": \"Sec-WebSocket-Protocol\"\n }," - - elif [[ "$transport_httpupgrade" = true ]]; then - transport_path=${transport_path_input:-/$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 8)} - - if [[ ! "$transport_path" =~ ^/ ]]; then - transport_path="/$transport_path" - fi - - transport_config="\n \"transport\": {\n \"type\": \"httpupgrade\",\n \"path\": \"$transport_path\"\n }," - - elif [[ "$transport_grpc" = true ]]; then - service_name=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 8) - transport_config="\n \"transport\": {\n \"type\": \"grpc\",\n \"service_name\": \"$service_name\"\n }," - - elif [[ "$transport_http" = true ]]; then - transport_config="\n \"transport\": {\n \"type\": \"http\"\n }," - - else - transport_config="" - fi -} - -# 生成 TLS 配置 -function generate_tls_config() { - if [[ "$tls_enabled" = true ]]; then - set_ech_config - select_certificate_option - fi - - if [[ -z "$domain_name" ]]; then - if [[ -n "$domain" ]]; then - server_name="$domain" - fi - else - server_name="$domain_name" - fi - - if [[ "$tls_enabled" = true ]]; then - tls_config=",\n \"tls\": {\n \"enabled\": true,\n \"server_name\": \"$server_name\",\n \"certificate_path\": \"$certificate_path\",\n \"key_path\": \"$private_key_path\"$ech_server_config\n }" - fi -} - -# 配置 ECH -function set_ech_config() { - while true; do - read -p "是否开启 ECH?(Y/N,默认N):" enable_ech - enable_ech="${enable_ech:-N}" - - if [[ "$enable_ech" == "y" || "$enable_ech" == "Y" ]]; then - get_ech_keys - enable_ech=true - ech_server_config=",\n \"ech\": {\n \"enabled\": true,\n \"key\": [\n$ech_key\n ]\n }" - break - elif [[ "$enable_ech" == "n" || "$enable_ech" == "N" ]]; then - enable_ech=false - ech_server_config="" - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done -} - -# 生成 Reality 配置 -function generate_reality_config() { - if [[ "$reality_enabled" = true ]]; then - set_server_name - set_target_server - generate_private_key - set_short_ids - - reality_config=",\n \"tls\": {\n \"enabled\": true,\n \"server_name\": \"$server_name\",\n \"reality\": {\n \"enabled\": true,\n \"handshake\": {\n \"server\": \"$target_server\",\n \"server_port\": 443\n },\n \"private_key\": \"$private_key\",\n \"short_id\": [$short_Ids\n ]\n }\n }" - fi -} - -# 配置 QUIC 流量混淆 -function configure_quic_obfuscation() { - while true; do - read -p "是否开启QUIC流量混淆(如果你的网络屏蔽了 QUIC 或 HTTP/3 流量,请选择开启)?(Y/N,默认为N): " choice - choice="${choice:-N}" - - if [[ "$choice" == "y" || "$choice" == "Y" ]]; then - read -p "请输入混淆密码(默认随机生成): " new_obfs_password - if [[ -z "$new_obfs_password" ]]; then - new_obfs_password=$(sing-box generate rand --base64 9 2>/dev/null || openssl rand -base64 9) - fi - - obfs_config="\n \"obfs\": {\n \"type\": \"salamander\",\n \"password\": \"$new_obfs_password\"\n }," - obfs_password="$new_obfs_password" - echo "混淆密码:$obfs_password" - break - elif [[ "$choice" == "n" || "$choice" == "N" ]]; then - obfs_config="" - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done -} - -# 配置 obfs 混淆 -function configure_obfuscation() { - while true; do - read -p "是否开启 obfs 混淆(用来绕过针对性的 DPI 屏蔽或者 QoS)?(Y/N,默认为N): " choice - choice="${choice:-N}" - - if [[ "$choice" == "y" || "$choice" == "Y" ]]; then - read -p "请输入混淆密码(默认随机生成): " new_obfs_password - if [[ -z "$new_obfs_password" ]]; then - new_obfs_password=$(sing-box generate rand --base64 9 2>/dev/null || openssl rand -base64 9) - fi - - obfs_config="\n \"obfs\": \"$new_obfs_password\"," - obfs_password="$new_obfs_password" - echo "混淆密码:$obfs_password" - break - elif [[ "$choice" == "n" || "$choice" == "N" ]]; then - obfs_config="" - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done -} - -# 配置多路复用 -function configure_multiplex() { - while true; do - read -p "是否开启多路复用?(Y/N,默认为Y): " choice - choice="${choice:-Y}" - - if [[ "$choice" == "y" || "$choice" == "Y" ]]; then - configure_brutal - multiplex_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"padding\": false$brutal_config\n }" - break - elif [[ "$choice" == "n" || "$choice" == "N" ]]; then - multiplex_config="" - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done -} - -# 配置 TCP Brutal -function configure_brutal() { - while true; do - read -p "是否开启 TCP Brutal?(Y/N,默认为N): " choice - choice="${choice:-N}" - - if [[ "$choice" == "y" || "$choice" == "Y" ]]; then - set_up_speed - set_down_speed - brutal_config=",\n \"brutal\": {\n \"enabled\": true,\n \"up_mbps\": $up_mbps,\n \"down_mbps\": $down_mbps\n }" - break - elif [[ "$choice" == "n" || "$choice" == "N" ]]; then - brutal_config="" - break - else - echo -e "${RED}无效的输入,请重新输入!${NC}" - fi - done -} - -# 提取 TLS 信息 -function extract_tls_info() { - local config_file="/usr/local/etc/sing-box/config.json" - local tls_info_file="/usr/local/etc/sing-box/tls_info.json" - - jq '.inbounds[].tls | select(.server_name and .certificate_path and .key_path) | {server_name: .server_name, certificate_path: .certificate_path, key_path: .key_path}' "$config_file" | jq -s 'unique' > "$tls_info_file" -} - -# 验证 TLS 信息,并根据 DNS 解析结果更新文件 -function validate_tls_info() { - local tls_info_file="/usr/local/etc/sing-box/tls_info.json" - local temp_tls_file="/usr/local/etc/sing-box/temp_tls_info.json" - server_names=($(jq -r '.[].server_name' "$tls_info_file")) - - for server_name in "${server_names[@]}"; do - local resolved_ipv4=$(dig +short A "$server_name" 2>/dev/null) - local resolved_ipv6=$(dig +short AAAA "$server_name" 2>/dev/null) - - if [[ (-n "$resolved_ipv4" && "$resolved_ipv4" == "$ip_v4") || (-n "$resolved_ipv6" && "$resolved_ipv6" == "$ip_v6") ]]; then - continue - else - jq 'map(select(.server_name != "'"$server_name"'"))' "$tls_info_file" > "$temp_tls_file" - mv "$temp_tls_file" "$tls_info_file" - fi - done -} - -# 修改路由规则 -function modify_route_rules() { - local config_file="/usr/local/etc/sing-box/config.json" - local temp_config_file="/usr/local/etc/sing-box/temp_config.json" - - if jq -e '.route.rules[] | select(.rule_set != null)' "$config_file" >/dev/null; then - jq '(.route.rules |= [.[] | select(.rule_set != null)] + [.[] | select(.rule_set == null)])' "$config_file" > "$temp_config_file" - mv "$temp_config_file" "$config_file" - fi - - jq '.route.rules |= (map(select(.action == "sniff")) + map(select(.action != "sniff")))' "$config_file" > tmp.json && mv tmp.json "$config_file" -} - -# 提取变量并清理临时文件 -function extract_variables_and_cleanup() { - server=$(jq -r '.server.v4' "$warp_output_file") - server_port=$(jq -r '.server_port' "$warp_output_file") - local_address_ipv4=$(jq -r '.local_address.v4' "$warp_output_file") - local_address_ipv6=$(jq -r '.local_address.v6' "$warp_output_file") - private_key=$(jq -r '.private_key' "$warp_output_file") - peer_public_key=$(jq -r '.public_key' "$warp_output_file") - reserved=$(jq -r '.reserved | tostring | gsub(","; ", ")' "$warp_output_file") - mtu=$(jq -r '.mtu' "$warp_output_file") - rm "$warp_output_file" -} - -# 日志出站配置 -function log_outbound_config() { - local config_file="/usr/local/etc/sing-box/config.json" - - if ! grep -q '"log": {' "$config_file" || ! grep -q '"route": {' "$config_file" || ! grep -q '"inbounds": \[' "$config_file" || ! grep -q '"outbounds": \[' "$config_file"; then - echo -e '{\n "log": {\n },\n "route": {\n },\n "inbounds": [\n ],\n "outbounds": [\n ]\n}' > "$config_file" - sed -i '/"log": {/!b;n;c\ "disabled": false,\n "level": "info",\n "timestamp": true\n },' "$config_file" - sed -i '/"route": {/!b;n;c\ "rules": [\n {\n "inbound": [\n ],\n "action": "sniff",\n "timeout": "1s"\n },\n {\n "inbound": [\n ],\n "action": "route",\n "outbound": "direct"\n }\n ]\n },' "$config_file" - sed -i '/"outbounds": \[/!b;n;c\ {\n "type": "direct",\n "tag": "direct"\n }\n ]' "$config_file" - fi -} - -# 修改JSON格式,去掉多余的逗号 -function modify_config_format() { - file_path="/usr/local/etc/sing-box/config.json" - start_lines_action=$(grep -n '"action":' "$file_path" | cut -d: -f1) - start_line_outbounds=$(grep -n '"outbounds": \[' "$file_path" | cut -d: -f1) - - for start_line_action in $start_lines_action; do - line_to_modify_action=$((start_line_action - 2)) - if [[ "$line_to_modify_action" -ge 1 ]]; then - sed -i "${line_to_modify_action}s/,[[:space:]]*$//" "$file_path" - fi - done - - if [[ -n "$start_line_outbounds" ]]; then - line_to_modify_outbounds_1=$((start_line_outbounds - 2)) - line_to_modify_outbounds_2=$((start_line_outbounds - 1)) - if [[ "$line_to_modify_outbounds_1" -ge 1 ]]; then - sed -i "$line_to_modify_outbounds_1 s/.*/ }/" "$file_path" - sed -i "$line_to_modify_outbounds_2 s/.*/ ],/" "$file_path" - fi - fi -} - -# 生成 HTTP 配置 -function generate_http_config() { - local config_file="/usr/local/etc/sing-box/config.json" - local cert_path="$certificate_path" - local key_path="$private_key_path" - tls_enabled=true - local tag_label - generate_unique_tag - set_listen_port - socks_naive_multiple_users - get_local_ip - generate_tls_config - local found_inbounds=0 - - awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v users="$users" -v tls_config="$tls_config" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"http\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"set_system_proxy\": false,"; print " \"users\": [" users ""; print " ]" tls_config ""; print " },"; found_inbounds=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 生成 AnyTLS 配置 -function generate_anytls_config() { - local config_file="/usr/local/etc/sing-box/config.json" - local cert_path="$certificate_path" - local key_path="$private_key_path" - tls_enabled=true - local tag_label - generate_unique_tag - set_listen_port - anytls_multiple_users - get_local_ip - generate_tls_config - local found_inbounds=0 - - awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v users="$users" -v tls_config="$tls_config" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"anytls\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"users\": [" users ""; print " ]" tls_config ""; print " },"; found_inbounds=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 生成 Direct 配置 -function generate_Direct_config() { - local config_file="/usr/local/etc/sing-box/config.json" - local tag_label - generate_unique_tag - local found_inbounds=0 - - awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v target_address="$target_address" -v override_port="$override_port" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"direct\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"proxy_protocol\": false,"; print " \"override_address\": \"" target_address "\","; print " \"override_port\": " override_port; print " },"; found_inbounds=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 生成 Shadowsocks 配置 -function generate_ss_config() { - local config_file="/usr/local/etc/sing-box/config.json" - local tag_label - generate_unique_tag - configure_multiplex - local found_inbounds=0 - - awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v ss_method="$ss_method" -v ss_password="$ss_password" -v multiplex_config="$multiplex_config" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"shadowsocks\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"method\": \"" ss_method "\","; print " \"password\": \"" ss_password "\"" multiplex_config ""; print " },"; found_inbounds=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 生成 VMess 配置 -function generate_vmess_config() { - local config_file="/usr/local/etc/sing-box/config.json" - local cert_path="$certificate_path" - local key_path="$private_key_path" - local tag_label - generate_unique_tag - select_vmess_type - set_listen_port - vmess_multiple_users - generate_transport_config - - if [[ "$transport_grpc" != true ]] && [[ "$transport_http" != true ]]; then - configure_multiplex - fi - - get_local_ip - generate_tls_config - check_firewall_configuration - local found_inbounds=0 - - awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v users="$users" -v transport_config="$transport_config" -v tls_config="$tls_config" -v multiplex_config="$multiplex_config" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"vmess\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port "," transport_config ""; print " \"users\": [" users ""; print " ]" tls_config "" multiplex_config ""; print " },"; found=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 生成 SOCKS 配置 -function generate_socks_config() { - local config_file="/usr/local/etc/sing-box/config.json" - local tag_label - generate_unique_tag - set_listen_port - socks_naive_multiple_users - local found_inbounds=0 - - awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v users="$users" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"socks\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"users\": [" users ""; print " ]"; print " },"; found_inbounds=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 生成 NaiveProxy 配置 -function generate_naive_config() { - local config_file="/usr/local/etc/sing-box/config.json" - disable_option=true - local tag_label - generate_unique_tag - set_listen_port - socks_naive_multiple_users - get_local_ip - select_certificate_option - local cert_path="$certificate_path" - local key_path="$private_key_path" - local found_inbounds=0 - - awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v users="$users" -v domain="$domain" -v certificate_path="$certificate_path" -v private_key_path="$private_key_path" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"naive\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"users\": [" users ""; print " ],"; print " \"tls\": {"; print " \"enabled\": true,"; print " \"server_name\": \"" domain "\","; print " \"certificate_path\": \"" certificate_path "\","; print " \"key_path\": \"" private_key_path "\""; print " }"; print " },"; found_inbounds=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 生成 TUIC 配置 -function generate_tuic_config() { - local config_file="/usr/local/etc/sing-box/config.json" - local tag_label - generate_unique_tag - set_listen_port - tuic_multiple_users - select_congestion_control - get_local_ip - set_ech_config - select_certificate_option - local cert_path="$certificate_path" - local key_path="$private_key_path" - local found_inbounds=0 - local server_name="$domain" - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - fi - - awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v users="$users" -v congestion_control="$congestion_control" -v server_name="$server_name" -v certificate_path="$certificate_path" -v private_key_path="$private_key_path" -v ech_server_config="$ech_server_config" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"tuic\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"users\": [" users ""; print " ],"; print " \"congestion_control\": \"" congestion_control "\","; print " \"auth_timeout\": \"3s\","; print " \"zero_rtt_handshake\": false,"; print " \"heartbeat\": \"10s\","; print " \"tls\": {"; print " \"enabled\": true,"; print " \"server_name\": \"" server_name "\","; print " \"alpn\": ["; print " \"h3\""; print " ],"; print " \"certificate_path\": \"" certificate_path "\","; print " \"key_path\": \"" private_key_path "\"" ech_server_config ""; print " }"; print " },"; found_inbounds=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 生成 Hysteria 配置 -function generate_Hysteria_config() { - local config_file="/usr/local/etc/sing-box/config.json" - local tag_label - generate_unique_tag - set_listen_port - set_up_speed - set_down_speed - hysteria_multiple_users - configure_obfuscation - get_local_ip - set_ech_config - ask_enable_port_forwarding - select_certificate_option - local cert_path="$certificate_path" - local key_path="$private_key_path" - local found_inbounds=0 - local server_name="$domain" - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - fi - - awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v up_mbps="$up_mbps" -v down_mbps="$down_mbps" -v obfs_config="$obfs_config" -v users="$users" -v server_name="$server_name" -v certificate_path="$certificate_path" -v private_key_path="$private_key_path" -v ech_server_config="$ech_server_config" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"hysteria\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"up_mbps\": " up_mbps ","; print " \"down_mbps\": " down_mbps ","obfs_config""; print " \"users\": [" users ""; print " ],"; print " \"tls\": {"; print " \"enabled\": true,"; print " \"server_name\": \"" server_name "\","; print " \"alpn\": ["; print " \"h3\""; print " ],"; print " \"certificate_path\": \"" certificate_path "\","; print " \"key_path\": \"" private_key_path "\"" ech_server_config ""; print " }"; print " },"; found_inbounds=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 生成 ShadowTLS 配置 -function generate_shadowtls_config() { - local config_file="/usr/local/etc/sing-box/config.json" - local tag_label - generate_unique_tag - tag_label1="$tag_label" - generate_unique_tag - tag_label2="$tag_label" - set_listen_port - select_encryption_method - shadowtls_multiple_users - set_ss_password - set_target_server - configure_multiplex - local found_inbounds=0 - - awk -v tag_label1="$tag_label1" -v tag_label2="$tag_label2" -v listen_port="$listen_port" -v users="$users" -v target_server="$target_server" -v ss_method="$ss_method" -v ss_password="$ss_password" -v multiplex_config="$multiplex_config" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label1 "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"shadowtls\","; print " \"tag\": \"" tag_label1 "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"version\": 3,"; print " \"users\": [" users ""; print " ],"; print " \"handshake\": {"; print " \"server\": \"" target_server "\","; print " \"server_port\": 443"; print " },"; print " \"strict_mode\": true,"; print " \"detour\": \"" tag_label2 "\""; print " },"; print " {"; print " \"type\": \"shadowsocks\","; print " \"tag\": \"" tag_label2 "\","; print " \"listen\": \"127.0.0.1\","; print " \"method\": \"" ss_method "\","; print " \"password\": \"" ss_password "\"" multiplex_config ""; print " },"; found=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 生成 Juicity 配置 -function generate_juicity_config() { - local config_file="/usr/local/etc/juicity/config.json" - set_listen_port - set_uuid - set_user_password - select_congestion_control - get_local_ip - select_certificate_option - local cert_path="$certificate_path" - local key_path="$private_key_path" - - awk -v listen_port="$listen_port" -v user_uuids="$user_uuids" -v user_passwords="$user_passwords" -v certificate_path="$certificate_path" -v private_key_path="$private_key_path" -v congestion_control="$congestion_control" 'BEGIN { print "{"; printf " \"listen\": \":%s\",\n", listen_port; printf " \"users\": {\n"; printf " \"%s\": \"%s\"\n", user_uuids, user_passwords; printf " },\n"; printf " \"certificate\": \"%s\",\n", certificate_path; printf " \"private_key\": \"%s\",\n", private_key_path; printf " \"congestion_control\": \"%s\",\n", congestion_control; printf " \"disable_outbound_udp443\": true,\n"; print " \"log_level\": \"info\""; print "}"}' > "$config_file" -} - -# 生成 Vless 配置 -function generate_vless_config() { - local config_file="/usr/local/etc/sing-box/config.json" - local tag_label - generate_unique_tag - select_vless_type - set_listen_port - vless_multiple_users - generate_transport_config - generate_reality_config - - if [[ "$flow_type" != xtls-rprx-vision ]] && [[ "$transport_grpc" != true ]] && [[ "$transport_http" != true ]]; then - configure_multiplex - fi - - local found_inbounds=0 - - awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v users="$users" -v transport_config="$transport_config" -v reality_config="$reality_config" -v multiplex_config="$multiplex_config" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"vless\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port "," transport_config ""; print " \"users\": [" users ""; print " ]"reality_config"" multiplex_config ""; print " },"; found=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 生成 Hysteria2 配置 -function generate_Hy2_config() { - local config_file="/usr/local/etc/sing-box/config.json" - local tag_label - generate_unique_tag - set_listen_port - set_up_speed - set_down_speed - hy2_multiple_users - configure_quic_obfuscation - set_fake_domain - get_local_ip - set_ech_config - ask_enable_port_forwarding - select_certificate_option - local cert_path="$certificate_path" - local key_path="$private_key_path" - local found_inbounds=0 - local server_name="$domain" - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - fi - - awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v up_mbps="$up_mbps" -v down_mbps="$down_mbps" -v obfs_config="$obfs_config" -v users="$users" -v fake_domain="$fake_domain" -v server_name="$server_name" -v certificate_path="$certificate_path" -v private_key_path="$private_key_path" -v ech_server_config="$ech_server_config" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"hysteria2\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"up_mbps\": " up_mbps ","; print " \"down_mbps\": " down_mbps ","obfs_config""; print " \"users\": [" users ""; print " ],"; print " \"ignore_client_bandwidth\": false,"; print " \"masquerade\": \"https://" fake_domain "\","; print " \"tls\": {"; print " \"enabled\": true,"; print " \"server_name\": \"" server_name "\","; print " \"alpn\": ["; print " \"h3\""; print " ],"; print " \"certificate_path\": \"" certificate_path "\","; print " \"key_path\": \"" private_key_path "\"" ech_server_config ""; print " }"; print " },"; found=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 生成 Trojan 配置 -function generate_trojan_config() { - local config_file="/usr/local/etc/sing-box/config.json" - local tag_label - generate_unique_tag - select_trojan_type - set_listen_port - trojan_multiple_users - generate_transport_config - - if [[ "$transport_grpc" != true ]] && [[ "$transport_http" != true ]]; then - configure_multiplex - fi - - get_local_ip - generate_tls_config - local cert_path="$certificate_path" - local key_path="$private_key_path" - check_firewall_configuration - local found_inbounds=0 - - awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v users="$users" -v transport_config="$transport_config" -v tls_config="$tls_config" -v multiplex_config="$multiplex_config" ' - /"inbounds": \[/{found_inbounds=1} - { print; if ($0 ~ /^ "inbound": \[/) print " \"" tag_label "\"," } - found_inbounds && /^ "inbounds": \[/{print " {"; print " \"type\": \"trojan\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port "," transport_config ""; print " \"users\": [" users ""; print " ]" tls_config "" multiplex_config ""; print " },"; found=0} - ' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" -} - -# 更新路由规则 -function update_route_file() { - local config_file="/usr/local/etc/sing-box/config.json" - local geosite_list=$(IFS=,; echo "${rule_set[*]}") - local geosite_formatted=$(sed 's/,/,\\n /g' <<< "$geosite_list") - local inbound_values=$(jq -r '.route.rules[].inbound // empty' "$config_file" | jq -s add | jq -r 'unique') - - echo "正在配置 WireGuard..." - - sed -i '/"route": {/a\ "rule_set": [\n ],' "$config_file" - - for geosite in "${rule_set[@]}"; do - geosite_clean=$(echo "$geosite" | sed 's/"//g') - sed -i '/"rule_set": \[/!b; a\{"type": "remote", "tag": "'"$geosite_clean"'", "format": "binary", "url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/'"$geosite_clean"'.srs", "download_detour": "direct"},' "$config_file" - done - - sed -i '/"rules": \[/!b; a\{"rule_set": ['"$geosite_formatted"'], "outbound": "wg-ep"},' "$config_file" - - sed -i ':a;N;$!ba;s/},\n\s*]/}\n ]/' "$config_file" - - jq '.route.rules |= (map(select(.action == "sniff")) + map(select(.action != "sniff")))' "$config_file" > tmp.json && mv tmp.json "$config_file" - - jq --argjson inbound "$inbound_values" '.route.rules |= map(if .outbound == "wg-ep" then {inbound: $inbound} + . else . end)' "$config_file" > tmp.json && mv tmp.json "$config_file" -} - -# 配置 WireGuard -function Configure_endpoints() { - local config_file="/usr/local/etc/sing-box/config.json" - - awk -v server="$server" -v server_port="$server_port" -v local_address_ipv4="$local_address_ipv4" -v local_address_ipv6="$local_address_ipv6" -v private_key="$private_key" -v peer_public_key="$peer_public_key" -v reserved="$reserved" -v mtu="$mtu" '{ - if ($0 ~ /^ "inbounds": \[/) { print " \"endpoints\": ["; print " {"; print " \"type\": \"wireguard\","; print " \"tag\": \"wg-ep\","; print " \"mtu\": " mtu ","; print " \"address\": ["; print " \"" local_address_ipv4 "\","; print " \"" local_address_ipv6 "\""; print " ],"; print " \"private_key\": \"" private_key "\","; print " \"peers\": ["; print " {"; print " \"address\": \"" server "\","; print " \"port\": " server_port ","; print " \"public_key\": \"" peer_public_key "\","; print " \"allowed_ips\": ["; print " \"0.0.0.0/0\","; print " \"::/0\""; print " ],"; print " \"reserved\": " reserved; print " }"; print " ]"; print " }"; print " ]," - } - print $0 - }' "$config_file" > "$config_file.tmp" - - mv "$config_file.tmp" "$config_file" - - echo "WireGuard 配置完成。" -} - -# 生成 sing-box 手机端配置信息 -function write_phone_client_file() { - local dir="/usr/local/etc/sing-box" - local phone_client="${dir}/phone_client.json" - - if [[ ! -s "${phone_client}" ]]; then - awk 'BEGIN { print "{"; print " \"log\": {"; print " \"disabled\": false,"; print " \"level\": \"info\","; print " \"timestamp\": true"; print " },"; print " \"dns\": {"; print " \"servers\": ["; print " {"; print " \"tag\": \"dns_proxy\","; print " \"type\": \"https\","; print " \"server\": \"1.1.1.1\","; print " \"detour\": \"Proxy\""; print " },"; print " {"; print " \"tag\": \"dns_direct\","; print " \"type\": \"https\","; print " \"server\": \"223.5.5.5\""; print " }"; print " ],"; print " \"rules\": ["; print " {"; print " \"clash_mode\": \"Direct\","; print " \"server\": \"dns_direct\""; print " },"; print " {"; print " \"clash_mode\": \"Global\","; print " \"server\": \"dns_proxy\""; print " },"; print " {"; print " \"rule_set\": \"geosite-category-ads-all\","; print " \"action\": \"reject\""; print " },"; print " {"; print " \"rule_set\": \"geosite-geolocation-cn\","; print " \"server\": \"dns_direct\""; print " },"; print " {"; print " \"type\": \"logical\","; print " \"mode\": \"and\","; print " \"rules\": ["; print " {"; print " \"rule_set\": \"geosite-geolocation-!cn\","; print " \"invert\": true"; print " },"; print " {"; print " \"rule_set\": \"geoip-cn\""; print " }"; print " ],"; print " \"server\": \"dns_proxy\","; print " \"client_subnet\": \"114.114.114.114/24\""; print " }"; print " ],"; print " \"final\": \"dns_proxy\","; print " \"strategy\": \"ipv4_only\","; print " \"independent_cache\": true"; print " },"; print " \"route\": {"; print " \"rule_set\": ["; print " {"; print " \"type\": \"remote\","; print " \"tag\": \"geosite-category-ads-all\","; print " \"format\": \"binary\","; print " \"url\": \"https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-category-ads-all.srs\","; print " \"download_detour\": \"Proxy\""; print " },"; print " {"; print " \"type\": \"remote\","; print " \"tag\": \"geosite-geolocation-cn\","; print " \"format\": \"binary\","; print " \"url\": \"https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs\","; print " \"download_detour\": \"Proxy\""; print " },"; print " {"; print " \"type\": \"remote\","; print " \"tag\": \"geosite-geolocation-!cn\","; print " \"format\": \"binary\","; print " \"url\": \"https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-!cn.srs\","; print " \"download_detour\": \"Proxy\""; print " },"; print " {"; print " \"type\": \"remote\","; print " \"tag\": \"geoip-cn\","; print " \"format\": \"binary\","; print " \"url\": \"https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs\","; print " \"download_detour\": \"Proxy\""; print " }"; print " ],"; print " \"default_domain_resolver\": \"dns_direct\","; print " \"rules\": ["; print " {"; print " \"inbound\": \"tun-in\","; print " \"action\": \"sniff\""; print " },"; print " {"; print " \"type\": \"logical\","; print " \"mode\": \"or\","; print " \"rules\": ["; print " {"; print " \"protocol\": \"dns\""; print " },"; print " {"; print " \"port\": 53"; print " }"; print " ],"; print " \"action\": \"hijack-dns\""; print " },"; print " {"; print " \"clash_mode\": \"Direct\","; print " \"outbound\": \"direct-out\""; print " },"; print " {"; print " \"clash_mode\": \"Global\","; print " \"outbound\": \"Proxy\""; print " },"; print " {"; print " \"ip_is_private\": true,"; print " \"outbound\": \"direct-out\""; print " },"; print " {"; print " \"type\": \"logical\","; print " \"mode\": \"or\","; print " \"rules\": ["; print " {"; print " \"port\": 853"; print " },"; print " {"; print " \"network\": \"udp\","; print " \"port\": 443"; print " },"; print " {"; print " \"protocol\": \"stun\""; print " }"; print " ],"; print " \"action\": \"reject\""; print " },"; print " {"; print " \"rule_set\": \"geosite-geolocation-cn\","; print " \"outbound\": \"direct-out\""; print " },"; print " {"; print " \"type\": \"logical\","; print " \"mode\": \"and\","; print " \"rules\": ["; print " {"; print " \"rule_set\": \"geoip-cn\""; print " },"; print " {"; print " \"rule_set\": \"geosite-geolocation-!cn\","; print " \"invert\": true"; print " }"; print " ],"; print " \"outbound\": \"direct-out\""; print " }"; print " ],"; print " \"final\": \"Proxy\","; print " \"auto_detect_interface\": true"; print " },"; print " \"inbounds\": ["; print " {"; print " \"type\": \"tun\","; print " \"tag\": \"tun-in\","; print " \"address\": ["; print " \"172.18.0.1/30\","; print " \"fdfe:dcba:9876::1/126\""; print " ],"; print " \"mtu\": 1400,"; print " \"auto_route\": true,"; print " \"strict_route\": true,"; print " \"stack\": \"gvisor\""; print " }"; print " ],"; print " \"outbounds\": ["; print " {"; print " \"type\": \"urltest\","; print " \"tag\": \"auto\","; print " \"outbounds\": ["; print " ],"; print " \"url\": \"https://www.gstatic.com/generate_204\","; print " \"interval\": \"1m\","; print " \"tolerance\": 50,"; print " \"interrupt_exist_connections\": false"; print " },"; print " {"; print " \"type\": \"selector\","; print " \"tag\": \"Proxy\","; print " \"outbounds\": ["; print " \"auto\""; print " ],"; print " \"default\": \"\","; print " \"interrupt_exist_connections\": false"; print " },"; print " {"; print " \"type\": \"direct\","; print " \"tag\": \"direct-out\""; print " }"; print " ],"; print " \"experimental\": {"; print " \"cache_file\": {"; print " \"enabled\": true,"; print " \"store_fakeip\": false,"; print " \"store_rdrc\": true"; print " },"; print " \"clash_api\": {"; print " \"external_controller\": \"127.0.0.1:9090\","; print " \"external_ui\": \"Dashboard\","; print " \"external_ui_download_url\": \"https://github.com/MetaCubeX/Yacd-meta/archive/gh-pages.zip\","; print " \"external_ui_download_detour\": \"Proxy\","; print " \"default_mode\": \"Rule\""; print " }"; print " }"; print "}" }' > "${phone_client}" - fi -} - -# 生成 sing-box 电脑端配置信息 -function write_win_client_file() { - local dir="/usr/local/etc/sing-box" - local win_client="${dir}/win_client.json" - - if [[ ! -s "${win_client}" ]]; then - awk 'BEGIN { print "{"; print " \"log\": {"; print " \"disabled\": false,"; print " \"level\": \"info\","; print " \"timestamp\": true"; print " },"; print " \"dns\": {"; print " \"servers\": ["; print " {"; print " \"tag\": \"dns_proxy\","; print " \"type\": \"https\","; print " \"server\": \"1.1.1.1\","; print " \"detour\": \"Proxy\""; print " },"; print " {"; print " \"tag\": \"dns_direct\","; print " \"type\": \"https\","; print " \"server\": \"223.5.5.5\""; print " }"; print " ],"; print " \"rules\": ["; print " {"; print " \"clash_mode\": \"Direct\","; print " \"server\": \"dns_direct\""; print " },"; print " {"; print " \"clash_mode\": \"Global\","; print " \"server\": \"dns_proxy\""; print " },"; print " {"; print " \"rule_set\": \"geosite-category-ads-all\","; print " \"action\": \"reject\""; print " },"; print " {"; print " \"rule_set\": \"geosite-geolocation-cn\","; print " \"server\": \"dns_direct\""; print " },"; print " {"; print " \"type\": \"logical\","; print " \"mode\": \"and\","; print " \"rules\": ["; print " {"; print " \"rule_set\": \"geosite-geolocation-!cn\","; print " \"invert\": true"; print " },"; print " {"; print " \"rule_set\": \"geoip-cn\""; print " }"; print " ],"; print " \"server\": \"dns_proxy\","; print " \"client_subnet\": \"114.114.114.114/24\""; print " }"; print " ],"; print " \"final\": \"dns_proxy\","; print " \"strategy\": \"ipv4_only\","; print " \"independent_cache\": true"; print " },"; print " \"route\": {"; print " \"rule_set\": ["; print " {"; print " \"type\": \"remote\","; print " \"tag\": \"geosite-category-ads-all\","; print " \"format\": \"binary\","; print " \"url\": \"https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-category-ads-all.srs\","; print " \"download_detour\": \"Proxy\""; print " },"; print " {"; print " \"type\": \"remote\","; print " \"tag\": \"geosite-geolocation-cn\","; print " \"format\": \"binary\","; print " \"url\": \"https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs\","; print " \"download_detour\": \"Proxy\""; print " },"; print " {"; print " \"type\": \"remote\","; print " \"tag\": \"geosite-geolocation-!cn\","; print " \"format\": \"binary\","; print " \"url\": \"https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-!cn.srs\","; print " \"download_detour\": \"Proxy\""; print " },"; print " {"; print " \"type\": \"remote\","; print " \"tag\": \"geoip-cn\","; print " \"format\": \"binary\","; print " \"url\": \"https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs\","; print " \"download_detour\": \"Proxy\""; print " }"; print " ],"; print " \"default_domain_resolver\": \"dns_direct\","; print " \"rules\": ["; print " {"; print " \"inbound\": \"mixed-in\","; print " \"action\": \"sniff\""; print " },"; print " {"; print " \"type\": \"logical\","; print " \"mode\": \"or\","; print " \"rules\": ["; print " {"; print " \"protocol\": \"dns\""; print " },"; print " {"; print " \"port\": 53"; print " }"; print " ],"; print " \"action\": \"hijack-dns\""; print " },"; print " {"; print " \"clash_mode\": \"Direct\","; print " \"outbound\": \"direct-out\""; print " },"; print " {"; print " \"clash_mode\": \"Global\","; print " \"outbound\": \"Proxy\""; print " },"; print " {"; print " \"ip_is_private\": true,"; print " \"outbound\": \"direct-out\""; print " },"; print " {"; print " \"type\": \"logical\","; print " \"mode\": \"or\","; print " \"rules\": ["; print " {"; print " \"port\": 853"; print " },"; print " {"; print " \"network\": \"udp\","; print " \"port\": 443"; print " },"; print " {"; print " \"protocol\": \"stun\""; print " }"; print " ],"; print " \"action\": \"reject\""; print " },"; print " {"; print " \"rule_set\": \"geosite-geolocation-cn\","; print " \"outbound\": \"direct-out\""; print " },"; print " {"; print " \"type\": \"logical\","; print " \"mode\": \"and\","; print " \"rules\": ["; print " {"; print " \"rule_set\": \"geoip-cn\""; print " },"; print " {"; print " \"rule_set\": \"geosite-geolocation-!cn\","; print " \"invert\": true"; print " }"; print " ],"; print " \"outbound\": \"direct-out\""; print " }"; print " ],"; print " \"final\": \"Proxy\","; print " \"auto_detect_interface\": true"; print " },"; print " \"inbounds\": ["; print " {"; print " \"type\": \"mixed\","; print " \"tag\": \"mixed-in\","; print " \"listen\": \"::\","; print " \"listen_port\": 1080,"; print " \"set_system_proxy\": false"; print " }"; print " ],"; print " \"outbounds\": ["; print " {"; print " \"type\": \"urltest\","; print " \"tag\": \"auto\","; print " \"outbounds\": ["; print " ],"; print " \"url\": \"https://www.gstatic.com/generate_204\","; print " \"interval\": \"1m\","; print " \"tolerance\": 50,"; print " \"interrupt_exist_connections\": false"; print " },"; print " {"; print " \"type\": \"selector\","; print " \"tag\": \"Proxy\","; print " \"outbounds\": ["; print " \"auto\""; print " ],"; print " \"default\": \"\","; print " \"interrupt_exist_connections\": false"; print " },"; print " {"; print " \"type\": \"direct\","; print " \"tag\": \"direct-out\""; print " }"; print " ],"; print " \"experimental\": {"; print " \"cache_file\": {"; print " \"enabled\": true,"; print " \"store_fakeip\": false,"; print " \"store_rdrc\": true"; print " },"; print " \"clash_api\": {"; print " \"external_controller\": \"127.0.0.1:9090\","; print " \"external_ui\": \"Dashboard\","; print " \"external_ui_download_url\": \"https://github.com/MetaCubeX/Yacd-meta/archive/gh-pages.zip\","; print " \"external_ui_download_detour\": \"Proxy\","; print " \"default_mode\": \"Rule\""; print " }"; print " }"; print "}" }' > "${win_client}" - fi -} - -# 更新客户端配置文件信息 -function update_client_file() { - local phone_file="/usr/local/etc/sing-box/phone_client.json" - local win_file="/usr/local/etc/sing-box/win_client.json" - local phone_tag_value=$(jq -r '.outbounds[0].tag' "$phone_file") - local win_tag_value=$(jq -r '.outbounds[0].tag' "$win_file") - - awk -v tag="$phone_tag_value" '{if ($0 ~ /"outbounds": \[/) outbounds_section=1; if (outbounds_section && $0 ~ /"default": /) {sub(/"default": "[^"]*"/, "\"default\": \"" tag "\"")} print}' "$phone_file" > tmp.json && mv tmp.json "$phone_file" - awk -v tag="$win_tag_value" '{if ($0 ~ /"outbounds": \[/) outbounds_section=1; if (outbounds_section && $0 ~ /"default": /) {sub(/"default": "[^"]*"/, "\"default\": \"" tag "\"")} print}' "$win_file" > tmp.json && mv tmp.json "$win_file" -} - -# 生成 clash 配置信息 -function write_clash_yaml() { - local dir="/usr/local/etc/sing-box" - local clash_yaml="${dir}/clash.yaml" - - if [[ ! -s "${clash_yaml}" ]]; then - awk 'BEGIN { print "mixed-port: 7890"; print "allow-lan: true"; print "bind-address: \"*\""; print "find-process-mode: strict"; print "mode: rule"; print "unified-delay: true"; print "tcp-concurrent: true"; print "log-level: info"; print "ipv6: true"; print "global-client-fingerprint: chrome"; print "external-controller: 127.0.0.1:9090"; print "external-ui: ui"; print "external-ui-url: \"https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip\""; print "tun:"; print " enable: true"; print " stack: system"; print " dns-hijack:"; print " - 0.0.0.0:53"; print " auto-detect-interface: true"; print " auto-route: true"; print " auto-redirect: false"; print " strict-route: true"; print " mtu: 1400"; print "profile:"; print " store-selected: true"; print " store-fake-ip: true"; print "sniffer:"; print " enable: true"; print " sniff:"; print " TLS:"; print " ports: [443, 8443]"; print " HTTP:"; print " ports: [80, 8080-8880]"; print " override-destination: true"; print " QUIC:"; print " ports: [443, 8443]"; print " skip-domain:"; print " - \"+.push.apple.com\""; print "dns:"; print " enable: true"; print " cache-algorithm: arc"; print " prefer-h3: false"; print " respect-rules: true"; print " ipv6: true"; print " default-nameserver:"; print " - 1.1.1.1"; print " - 8.8.8.8"; print " - 223.5.5.5"; print " - 119.29.29.29"; print " enhanced-mode: fake-ip"; print " fake-ip-range: 198.18.0.1/16"; print " fake-ip-filter:"; print " - \"*.lan\""; print " - \"*.local\""; print " - \"*.localdomain\""; print " - \"*.example\""; print " - \"*.invalid\""; print " - \"*.localhost\""; print " - \"*.test\""; print " - \"*.home.arpa\""; print " - \"*.direct\""; print " nameserver-policy:"; print " \"rule-set:category_ads_all\": "; print " - rcode://success"; print " \"rule-set:cn_domain,private_domain\":"; print " - https://dns.alidns.com/dns-query"; print " - https://doh.pub/dns-query"; print " nameserver:"; print " - https://cloudflare-dns.com/dns-query"; print " - https://dns.google/dns-query"; print " proxy-server-nameserver:"; print " - https://dns.alidns.com/dns-query"; print " - https://doh.pub/dns-query"; print "proxies:"; print "proxy-groups:"; print " - name: Proxy"; print " type: select"; print " proxies:"; print " - auto"; print " - name: auto"; print " type: url-test"; print " proxies:"; print " url: \"https://cp.cloudflare.com/generate_204\""; print " interval: 300"; print "rules:"; print " - RULE-SET,private_ip,DIRECT,no-resolve"; print " - RULE-SET,category_ads_all,REJECT"; print " - RULE-SET,private_domain,DIRECT"; print " - RULE-SET,google_domain,Proxy"; print " - RULE-SET,cn_domain,DIRECT"; print " - RULE-SET,cn_ip,DIRECT"; print " - MATCH,Proxy"; print "rule-anchor:"; print " ip: &ip {type: http, interval: 86400, behavior: ipcidr, format: mrs}"; print " domain: &domain {type: http, interval: 86400, behavior: domain, format: mrs}"; print "rule-providers:"; print " private_domain:"; print " <<: *domain"; print " url: \"https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/private.mrs\""; print " cn_domain:"; print " <<: *domain"; print " url: \"https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/cn.mrs\""; print " google_domain:"; print " <<: *domain"; print " url: \"https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo-lite/geosite/google.mrs\""; print " category_ads_all:"; print " <<: *domain"; print " url: \"https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/category-ads-all.mrs\""; print " private_ip:"; print " <<: *ip"; print " url: \"https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geoip/private.mrs\""; print " cn_ip:"; print " <<: *ip"; print " url: \"https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geoip/cn.mrs\""; }' > "${clash_yaml}" - fi -} - -# 生成 NaiveProxy 客户端配置信息 -function write_naive_client_file() { - local naive_client_file="$naive_client_filename" - - awk -v naive_client_file="$naive_client_file" 'BEGIN { print "{"; print " \"listen\": \"socks://127.0.0.1:1080\","; print " \"proxy\": \"https://user_name:user_password@server_name:listen_port\""; print "}" }' > "$naive_client_file" -} - -# 生成 Shadowsocks Windows 客户端配置 -function generate_shadowsocks_win_client_config() { - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local proxy_name - - if [[ -n "$multiplex_config" && -n "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false,\n \"brutal\": {\n \"enabled\": true,\n \"up_mbps\": $down_mbps,\n \"down_mbps\": $up_mbps\n }\n }" - elif [[ -n "$multiplex_config" && -z "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false\n }" - fi - - while true; do - proxy_name="ss-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$win_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v ss_method="$ss_method" -v ss_password="$ss_password" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"shadowsocks\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port ","; print " \"method\": \"" ss_method "\", "; print " \"password\": \"" ss_password "\"" multiplex_client_config ""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - - mv "$win_client_file.tmp" "$win_client_file" -} - -# 生成 Shadowsocks 手机客户端配置 -function generate_shadowsocks_phone_client_config() { - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local proxy_name - - if [[ -n "$multiplex_config" && -n "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false,\n \"brutal\": {\n \"enabled\": true,\n \"up_mbps\": $down_mbps,\n \"down_mbps\": $up_mbps\n }\n }" - elif [[ -n "$multiplex_config" && -z "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false\n }" - fi - - while true; do - proxy_name="ss-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$phone_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v ss_method="$ss_method" -v ss_password="$ss_password" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"shadowsocks\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port ","; print " \"method\": \"" ss_method "\", "; print " \"password\": \"" ss_password "\"" multiplex_client_config ""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - - mv "$phone_client_file.tmp" "$phone_client_file" -} - -# 生成 Shadowsocks Clash 客户端配置 -function generate_shadowsocks_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local proxy_name - - while true; do - proxy_name="ss-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v ss_method="$ss_method" -v ss_password="$ss_password" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: ss"; print " server:", local_ip; print " port:", listen_port; print " cipher:", ss_method; print " password:", "\"" ss_password "\""; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 Juicity Windows 客户端配置 -function generate_juicity_win_client_config() { - local client_file="/usr/local/etc/juicity/client.json" - local server_name="$domain" - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - awk -v listen_port="$listen_port" -v server_value="$server_value" -v user_uuids="$user_uuids" -v user_passwords="$user_passwords" -v server_name="$server_name" -v tls_insecure="$tls_insecure" -v congestion_control="$congestion_control" 'BEGIN { print "{"; printf " \"listen\": \":%s\",\n", 1080; printf " \"server\": \"%s:%s\",\n", server_value, listen_port; printf " \"uuid\": \"%s\",\n", user_uuids; printf " \"password\": \"%s\",\n", user_passwords; printf " \"sni\": \"%s\",\n", server_name; printf " \"allow_insecure\": %s,\n", tls_insecure; printf " \"congestion_control\": \"%s\",\n", congestion_control; printf " \"log_level\": \"info\"\n"; print "}"}' > "$client_file" - - echo "客户端配置文件已保存至$client_file,请下载后使用!" -} - -# 生成 TUIC 手机客户端配置 -function generate_tuic_phone_client_config() { - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"config\": [\n$ech_config\n ]\n }" - fi - - while true; do - proxy_name="tuic-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$phone_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v user_password="$user_password" -v congestion_control="$congestion_control" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"tuic\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; print " \"uuid\": \"" user_uuid "\", "; print " \"password\": \"" user_password "\", "; print " \"congestion_control\": \""congestion_control"\","; print " \"udp_relay_mode\": \"native\","; print " \"zero_rtt_handshake\": false,"; print " \"heartbeat\": \"10s\","; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\", "; print " \"alpn\": ["; print " \"h3\""; print " ]" ech_client_config ""; print " }"; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - - mv "$phone_client_file.tmp" "$phone_client_file" -} - -# 生成 TUIC Windows 客户端配置 -function generate_tuic_win_client_config() { - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"config\": [\n$ech_config\n ]\n }" - fi - - while true; do - proxy_name="tuic-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$win_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v user_password="$user_password" -v congestion_control="$congestion_control" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"tuic\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; print " \"uuid\": \"" user_uuid "\", "; print " \"password\": \"" user_password "\", "; print " \"congestion_control\": \""congestion_control"\","; print " \"udp_relay_mode\": \"native\","; print " \"zero_rtt_handshake\": false,"; print " \"heartbeat\": \"10s\","; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\", "; print " \"alpn\": ["; print " \"h3\""; print " ]" ech_client_config ""; print " }"; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - - mv "$win_client_file.tmp" "$win_client_file" -} - -# 生成 TUIC Clash 客户端配置 -function generate_tuic_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - while true; do - proxy_name="tuic-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v user_password="$user_password" -v congestion_control="$congestion_control" -v tls_insecure="$tls_insecure" '/^proxies:$/ {print; print " - name: " proxy_name; print " server:", server_value; print " port:", listen_port; print " type: tuic"; print " uuid:", user_uuid; print " password:", user_password; print " sni:", server_name; print " alpn: [h3]"; print " request-timeout: 8000"; print " udp-relay-mode: native"; print " skip-cert-verify:", tls_insecure; print " congestion-controller:", congestion_control; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 SOCKS Windows 客户端配置 -function generate_socks_win_client_config() { - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local proxy_name - - while true; do - proxy_name="socks-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$win_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_name="$user_name" -v user_password="$user_password" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"socks\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port ","; print " \"username\": \"" user_name "\", "; print " \"password\": \"" user_password "\" "; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - - mv "$win_client_file.tmp" "$win_client_file" -} - -# 生成 SOCKS 手机客户端配置 -function generate_socks_phone_client_config() { - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local proxy_name - - while true; do - proxy_name="socks-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$phone_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_name="$user_name" -v user_password="$user_password" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"socks\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port ","; print " \"username\": \"" user_name "\", "; print " \"password\": \"" user_password "\" "; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - - mv "$phone_client_file.tmp" "$phone_client_file" -} - -# 生成 SOCKS Clash 客户端配置 -function generate_socks_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local proxy_name - - while true; do - proxy_name="socks-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_name="$user_name" -v user_password="$user_password" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: socks5"; print " server:", local_ip; print " port:", listen_port; print " username:", user_name; print " password:", user_password; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 Hysteria Windows 客户端配置 -function generate_Hysteria_win_client_config() { - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$obfs_password" ]]; then - obfs_config="\n \"obfs\": \"$obfs_password\"," - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"config\": [\n$ech_config\n ]\n }" - fi - - if [[ -z "$start_port" ]] || [[ -z "$end_port" ]]; then - server_ports_config="\"server_port\": $listen_port" - else - server_ports_config="\"server_ports\": [\n \"$start_port:$end_port\"\n ]" - fi - - while true; do - proxy_name="Hysteria-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$win_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v server_ports_config="$server_ports_config" -v up_mbps="$up_mbps" -v down_mbps="$down_mbps" -v obfs_config="$obfs_config" -v user_password="$user_password" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"hysteria\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " " server_ports_config ","; print " \"up_mbps\": " down_mbps ", "; print " \"down_mbps\": " up_mbps ","obfs_config""; print " \"auth_str\": \""user_password"\","; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\", "; print " \"alpn\": ["; print " \"h3\""; print " ]" ech_client_config ""; print " }"; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - - mv "$win_client_file.tmp" "$win_client_file" -} - -# 生成 Hysteria 手机客户端配置 -function generate_Hysteria_phone_client_config() { - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$obfs_password" ]]; then - obfs_config="\n \"obfs\": \"$obfs_password\"," - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"config\": [\n$ech_config\n ]\n }" - fi - - if [[ -z "$start_port" ]] || [[ -z "$end_port" ]]; then - server_ports_config="\"server_port\": $listen_port" - else - server_ports_config="\"server_ports\": [\n \"$start_port:$end_port\"\n ]" - fi - - while true; do - proxy_name="Hysteria-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$phone_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v server_ports_config="$server_ports_config" -v up_mbps="$up_mbps" -v down_mbps="$down_mbps" -v obfs_config="$obfs_config" -v user_password="$user_password" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"hysteria\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " " server_ports_config ","; print " \"up_mbps\": " down_mbps ", "; print " \"down_mbps\": " up_mbps ","obfs_config""; print " \"auth_str\": \""user_password"\","; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\", "; print " \"alpn\": ["; print " \"h3\""; print " ]" ech_client_config ""; print " }"; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - - mv "$phone_client_file.tmp" "$phone_client_file" -} - -# 生成 Hysteria Clash 客户端配置 -function generate_Hysteria_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$obfs_password" ]]; then - obfs_config=" - obfs: $obfs_password" - fi - - if [[ -n "$start_port" ]] && [[ -n "$end_port" ]]; then - ports_config=" - ports: $start_port-$end_port" - else - ports_config="" - fi - - while true; do - proxy_name="hysteria-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v ports_config="$ports_config" -v up_mbps="$up_mbps" -v down_mbps="$down_mbps" -v user_password="$user_password" -v obfs_config="$obfs_config" -v tls_insecure="$tls_insecure" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: hysteria"; print " server:", server_value; print " port:", listen_port ports_config; print " auth-str:", user_password obfs_config; print " sni:", server_name; print " skip-cert-verify:", tls_insecure; print " alpn:"; print " - h3"; print " protocol: udp"; print " up: \"" down_mbps " Mbps\""; print " down: \"" up_mbps " Mbps\""; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 VMess Windows 客户端配置 -function generate_vmess_win_client_config() { - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local proxy_name - local server_name="$domain" - local server_value - local tls_insecure - - if [[ -z "$domain" && -n "$domain_name" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - elif [[ -z "$domain" && -z "$domain_name" ]]; then - server_value="$local_ip" - elif [[ -z "$domain_name" && -n "$domain" ]]; then - server_name="$domain" - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$multiplex_config" && -n "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false,\n \"brutal\": {\n \"enabled\": true,\n \"up_mbps\": $down_mbps,\n \"down_mbps\": $up_mbps\n }\n }" - elif [[ -n "$multiplex_config" && -z "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false\n }" - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"pq_signature_schemes_enabled\": true,\n \"dynamic_record_sizing_disabled\": false,\n \"config\": [\n$ech_config\n ]\n }" - fi - - while true; do - proxy_name="vmess-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$win_client_file"; then - break - fi - done - - if [[ -n "$domain" || -n "$domain_name" ]]; then - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v transport_config="$transport_config" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"vmess\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; print " \"uuid\": \"" user_uuid "\"," transport_config " "; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\"" ech_client_config ""; print " },"; print " \"security\": \"auto\","; print " \"alter_id\": 0,"; print " \"packet_encoding\": \"xudp\"" multiplex_client_config ""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - else - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v transport_config="$transport_config" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"vmess\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port ","; print " \"uuid\": \"" user_uuid "\"," transport_config " "; print " \"security\": \"auto\","; print " \"alter_id\": 0,"; print " \"packet_encoding\": \"xudp\"" multiplex_client_config ""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - fi - - mv "$win_client_file.tmp" "$win_client_file" -} - -# 生成 VMess 手机客户端配置 -function generate_vmess_phone_client_config() { - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local proxy_name - local server_name="$domain" - local server_value - local tls_insecure - - if [[ -z "$domain" && -n "$domain_name" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - elif [[ -z "$domain" && -z "$domain_name" ]]; then - server_value="$local_ip" - elif [[ -z "$domain_name" && -n "$domain" ]]; then - server_name="$domain" - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$multiplex_config" && -n "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false,\n \"brutal\": {\n \"enabled\": true,\n \"up_mbps\": $down_mbps,\n \"down_mbps\": $up_mbps\n }\n }" - elif [[ -n "$multiplex_config" && -z "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false\n }" - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"pq_signature_schemes_enabled\": true,\n \"dynamic_record_sizing_disabled\": false,\n \"config\": [\n$ech_config\n ]\n }" - fi - - while true; do - proxy_name="vmess-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$phone_client_file"; then - break - fi - done - - if [[ -n "$domain" || -n "$domain_name" ]]; then - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v transport_config="$transport_config" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"vmess\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; print " \"uuid\": \"" user_uuid "\"," transport_config " "; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\"" ech_client_config ""; print " },"; print " \"security\": \"auto\","; print " \"alter_id\": 0,"; print " \"packet_encoding\": \"xudp\"" multiplex_client_config ""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - else - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v transport_config="$transport_config" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"vmess\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port ","; print " \"uuid\": \"" user_uuid "\"," transport_config " "; print " \"security\": \"auto\","; print " \"alter_id\": 0,"; print " \"packet_encoding\": \"xudp\"" multiplex_client_config ""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - fi - - mv "$phone_client_file.tmp" "$phone_client_file" -} - -# 生成 VMess+TCP Clash 客户端配置 -function generate_vmess_tcp_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local proxy_name - - while true; do - proxy_name="vmess-tcp-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_uuid="$user_uuid" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: vmess"; print " server:", local_ip; print " port:", listen_port; print " uuid:", user_uuid; print " alterId: 0"; print " cipher: auto"; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 VMess+TCP+TLS Clash 客户端配置 -function generate_vmess_tcp_tls_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - while true; do - proxy_name="vmess-tcp-tls-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v tls_insecure="$tls_insecure" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: vmess"; print " server:", server_value; print " port:", listen_port; print " uuid:", user_uuid; print " alterId: 0"; print " cipher: auto"; print " tls: true"; print " skip-cert-verify:", tls_insecure; print " servername: " server_name; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 VMess+WebSocket Clash 客户端配置 -function generate_vmess_ws_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local proxy_name - - while true; do - proxy_name="vmess-ws-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v transport_path="$transport_path" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: vmess"; print " server:", local_ip; print " port:", listen_port; print " uuid:", user_uuid; print " alterId: 0"; print " cipher: auto"; print " network: ws"; print " ws-opts:"; print " path: " transport_path; print " max-early-data: 2048"; print " early-data-header-name: Sec-WebSocket-Protocol"; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 VMess+WebSocket+TLS Clash 客户端配置 -function generate_vmess_ws_tls_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - while true; do - proxy_name="vmess-ws-tls-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v transport_path="$transport_path" -v tls_insecure="$tls_insecure" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: vmess"; print " server:", server_value; print " port:", listen_port; print " uuid:", user_uuid; print " alterId: 0"; print " cipher: auto"; print " network: ws"; print " tls: true"; print " skip-cert-verify:", tls_insecure; print " servername:", server_name; print " ws-opts:"; print " path: " transport_path; print " max-early-data: 2048"; print " early-data-header-name: Sec-WebSocket-Protocol"; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 VMess+gRPC Clash 客户端配置 -function generate_vmess_grpc_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local proxy_name - - while true; do - proxy_name="vmess-grpc-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v transport_service_name="$transport_service_name" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: vmess"; print " server:", local_ip; print " port:", listen_port; print " uuid:", user_uuid; print " alterId: 0"; print " cipher: auto"; print " network: grpc"; print " grpc-opts:"; print " grpc-service-name:", "\"" transport_service_name "\""; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 VMess+gRPC+TLS Clash 客户端配置 -function generate_vmess_grpc_tls_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - while true; do - proxy_name="vmess-grpc-tls-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v transport_service_name="$transport_service_name" -v tls_insecure="$tls_insecure" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: vmess"; print " server:", server_value; print " port:", listen_port; print " uuid:", user_uuid; print " alterId: 0"; print " cipher: auto"; print " network: grpc"; print " tls: true"; print " skip-cert-verify:", tls_insecure; print " servername:", server_name; print " grpc-opts:"; print " grpc-service-name:", "\"" transport_service_name "\""; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 HTTP 手机客户端配置 -function generate_http_phone_client_config() { - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"config\": [\n$ech_config\n ]\n }" - fi - - while true; do - proxy_name="http-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$phone_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_name="$user_name" -v user_password="$user_password" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"http\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; print " \"username\": \"" user_name "\", "; print " \"password\": \"" user_password "\","; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\"" ech_client_config ""; print " }"; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - - mv "$phone_client_file.tmp" "$phone_client_file" -} - -# 生成 HTTP Windows 客户端配置 -function generate_http_win_client_config() { - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"config\": [\n$ech_config\n ]\n }" - fi - - while true; do - proxy_name="http-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$win_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_name="$user_name" -v user_password="$user_password" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"http\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; print " \"username\": \"" user_name "\", "; print " \"password\": \"" user_password "\","; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\"" ech_client_config ""; print " }"; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - - mv "$win_client_file.tmp" "$win_client_file" -} - -# 生成 HTTP Clash 客户端配置 -function generate_http_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - while true; do - proxy_name="http-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_name="$user_name" -v user_password="$user_password" -v tls_insecure="$tls_insecure" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: http"; print " server:", server_value; print " port:", listen_port; print " username:", user_name; print " password:", user_password; print " tls: true"; print " sni:", server_name; print " skip-cert-verify:", tls_insecure; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 AnyTLS 手机客户端配置 -function generate_anytls_phone_client_config() { - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"config\": [\n$ech_config\n ]\n }" - fi - - while true; do - proxy_name="anytls-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$phone_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_password="$user_password" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"anytls\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; print " \"password\": \"" user_password "\","; print " \"idle_session_check_interval\": \"30s\","; print " \"idle_session_timeout\": \"30s\","; print " \"min_idle_session\": 5,"; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\"" ech_client_config ""; print " }"; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - - mv "$phone_client_file.tmp" "$phone_client_file" -} - -# 生成 AnyTLS Windows 客户端配置 -function generate_anytls_win_client_config() { - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"config\": [\n$ech_config\n ]\n }" - fi - - while true; do - proxy_name="anytls-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$win_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_password="$user_password" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"anytls\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; print " \"password\": \"" user_password "\","; print " \"idle_session_check_interval\": \"30s\","; print " \"idle_session_timeout\": \"30s\","; print " \"min_idle_session\": 5,"; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\"" ech_client_config ""; print " }"; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - - mv "$win_client_file.tmp" "$win_client_file" -} - -# 生成 AnyTLS Clash 客户端配置 -function generate_anytls_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - while true; do - proxy_name="anytls-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_name="$user_name" -v user_password="$user_password" -v tls_insecure="$tls_insecure" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: anytls"; print " server:", server_value; print " port:", listen_port; print " password:", user_password; print " udp: true"; print " idle-session-check-interval: 30"; print " idle-session-timeout: 30"; print " min-idle-session: 5"; print " sni:", server_name; print " alpn:"; print " - h2"; print " - http/1.1"; print " skip-cert-verify:", tls_insecure; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 Hysteria2 手机客户端配置 -function generate_Hysteria2_phone_client_config() { - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$obfs_password" ]]; then - obfs_config="\n \"obfs\": {\n \"type\": \"salamander\",\n \"password\": \"$obfs_password\"\n }," - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"config\": [\n$ech_config\n ]\n }" - fi - - if [[ -z "$start_port" || -z "$end_port" ]]; then - server_ports_config="\"server_port\": $listen_port" - else - server_ports_config="\"server_ports\": [\n \"$start_port:$end_port\"\n ]" - fi - - while true; do - proxy_name="Hysteria2-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$phone_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v server_ports_config="$server_ports_config" -v up_mbps="$up_mbps" -v down_mbps="$down_mbps" -v obfs_config="$obfs_config" -v user_password="$user_password" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"hysteria2\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " " server_ports_config ","; print " \"up_mbps\": " down_mbps ", "; print " \"down_mbps\": " up_mbps ","obfs_config""; print " \"password\": \"" user_password "\","; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\", "; print " \"alpn\": ["; print " \"h3\""; print " ]" ech_client_config ""; print " }"; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - - mv "$phone_client_file.tmp" "$phone_client_file" -} - -# 生成 Hysteria2 Windows 客户端配置 -function generate_Hysteria2_win_client_config() { - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$obfs_password" ]]; then - obfs_config="\n \"obfs\": {\n \"type\": \"salamander\",\n \"password\": \"$obfs_password\"\n }," - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"config\": [\n$ech_config\n ]\n }" - fi - - if [[ -z "$start_port" || -z "$end_port" ]]; then - server_ports_config="\"server_port\": $listen_port" - else - server_ports_config="\"server_ports\": [\n \"$start_port:$end_port\"\n ]" - fi - - while true; do - proxy_name="Hysteria2-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$win_client_file"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v server_ports_config="$server_ports_config" -v up_mbps="$up_mbps" -v down_mbps="$down_mbps" -v obfs_config="$obfs_config" -v user_password="$user_password" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"hysteria2\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " " server_ports_config ","; print " \"up_mbps\": " down_mbps ", "; print " \"down_mbps\": " up_mbps ","obfs_config""; print " \"password\": \"" user_password "\","; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\", "; print " \"alpn\": ["; print " \"h3\""; print " ]" ech_client_config ""; print " }"; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - - mv "$win_client_file.tmp" "$win_client_file" -} - -# 生成 Hysteria2 Clash 客户端配置 -function generate_Hysteria2_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$obfs_password" ]]; then - obfs_config=" - obfs: salamander - obfs-password: $obfs_password" - fi - - if [[ -n "$start_port" && -n "$end_port" ]]; then - ports_config=" - ports: $start_port-$end_port" - else - ports_config="" - fi - - while true; do - proxy_name="hysteria2-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v ports_config="$ports_config" -v up_mbps="$up_mbps" -v down_mbps="$down_mbps" -v user_password="$user_password" -v obfs_config="$obfs_config" -v tls_insecure="$tls_insecure" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: hysteria2"; print " server:", server_value; print " port:", listen_port ports_config; print " password:", user_password obfs_config; print " alpn:"; print " - h3"; print " sni:", server_name; print " skip-cert-verify:", tls_insecure; print " up: \"" down_mbps " Mbps\""; print " down: \"" up_mbps " Mbps\""; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 VLESS Windows 客户端配置 -function generate_vless_win_client_config() { - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local proxy_name - local server_name_in_config=$(jq -r '.inbounds[0].tls.server_name' "$config_file") - - if [[ -n "$multiplex_config" && -n "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false,\n \"brutal\": {\n \"enabled\": true,\n \"up_mbps\": $down_mbps,\n \"down_mbps\": $up_mbps\n }\n }" - elif [[ -n "$multiplex_config" && -z "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false\n }" - fi - - while true; do - proxy_name="vless-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$win_client_file"; then - break - fi - done - - if [[ "$server_name_in_config" != "null" ]]; then - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v server_name="$server_name" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v flow_type="$flow_type" -v public_key="$public_key" -v short_id="$short_id" -v transport_config="$transport_config" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"vless\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port ","; print " \"uuid\": \"" user_uuid "\", "; print " \"flow\": \"" flow_type "\"," transport_config ""; print " \"tls\": {"; print " \"enabled\": true,"; print " \"server_name\": \"" server_name "\", "; print " \"utls\": {"; print " \"enabled\": true,"; print " \"fingerprint\": \"chrome\""; print " },"; print " \"reality\": {"; print " \"enabled\": true,"; print " \"public_key\": \"" public_key "\","; print " \"short_id\": \"" short_id "\""; print " }"; print " }" multiplex_client_config ""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - else - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v flow_type="$flow_type" -v transport_config="$transport_config" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"vless\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port ","; print " \"uuid\": \"" user_uuid "\"," transport_config ""; print " \"flow\": \"" flow_type "\"" multiplex_client_config ""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - fi - - mv "$win_client_file.tmp" "$win_client_file" -} - -# 生成 VLESS 手机客户端配置 -function generate_vless_phone_client_config() { - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local proxy_name - local server_name_in_config=$(jq -r '.inbounds[0].tls.server_name' "$config_file") - - if [[ -n "$multiplex_config" && -n "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false,\n \"brutal\": {\n \"enabled\": true,\n \"up_mbps\": $down_mbps,\n \"down_mbps\": $up_mbps\n }\n }" - elif [[ -n "$multiplex_config" && -z "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false\n }" - fi - - while true; do - proxy_name="vless-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$phone_client_file"; then - break - fi - done - - if [[ "$server_name_in_config" != "null" ]]; then - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v server_name="$server_name" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v flow_type="$flow_type" -v public_key="$public_key" -v short_id="$short_id" -v transport_config="$transport_config" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"vless\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port ","; print " \"uuid\": \"" user_uuid "\", "; print " \"flow\": \"" flow_type "\"," transport_config ""; print " \"tls\": {"; print " \"enabled\": true,"; print " \"server_name\": \"" server_name "\", "; print " \"utls\": {"; print " \"enabled\": true,"; print " \"fingerprint\": \"chrome\""; print " },"; print " \"reality\": {"; print " \"enabled\": true,"; print " \"public_key\": \"" public_key "\","; print " \"short_id\": \"" short_id "\""; print " }"; print " }" multiplex_client_config ""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - else - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v flow_type="$flow_type" -v transport_config="$transport_config" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"vless\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port ","; print " \"uuid\": \"" user_uuid "\"," transport_config ""; print " \"flow\": \"" flow_type "\"" multiplex_client_config ""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - fi - - mv "$phone_client_file.tmp" "$phone_client_file" -} - -# 生成 VLESS+TCP Clash 客户端配置 -function generate_vless_tcp_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local proxy_name - - while true; do - proxy_name="vless-tcp-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_uuid="$user_uuid" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: vless"; print " server:", local_ip; print " port:", listen_port; print " uuid:", user_uuid; print " network: tcp"; print " udp: true"; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 VLESS+WebSocket Clash 客户端配置 -function generate_vless_ws_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local proxy_name - - while true; do - proxy_name="vless-ws-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v transport_path="$transport_path" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: vless"; print " server:", local_ip; print " port:", listen_port; print " uuid:", user_uuid; print " network: ws"; print " udp: true"; print " ws-opts:"; print " path: " transport_path; print " max-early-data: 2048"; print " early-data-header-name: Sec-WebSocket-Protocol"; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 VLESS+gRPC Clash 客户端配置 -function generate_vless_grpc_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local proxy_name - - while true; do - proxy_name="vless-grpc-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v transport_service_name="$transport_service_name" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: vless"; print " server:", local_ip; print " port:", listen_port; print " uuid:", user_uuid; print " network: grpc"; print " udp: true"; print " grpc-opts:"; print " grpc-service-name:", "\"" transport_service_name "\""; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 VLESS+Vision+REALITY Clash 客户端配置 -function generate_vless_reality_vision_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local proxy_name - - while true; do - proxy_name="vless-reality-vision-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v server_name="$server_name" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v public_key="$public_key" -v short_id="$short_id" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: vless"; print " server:", local_ip; print " port:", listen_port; print " uuid:", user_uuid; print " network: tcp"; print " udp: true"; print " tls: true"; print " flow: xtls-rprx-vision"; print " servername:", server_name; print " reality-opts:"; print " public-key:", public_key; print " short-id:", short_id; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 VLESS+gRPC+REALITY Clash 客户端配置 -function generate_vless_reality_grpc_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local proxy_name - - while true; do - proxy_name="vless-reality-grpc-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v server_name="$server_name" -v listen_port="$listen_port" -v user_uuid="$user_uuid" -v public_key="$public_key" -v short_id="$short_id" -v transport_service_name="$transport_service_name" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: vless"; print " server:", local_ip; print " port:", listen_port; print " uuid:", user_uuid; print " network: grpc"; print " udp: true"; print " tls: true"; print " flow: "; print " servername:", server_name; print " reality-opts:"; print " public-key:", public_key; print " short-id:", short_id; print " grpc-opts:"; print " grpc-service-name:", "\"" transport_service_name "\""; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 Trojan 手机客户端配置 -function generate_trojan_phone_client_config() { - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local proxy_name - local server_name="$domain" - local server_value - local tls_insecure - - if [[ -z "$domain" && -n "$domain_name" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - elif [[ -z "$domain" && -z "$domain_name" ]]; then - server_value="$local_ip" - elif [[ -z "$domain_name" && -n "$domain" ]]; then - server_name="$domain" - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$multiplex_config" && -n "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false,\n \"brutal\": {\n \"enabled\": true,\n \"up_mbps\": $down_mbps,\n \"down_mbps\": $up_mbps\n }\n }" - elif [[ -n "$multiplex_config" && -z "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false\n }" - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"config\": [\n$ech_config\n ]\n }" - fi - - while true; do - proxy_name="trojan-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$phone_client_file"; then - break - fi - done - - if [[ -n "$domain" || -n "$domain_name" ]]; then - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_password="$user_password" -v transport_config="$transport_config" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"trojan\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; print " \"password\": \"" user_password "\"," transport_config " "; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\"" ech_client_config ""; print " }"multiplex_client_config""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - else - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_password="$user_password" -v transport_config="$transport_config" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"trojan\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port "," transport_config " "; print " \"password\": \"" user_password "\""multiplex_client_config""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - fi - - mv "$phone_client_file.tmp" "$phone_client_file" -} - -# 生成 Trojan Windows 客户端配置 -function generate_trojan_win_client_config() { - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local proxy_name - local server_name="$domain" - local server_value - local tls_insecure - - if [[ -z "$domain" && -n "$domain_name" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - elif [[ -z "$domain" && -z "$domain_name" ]]; then - server_value="$local_ip" - elif [[ -z "$domain_name" && -n "$domain" ]]; then - server_name="$domain" - server_value="$domain" - tls_insecure="false" - fi - - if [[ -n "$multiplex_config" && -n "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false,\n \"brutal\": {\n \"enabled\": true,\n \"up_mbps\": $down_mbps,\n \"down_mbps\": $up_mbps\n }\n }" - elif [[ -n "$multiplex_config" && -z "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false\n }" - fi - - if [[ -n "$ech_config" ]]; then - ech_client_config=",\n \"ech\": {\n \"enabled\": true,\n \"config\": [\n$ech_config\n ]\n }" - fi - - while true; do - proxy_name="trojan-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$win_client_file"; then - break - fi - done - - if [[ -n "$domain" || -n "$domain_name" ]]; then - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_password="$user_password" -v transport_config="$transport_config" -v tls_insecure="$tls_insecure" -v ech_client_config="$ech_client_config" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"trojan\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; print " \"password\": \"" user_password "\"," transport_config " "; print " \"tls\": {"; print " \"enabled\": true,"; print " \"insecure\": " tls_insecure ","; print " \"server_name\": \"" server_name "\"" ech_client_config ""; print " }"multiplex_client_config""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - else - awk -v proxy_name="$proxy_name" -v local_ip="$local_ip" -v listen_port="$listen_port" -v user_password="$user_password" -v transport_config="$transport_config" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"trojan\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port "," transport_config " "; print " \"password\": \"" user_password "\""multiplex_client_config""; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - fi - - mv "$win_client_file.tmp" "$win_client_file" -} - -# 生成 Trojan+TCP Clash 客户端配置 -function generate_trojan_tcp_tls_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - while true; do - proxy_name="trojan-tcp-tls-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_password="$user_password" -v tls_insecure="$tls_insecure" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: trojan"; print " server:", server_value; print " port:", listen_port; print " password:", user_password; print " udp: true"; print " sni:", server_name; print " skip-cert-verify:", tls_insecure; print " alpn:"; print " - h2"; print " - http/1.1"; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 Trojan+WebSocket+TLS Clash 客户端配置 -function generate_trojan_ws_tls_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - while true; do - proxy_name="trojan-ws-tls-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_password="$user_password" -v transport_path="$transport_path" -v tls_insecure="$tls_insecure" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: trojan"; print " server:", server_value; print " port:", listen_port; print " password:", "\"" user_password "\""; print " network: ws"; print " sni:", server_name; print " skip-cert-verify:", tls_insecure; print " udp: true"; print " ws-opts:"; print " path:", transport_path; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 Trojan+gRPC+TLS Clash 客户端配置 -function generate_trojan_grpc_tls_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local server_name="$domain" - local proxy_name - local server_value - local tls_insecure - - if [[ -z "$domain" ]]; then - server_name="$domain_name" - server_value="$local_ip" - tls_insecure="true" - else - server_value="$domain" - tls_insecure="false" - fi - - while true; do - proxy_name="trojan-grpc-tls-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -v user_password="$user_password" -v transport_service_name="$transport_service_name" -v tls_insecure="$tls_insecure" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: trojan"; print " server:", server_value; print " port:", listen_port; print " password:", "\"" user_password "\""; print " network: grpc"; print " sni:", server_name; print " udp: true"; print " skip-cert-verify:", tls_insecure; print " grpc-opts:"; print " grpc-service-name:", "\"" transport_service_name "\""; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 ShadowTLS Windows 客户端配置 -function generate_shadowtls_win_client_config() { - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local proxy_name - local shadowtls_out - - if [[ -n "$multiplex_config" && -n "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false,\n \"brutal\": {\n \"enabled\": true,\n \"up_mbps\": $down_mbps,\n \"down_mbps\": $up_mbps\n }\n }" - elif [[ -n "$multiplex_config" && -z "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false\n }" - fi - - while true; do - proxy_name="shadowtls-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - shadowtls_out="stl-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$win_client_file" && ! grep -q "name: $shadowtls_out" "$win_client_file" && [ "$proxy_name" != "$shadowtls_out" ]; then - break - fi - done - - awk -v shadowtls_out="$shadowtls_out" -v proxy_name="$proxy_name" -v method="$method" -v ss_password="$ss_password" -v local_ip="$local_ip" -v listen_port="$listen_port" -v stls_password="$stls_password" -v user_input="$user_input" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"shadowsocks\","; print " \"tag\": \"" proxy_name "\","; print " \"method\": \"" method "\", "; print " \"password\": \"" ss_password "\","; print " \"detour\": \"" shadowtls_out "\""multiplex_client_config""; print " },"; print " {"; print " \"type\": \"shadowtls\","; print " \"tag\": \"" shadowtls_out "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port ","; print " \"version\": 3, "; print " \"password\": \""stls_password"\", "; print " \"tls\": {"; print " \"enabled\": true,"; print " \"server_name\": \"" user_input "\", "; print " \"utls\": {"; print " \"enabled\": true,"; print " \"fingerprint\": \"chrome\" "; print " }"; print " }"; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$win_client_file" > "$win_client_file.tmp" - - mv "$win_client_file.tmp" "$win_client_file" -} - -# 生成 ShadowTLS 手机客户端配置 -function generate_shadowtls_phone_client_config() { - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local proxy_name - local shadowtls_out - - if [[ -n "$multiplex_config" && -n "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false,\n \"brutal\": {\n \"enabled\": true,\n \"up_mbps\": $down_mbps,\n \"down_mbps\": $up_mbps\n }\n }" - elif [[ -n "$multiplex_config" && -z "$brutal_config" ]]; then - multiplex_client_config=",\n \"multiplex\": {\n \"enabled\": true,\n \"protocol\": \"h2mux\",\n \"max_connections\": 1,\n \"min_streams\": 4,\n \"padding\": false\n }" - fi - - while true; do - proxy_name="shadowtls-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - shadowtls_out="stl-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$phone_client_file" && ! grep -q "name: $shadowtls_out" "$phone_client_file" && [ "$proxy_name" != "$shadowtls_out" ]; then - break - fi - done - - awk -v shadowtls_out="$shadowtls_out" -v proxy_name="$proxy_name" -v method="$method" -v ss_password="$ss_password" -v local_ip="$local_ip" -v listen_port="$listen_port" -v stls_password="$stls_password" -v user_input="$user_input" -v multiplex_client_config="$multiplex_client_config" ' - /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"shadowsocks\","; print " \"tag\": \"" proxy_name "\","; print " \"method\": \"" method "\", "; print " \"password\": \"" ss_password "\","; print " \"detour\": \"" shadowtls_out "\""multiplex_client_config""; print " },"; print " {"; print " \"type\": \"shadowtls\","; print " \"tag\": \"" shadowtls_out "\","; print " \"server\": \"" local_ip "\", "; print " \"server_port\": " listen_port ","; print " \"version\": 3, "; print " \"password\": \""stls_password"\", "; print " \"tls\": {"; print " \"enabled\": true,"; print " \"server_name\": \"" user_input "\", "; print " \"utls\": {"; print " \"enabled\": true,"; print " \"fingerprint\": \"chrome\" "; print " }"; print " }"; print " },";} - /^ "outbounds": \[/ {print; getline; if ($0 ~ /^ \],$/) {print " \"" proxy_name "\""} else {print " \"" proxy_name "\", "} } - {print}' "$phone_client_file" > "$phone_client_file.tmp" - - mv "$phone_client_file.tmp" "$phone_client_file" -} - -# 生成 ShadowTLS Clash 客户端配置 -function generate_shadowtls_yaml() { - local filename="/usr/local/etc/sing-box/clash.yaml" - local proxy_name - - while true; do - proxy_name="shadowtls-$(head /dev/urandom | tr -dc '0-9' | head -c 4)" - if ! grep -q "name: $proxy_name" "$filename"; then - break - fi - done - - awk -v proxy_name="$proxy_name" -v method="$method" -v ss_password="$ss_password" -v local_ip="$local_ip" -v listen_port="$listen_port" -v stls_password="$stls_password" -v user_input="$user_input" '/^proxies:$/ {print; print " - name: " proxy_name; print " type: ss"; print " server:", local_ip; print " port:", listen_port; print " cipher:", method; print " password:", "\"" ss_password "\""; print " plugin: shadow-tls"; print " plugin-opts:"; print " host: \"" user_input "\""; print " password:", "\"" stls_password "\""; print " version: 3"; print ""; next} /- name: Proxy/ { print; flag_proxy=1; next } flag_proxy && flag_proxy++ == 3 { print " - " proxy_name } /- name: auto/ { print; flag_auto=1; next } flag_auto && flag_auto++ == 3 { print " - " proxy_name } 1' "$filename" > temp_file && mv temp_file "$filename" -} - -# 生成 NaiveProxy Windows 客户端配置 -function generate_naive_win_client_config() { - local naive_client_file="$naive_client_filename" - - sed -i -e "s,user_name,$user_name," -e "s,user_password,$user_password," -e "s,listen_port,$listen_port," -e "s,server_name,$domain," "$naive_client_file" - echo "电脑端配置文件已保存至$naive_client_file,请下载后使用!" -} - -# 提取节点配置中的协议类型和标签 -function extract_types_tags() { - local config_files=("$sing_box_config_file" "$juicity_config_file") - local detour_tag wireguard_type type tag - local i=0 max_length=0 - filtered_tags=() - types=() - - if [[ ! -f "$sing_box_config_file" && ! -f "$juicity_config_file" ]]; then - echo "未检测到节点配置,请搭建节点后再使用本选项!" - exit 1 - fi - - for cfg in "${config_files[@]}"; do - if [[ -f "$cfg" ]]; then - if [[ "$cfg" == "$sing_box_config_file" ]]; then - mapfile -t tags < <(jq -r '.inbounds[] | select(.tag != null) | .tag' "$cfg") - detour_tag=$(jq -r '.inbounds[] | select(.type == "shadowtls") | .detour' "$cfg") - wireguard_type=$(jq -r '(.endpoints // []) | map(select(.type == "wireguard") | .type)[]?' "$cfg") - for tag in "${tags[@]}"; do - [[ $tag != "$detour_tag" ]] && filtered_tags+=("$tag") - done - [[ -n "$wireguard_type" ]] && filtered_tags+=("wg-ep") - elif [[ "$cfg" == "$juicity_config_file" ]]; then - filtered_tags+=("juicity-in") - fi - - for tag in "${filtered_tags[@]:i}"; do - if [[ "$cfg" == "$sing_box_config_file" && "$tag" == "wg-ep" ]]; then - type="$wireguard_type" - elif [[ "$cfg" == "$sing_box_config_file" ]]; then - type=$(jq -r --arg tag "$tag" '.inbounds[] | select(.tag == $tag) | .type' "$cfg") - else - type="juicity" - fi - types[i]="$type" - (( ${#tag} > max_length )) && max_length=${#tag} - printf "%d). 协议类型: %-20s 入站标签: %s\n" "$((++i))" "$type" "$tag" - done - fi - done -} - -# 选择要删除的节点 -function select_node_choice() { - local choice valid_choice=false - - while [[ $valid_choice == false ]]; do - read -p "请选择要删除的节点配置(请输入对应的数字,输入 0 返回主菜单): " choice - if [[ $choice == 0 ]]; then - return 1 - elif [[ ! $choice =~ ^[0-9]+$ || $choice -lt 1 || $choice -gt ${#types[@]} ]]; then - echo -e "${RED}错误:无效的选择,请重新输入!${NC}" - else - valid_choice=true - fi - done - - selected_tag="${filtered_tags[choice-1]}" - selected_type="${types[choice-1]}" - if [[ "$selected_type" != "juicity" ]]; then - listen_port=$(jq -r --arg selected_tag "$selected_tag" '.inbounds[] | select(.tag == $selected_tag) | .listen_port' "$sing_box_config_file" | awk '{print int($0)}') - fi -} - -# 删除配置文件中相关配置 -function process_config_deletion() { - if [[ "$selected_type" == "wireguard" ]]; then - jq 'del(.endpoints)' "$sing_box_config_file" > "$temp_json" && mv "$temp_json" "$sing_box_config_file" - jq '.route.rules |= map(select(.outbound != "wg-ep"))' "$sing_box_config_file" > "$temp_json" && mv "$temp_json" "$sing_box_config_file" - jq 'del(.route.rule_set)' "$sing_box_config_file" > "$temp_json" && mv "$temp_json" "$sing_box_config_file" - elif [[ "$selected_type" == "juicity" ]]; then - systemctl stop juicity.service - systemctl disable juicity.service - rm -rf /etc/systemd/system/juicity.service - rm -rf /usr/local/etc/juicity - rm -rf /usr/local/bin/juicity-server - else - detour_tag=$(jq -r --arg selected_tag "$selected_tag" '.inbounds[] | select(.type == "shadowtls" and .tag == $selected_tag) | .detour' "$sing_box_config_file") - jq --arg selected_tag "$selected_tag" --arg detour_tag "$detour_tag" '.inbounds |= map(select(.tag != $selected_tag and .tag != $detour_tag))' "$sing_box_config_file" > "$temp_json" && mv "$temp_json" "$sing_box_config_file" - jq --arg selected_tag "$selected_tag" '.route.rules |= map(.inbound |= map(select(. != $selected_tag)))' "$sing_box_config_file" > "$temp_json" && mv "$temp_json" "$sing_box_config_file" - fi -} - -# 删除 output 中对应端口的条目 -function process_output_file_deletion() { - if [[ "$selected_type" != "wireguard" && "$selected_type" != "juicity" ]]; then - awk -v port="$listen_port" '$0 ~ "监听端口: " port {print; in_block=1; next} in_block && NF == 0 {in_block=0} !in_block' "$sing_box_output_file" > "$sing_box_output_file.tmp1" - mv "$sing_box_output_file.tmp1" "$sing_box_output_file" - awk -v port="$listen_port" '$0 ~ "监听端口: " port {start=NR; next} {lines[NR]=$0} END {for (i=1; i<=NR; i++) if (i < start - 4 || i > start) print lines[i]}' "$sing_box_output_file" > "$sing_box_output_file.tmp2" - mv "$sing_box_output_file.tmp2" "$sing_box_output_file" - sed -i '/./,$!d' "$sing_box_output_file" - fi -} - -# 提取 Clash 配置相关标签 -function process_clash_yaml_deletion() { - if [[ -f "$clash_yaml" && "$selected_type" != "juicity" ]]; then - awk '/proxies:/ {in_proxies_block=1} in_proxies_block && /- name:/ {name = $3} in_proxies_block && /port:/ {port = $2; print "Name:", name, "Port:", port}' "$clash_yaml" > "$temp_yaml" - matching_clash_tag=$(grep "Port: $listen_port" "$temp_yaml" | awk '{print $2}') - fi -} - -# 检查防火墙端口转发规则 -function process_firewall_rules_deletion() { - for table in iptables ip6tables; do - if command -v $table &> /dev/null; then - while read -r line; do - if [[ "$line" =~ (tcp|udp)[[:space:]]+dpts?:([0-9]+):([0-9]+)[^[:alnum:]]+to::([0-9]+) ]]; then - protocol="${BASH_REMATCH[1]}" - d_start="${BASH_REMATCH[2]}" - d_end="${BASH_REMATCH[3]}" - d_target="${BASH_REMATCH[4]}" - if [[ "$d_target" == "$listen_port" ]]; then - start_port="$d_start" - end_port="$d_end" - break 2 - fi - fi - done < <($table -t nat -nL PREROUTING) - fi - done -} - -# 提取客户端要删除的标签 -function process_client_files_deletion() { - if [[ -f "$phone_client_file" && -f "$win_client_file" ]]; then - if [[ -n "$listen_port" ]]; then - if [[ -n "$start_port" && -n "$end_port" ]]; then - phone_matching_tags=$(jq -r --arg target "$start_port:$end_port" '.outbounds[] | select((.server_ports // []) | index($target)) | .tag' "$phone_client_file") - win_matching_tags=$(jq -r --arg target "$start_port:$end_port" '.outbounds[] | select((.server_ports // []) | index($target)) | .tag' "$win_client_file") - else - phone_matching_tags=$(jq -r --argjson listen_port "$listen_port" '.outbounds[] | select(.server_port == $listen_port) | .tag' "$phone_client_file") - win_matching_tags=$(jq -r --argjson listen_port "$listen_port" '.outbounds[] | select(.server_port == $listen_port) | .tag' "$win_client_file") - fi - fi - delete_tags_from_client "$phone_matching_tags" "$phone_client_file" - delete_tags_from_client "$win_matching_tags" "$win_client_file" - fi -} - -# 更新客户端 JSON 配置和防火墙规则 -function delete_tags_from_client() { - local tags="$1" - local client_file="$2" - - if [[ ! -f "$client_file" ]]; then - return - fi - - echo "$tags" | while read -r tag; do - if [[ -n "$tag" ]]; then - if [[ -n "$start_port" && -n "$end_port" ]]; then - target_port_range="$start_port:$end_port" - tag_port_range=$(jq -r --arg tag "$tag" '.outbounds[] | select(.tag == $tag) | (.server_ports // [])[0]' "$client_file") - if [[ "$tag_port_range" == "$target_port_range" ]]; then - for table in iptables ip6tables; do - if command -v $table &> /dev/null; then - rules=$($table -t nat -nL PREROUTING --line-numbers) - echo "$rules" | while read -r line; do - if [[ "$line" =~ ^([0-9]+)[[:space:]].*(tcp|udp)[[:space:]]+dpts?:$start_port:$end_port.*to::[0-9]+ ]]; then - rule_num="${BASH_REMATCH[1]}" - $table -t nat -D PREROUTING "$rule_num" - fi - done - fi - done - fi - fi - - jq --arg tag "$tag" '.outbounds |= map(select(.tag != $tag))' "$client_file" > "$temp_json" && mv "$temp_json" "$client_file" - - local matching_detour=$(jq -r --arg tag "$tag" '.outbounds[] | select(.detour == $tag) | .detour' "$client_file") - local matching_detour_tag=$(jq -r --arg detour "$matching_detour" '.outbounds[] | select(.detour == $detour) | .tag' "$client_file") - - awk -v tag="$tag" '!/^ "outbounds": \[$/,/^\s*]/{if (!($0 ~ "^ * \"" tag "\"")) print; else next; }' "$client_file" > "$client_file.tmp" - mv "$client_file.tmp" "$client_file" - - if [[ "$tag" == "$matching_detour" ]]; then - jq --arg detour "$matching_detour" '.outbounds |= map(select(.detour != $detour))' "$client_file" > "$temp_json" && mv "$temp_json" "$client_file" - awk -v detour_tag="$matching_detour_tag" '!/^ "outbounds": \[$/,/^\s*]/{if (!($0 ~ "^ * \"" detour_tag "\"")) print; else next; }' "$client_file" > "$client_file.tmp" - mv "$client_file.tmp" "$client_file" - fi - fi - done -} - -# 整理客户端配置文件格式 -function cleanup_files_and_restart() { - if [[ -n "$matching_clash_tag" && "$selected_type" != "wireguard" ]]; then - echo "$matching_clash_tag" | while read -r tag; do - if [[ -n "$tag" ]]; then - escaped_tag=$(printf '%q' "$tag") - sed -i "/^ - name: $escaped_tag$/,/^\s*$/d" "$clash_yaml" - sed -i "/proxy-groups:/,/^\s*$/ {/ - $escaped_tag/d}" "$clash_yaml" - fi - done - fi - - if [[ -f "$phone_client_file" ]]; then - awk '{if ($0 ~ /],$/ && p ~ /,$/) sub(/,$/, "", p); if (NR > 1) print p; p = $0;}END{print p;}' "$phone_client_file" > "$phone_client_file.tmp" - mv "$phone_client_file.tmp" "$phone_client_file" - fi - - if [[ -f "$win_client_file" ]]; then - awk '{if ($0 ~ /],$/ && p ~ /,$/) sub(/,$/, "", p); if (NR > 1) print p; p = $0;}END{print p;}' "$win_client_file" > "$win_client_file.tmp" - mv "$win_client_file.tmp" "$win_client_file" - fi - - if [[ -f "$temp_yaml" ]]; then - rm "$temp_yaml" - fi - - if ! jq -e 'select(.inbounds[] | .listen == "::")' "$sing_box_config_file" > /dev/null; then - sed -i 's/^ "inbound": \[\],/ "inbound": [\n ],/' "$sing_box_config_file" - sed -i 's/^ "inbounds": \[\],/ "inbounds": [\n ],/' "$sing_box_config_file" - sed -i 's/^ "outbounds": \[\],/ "outbounds": [\n ],/' "$win_client_file" - sed -i 's/^ "outbounds": \[\],/ "outbounds": [\n ],/' "$phone_client_file" - fi - - update_client_file - systemctl restart sing-box -} - -# 删除指定节点的配置信息 -function delete_choice() { - local sing_box_config_file="/usr/local/etc/sing-box/config.json" - local juicity_config_file="/usr/local/etc/juicity/config.json" - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local sing_box_output_file="/usr/local/etc/sing-box/output.txt" - local clash_yaml="/usr/local/etc/sing-box/clash.yaml" - local temp_yaml="/usr/local/etc/sing-box/temp.yaml" - local temp_json="/usr/local/etc/sing-box/temp.json" - - extract_types_tags - if ! select_node_choice; then - return 1 - fi - process_config_deletion - process_output_file_deletion - process_clash_yaml_deletion - process_firewall_rules_deletion - process_client_files_deletion - cleanup_files_and_restart - - echo "已删除 $selected_type 的配置信息,服务端及客户端配置信息已更新,请下载新的配置文件使用!" -} - -# 显示 NaiveProxy 节点配置信息 -function display_naive_config_info() { - local config_file="/usr/local/etc/sing-box/config.json" - local output_file="/usr/local/etc/sing-box/output.txt" - local num_users=${#user_names[@]} - - echo -e "${CYAN}NaiveProxy 节点配置信息:${NC}" | tee -a "$output_file" - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "服务器地址: $domain" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "监听端口: $listen_port" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "用 户 名 密 码" | tee -a "$output_file" - echo "------------------------------------------------------------------------------" | tee -a "$output_file" - - for ((i=0; i> "$output_file" - echo "配置信息已保存至 $output_file" -} - -# 生成 NaiveProxy 客户端配置文件 -function generate_naive_config_files() { - local config_file="/usr/local/etc/sing-box/config.json" - local naive_client_file="$naive_client_filename" - local num_users=${#user_names[@]} - - for ((i=0; i> "$output_file" - echo "配置信息已保存至 $output_file" -} - -# 显示并生成 Juicity 节点配置信息 -function display_juicity_config() { - local config_file="/usr/local/etc/juicity/config.json" - local output_file="/usr/local/etc/juicity/output.txt" - local server_address - local congestion_control=$(jq -r '.congestion_control' "$config_file") - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - if [[ -z "$domain" ]]; then - server_address="$local_ip" - else - server_address="$domain" - fi - - echo -e "${CYAN}Juicity 节点配置信息:${NC}" | tee -a "$output_file" - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "服务器地址: $server_address" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "监听端口: $listen_port" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "UUID:$user_uuids 密码:$user_passwords " | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "拥塞控制算法: $congestion_control" | tee -a "$output_file" - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "" >> "$output_file" - - echo "分享链接:" - juicity-server generate-sharelink -c "$config_file" - - generate_juicity_win_client_config - echo "配置信息已保存至 $output_file" -} - -# 显示 HTTP 节点配置信息 -function display_http_config_info() { - local config_file="/usr/local/etc/sing-box/config.json" - local output_file="/usr/local/etc/sing-box/output.txt" - local num_users=${#user_names[@]} - local server_address - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - if [[ -z "$domain" ]]; then - server_address="$local_ip" - else - server_address="$domain" - fi - - echo -e "${CYAN}HTTP 节点配置信息:${NC}" | tee -a "$output_file" - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "服务器地址: $server_address" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "监听端口: $listen_port" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "用 户 名 密 码" | tee -a "$output_file" - echo "------------------------------------------------------------------------------" | tee -a "$output_file" - - for ((i=0; i> "$output_file" - echo "配置信息已保存至 $output_file" -} - -# 生成 HTTP 客户端配置文件 -function display_http_config_files() { - local config_file="/usr/local/etc/sing-box/config.json" - local clash_file="/usr/local/etc/sing-box/clash.yaml" - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local num_users=${#user_names[@]} - - for ((i=0; i> "$output_file" - echo "配置信息已保存至 $output_file" -} - -# 生成 AnyTLS 客户端配置文件 -function display_anytls_config_files() { - local config_file="/usr/local/etc/sing-box/config.json" - local clash_file="/usr/local/etc/sing-box/clash.yaml" - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local num_users=${#user_names[@]} - - for ((i=0; i> "$output_file" - echo "配置信息已保存至 $output_file" -} - -# 生成 TUIC 客户端配置文件 -function display_tuic_config_files() { - local config_file="/usr/local/etc/sing-box/config.json" - local clash_file="/usr/local/etc/sing-box/clash.yaml" - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local congestion_control=$(jq -r '.inbounds[0].congestion_control' "$config_file") - local alpn=$(jq -r '.inbounds[0].tls.alpn[0]' "$config_file") - local num_users=${#user_uuids[@]} - - for ((i=0; i> "$output_file" - echo "配置信息已保存至 $output_file" -} - -# 生成 Shadowsocks 客户端配置文件 -function display_Shadowsocks_config_files() { - local config_file="/usr/local/etc/sing-box/config.json" - local clash_file="/usr/local/etc/sing-box/clash.yaml" - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local ss_method=$(jq -r '.inbounds[0].method' "$config_file") - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - write_phone_client_file - write_win_client_file - generate_shadowsocks_win_client_config - generate_shadowsocks_phone_client_config - ensure_clash_yaml - write_clash_yaml - generate_shadowsocks_yaml - - echo "手机端配置文件已保存至 $phone_client_file,请下载后使用!" - echo "电脑端配置文件已保存至 $win_client_file,请下载后使用!" - echo "Clash配置文件已保存至 $clash_file,请下载使用!" -} - -# 显示 SOCKS 节点配置信息 -function display_socks_config_info() { - local config_file="/usr/local/etc/sing-box/config.json" - local output_file="/usr/local/etc/sing-box/output.txt" - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - echo -e "${CYAN}SOCKS 节点配置信息:${NC}" | tee -a "$output_file" - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "服务器地址: $local_ip" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "监听端口: $listen_port" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "用户密码列表:" | tee -a "$output_file" - echo "------------------------------------------------------------------------------" | tee -a "$output_file" - echo "用户名 密码" | tee -a "$output_file" - - for ((i=0; i<${#user_names[@]}; i++)); do - user_name="${user_names[$i]}" - user_password="${user_passwords[$i]}" - printf "%-35s %s\n" "$user_name" "$user_password" | tee -a "$output_file" - done - - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "" >> "$output_file" - echo "节点配置信息已保存至 $output_file" -} - -# 生成 SOCKS 客户端配置文件 -function display_socks_config_files() { - local config_file="/usr/local/etc/sing-box/config.json" - local clash_file="/usr/local/etc/sing-box/clash.yaml" - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local num_users=${#user_names[@]} - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - for ((i=0; i> "$output_file" - echo "配置信息已保存至 $output_file" -} - -# 生成 Hysteria 客户端配置文件 -function display_Hysteria_config_files() { - local config_file="/usr/local/etc/sing-box/config.json" - local clash_file="/usr/local/etc/sing-box/clash.yaml" - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local alpn=$(jq -r '.inbounds[0].tls.alpn[0]' "$config_file") - - for ((i=0; i<${#user_passwords[@]}; i++)); do - user_password="${user_passwords[$i]}" - - if [[ "$enable_ech" == true ]]; then - write_phone_client_file - write_win_client_file - generate_Hysteria_win_client_config "$user_password" - generate_Hysteria_phone_client_config "$user_password" - else - write_phone_client_file - write_win_client_file - generate_Hysteria_win_client_config "$user_password" - generate_Hysteria_phone_client_config "$user_password" - ensure_clash_yaml - write_clash_yaml - generate_Hysteria_yaml - fi - done - - if [[ "$enable_ech" == true ]]; then - echo "手机端配置文件已保存至$phone_client_file,请下载后使用!" - echo "电脑端配置文件已保存至$win_client_file,请下载后使用!" - else - echo "手机端配置文件已保存至$phone_client_file,请下载后使用!" - echo "电脑端配置文件已保存至$win_client_file,请下载后使用!" - echo "Clash配置文件已保存至 $clash_file,请下载使用!" - fi -} - -# 显示 Hysteria2 节点配置信息 -function display_Hy2_config_info() { - local config_file="/usr/local/etc/sing-box/config.json" - local output_file="/usr/local/etc/sing-box/output.txt" - local server_address - local alpn=$(jq -r '.inbounds[0].tls.alpn[0]' "$config_file") - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - if [[ -z "$domain" ]]; then - server_address="$local_ip" - else - server_address="$domain" - fi - - echo -e "${CYAN}Hysteria2 节点配置信息:${NC}" | tee -a "$output_file" - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "服务器地址:$server_address" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "监听端口: $listen_port" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "端口跳跃范围: $start_port:$end_port" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "上行速度:${up_mbps}Mbps" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "下行速度:${down_mbps}Mbps" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "ALPN:$alpn" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "用户名 密码" | tee -a "$output_file" - echo "------------------------------------------------------------------------------" | tee -a "$output_file" - - for ((i=0; i<${#user_names[@]}; i++)); do - user_name="${user_names[$i]}" - user_password="${user_passwords[$i]}" - printf "%-35s %s\n" "$user_name" "$user_password" | tee -a "$output_file" - done - - if [[ -n "$obfs_password" ]]; then - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "QUIC 流量混淆器密码:$obfs_password" | tee -a "$output_file" - fi - - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "" >> "$output_file" - echo "配置信息已保存至 $output_file" -} - -# 生成 Hysteria2 客户端配置文件 -function display_Hy2_config_files() { - local config_file="/usr/local/etc/sing-box/config.json" - local clash_file="/usr/local/etc/sing-box/clash.yaml" - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local alpn=$(jq -r '.inbounds[0].tls.alpn[0]' "$config_file") - - for ((i=0; i<${#user_passwords[@]}; i++)); do - user_password="${user_passwords[$i]}" - - if [[ "$enable_ech" == true ]]; then - write_phone_client_file - write_win_client_file - generate_Hysteria2_win_client_config "$user_password" - generate_Hysteria2_phone_client_config "$user_password" - else - write_phone_client_file - write_win_client_file - generate_Hysteria2_win_client_config "$user_password" - generate_Hysteria2_phone_client_config "$user_password" - ensure_clash_yaml - write_clash_yaml - generate_Hysteria2_yaml - fi - done - - if [[ "$enable_ech" == true ]]; then - echo "手机端配置文件已保存至$phone_client_file,请下载后使用!" - echo "电脑端配置文件已保存至$win_client_file,请下载后使用!" - else - echo "手机端配置文件已保存至$phone_client_file,请下载后使用!" - echo "电脑端配置文件已保存至$win_client_file,请下载后使用!" - echo "Clash配置文件已保存至 $clash_file,请下载使用!" - fi -} - -# 显示 VLESS 节点配置信息 -function display_reality_config_info() { - local config_file="/usr/local/etc/sing-box/config.json" - local output_file="/usr/local/etc/sing-box/output.txt" - local flow_type=$(jq -r '.inbounds[0].users[0].flow' "$config_file") - local transport_type=$(jq -r '.inbounds[0].transport.type' "$config_file") - local server_name=$(jq -r '.inbounds[0].tls.server_name' "$config_file") - local target_server=$(jq -r '.inbounds[0].tls.reality.handshake.server' "$config_file") - local transport_service_name=$(jq -r '.inbounds[0].transport.service_name' "$config_file") - local local_public_key="$public_key" - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - if [[ "$flow_type" == "xtls-rprx-vision" ]]; then - transport_type="tcp" - fi - - echo -e "${CYAN}VLESS 节点配置信息:${NC}" | tee -a "$output_file" - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "服务器地址: $local_ip" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "监听端口: $listen_port" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "UUID列表:" | tee -a "$output_file" - - for ((i=0; i<${#user_uuids[@]}; i++)); do - user_uuid="${user_uuids[$i]}" - echo "$user_uuid" | tee -a "$output_file" - done - - if [[ -n "$flow_type" ]]; then - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "流控类型: $flow_type" | tee -a "$output_file" - fi - - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - - if [[ "$transport_type" != "null" ]]; then - echo "传输协议: $transport_type" | tee -a "$output_file" - if [[ "$transport_type" == "ws" || "$transport_type" == "httpupgrade" ]]; then - echo "路径: $transport_path" | tee -a "$output_file" - elif [[ "$transport_type" == "grpc" ]]; then - echo "grpc-service-name: $transport_service_name" | tee -a "$output_file" - fi - else - echo "传输协议: tcp" | tee -a "$output_file" - fi - - if [[ -n "$server_name" && "$server_name" != "null" ]]; then - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "ServerName: $server_name" | tee -a "$output_file" - fi - - if [[ -n "$target_server" && "$target_server" != "null" ]]; then - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "目标网站地址: $target_server" | tee -a "$output_file" - fi - - if [[ -n "$short_id" ]]; then - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "Short ID:" | tee -a "$output_file" - for ((i=0; i<${#short_ids[@]}; i++)); do - short_id="${short_ids[$i]}" - echo "$short_id" | tee -a "$output_file" - done - fi - - if [[ -n "$public_key" ]]; then - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "PublicKey: $public_key" | tee -a "$output_file" - fi - - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "" >> "$output_file" - echo "配置信息已保存至 $output_file" -} - -# 生成 VLESS 客户端配置文件 -function display_reality_config_files() { - local config_file="/usr/local/etc/sing-box/config.json" - local clash_file="/usr/local/etc/sing-box/clash.yaml" - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local flow_type=$(jq -r '.inbounds[0].users[0].flow' "$config_file") - local transport_type=$(jq -r '.inbounds[0].transport.type' "$config_file") - local server_name=$(jq -r '.inbounds[0].tls.server_name' "$config_file") - local target_server=$(jq -r '.inbounds[0].tls.reality.handshake.server' "$config_file") - local transport_service_name=$(jq -r '.inbounds[0].transport.service_name' "$config_file") - local local_public_key="$public_key" - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - for ((i=0; i<${#user_uuids[@]}; i++)); do - local user_uuid="${user_uuids[$i]}" - write_phone_client_file - write_win_client_file - - if [[ "$server_name" == "null" ]] && [[ "$transport_type" == "null" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_vless_tcp_yaml - generate_vless_win_client_config - generate_vless_phone_client_config - elif [[ "$server_name" == "null" ]] && [[ "$transport_type" == "ws" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_vless_ws_yaml - generate_vless_win_client_config - generate_vless_phone_client_config - elif [[ "$server_name" == "null" ]] && [[ "$transport_type" == "grpc" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_vless_grpc_yaml - generate_vless_win_client_config - generate_vless_phone_client_config - elif [[ "$server_name" == "null" ]] && [[ "$transport_type" == "httpupgrade" ]]; then - generate_vless_win_client_config - generate_vless_phone_client_config - fi - - for ((j=0; j<${#short_ids[@]}; j++)); do - local short_id="${short_ids[$j]}" - write_phone_client_file - write_win_client_file - - if [[ -n "$server_name" ]] && [[ "$server_name" != "null" ]] && [[ "$transport_type" == "null" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_vless_reality_vision_yaml - generate_vless_win_client_config - generate_vless_phone_client_config - elif [[ -n "$server_name" ]] && [[ "$server_name" != "null" ]] && [[ "$transport_type" == "http" ]]; then - generate_vless_win_client_config - generate_vless_phone_client_config - elif [[ -n "$server_name" ]] && [[ "$server_name" != "null" ]] && [[ "$transport_type" == "grpc" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_vless_reality_grpc_yaml - generate_vless_win_client_config - generate_vless_phone_client_config - fi - done - done - - if [[ "$transport_type" != "http" && "$transport_type" != "httpupgrade" ]]; then - echo "Clash配置文件已保存至 $clash_file,请下载使用!" - fi - - echo "手机端配置文件已保存至$phone_client_file,请下载后使用!" - echo "电脑端配置文件已保存至$win_client_file,请下载后使用!" -} - -# 显示 VMess 节点配置信息 -function display_vmess_config_info() { - local config_file="/usr/local/etc/sing-box/config.json" - local output_file="/usr/local/etc/sing-box/output.txt" - local server_address - local transport_type=$(jq -r '.inbounds[0].transport.type' "$config_file") - local transport_path=$(jq -r '.inbounds[0].transport.path' "$config_file") - local transport_service_name=$(jq -r '.inbounds[0].transport.service_name' "$config_file") - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - if [[ -z "$domain" && -n "$domain_name" ]]; then - server_address="$local_ip" - elif [[ -z "$domain" && -z "$domain_name" ]]; then - server_address="$local_ip" - elif [[ -n "$domain" ]]; then - server_address="$domain" - fi - - echo -e "${CYAN}VMess 节点配置信息:${NC}" | tee -a "$output_file" - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "服务器地址: $server_address" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "监听端口: $listen_port" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "UUID列表:" | tee -a "$output_file" - echo "------------------------------------------------------------------------------" | tee -a "$output_file" - - for ((i=0; i<${#user_uuids[@]}; i++)); do - user_uuid="${user_uuids[$i]}" - echo "$user_uuid" | tee -a "$output_file" - done - - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - - if [[ "$transport_type" != "null" ]]; then - echo "传输协议: $transport_type" | tee -a "$output_file" - if [[ "$transport_type" == "ws" ]]; then - echo "路径: $transport_path" | tee -a "$output_file" - elif [[ "$transport_type" == "httpupgrade" ]]; then - echo "路径: $transport_path" | tee -a "$output_file" - elif [[ "$transport_type" == "grpc" ]]; then - echo "grpc-service-name: $transport_service_name" | tee -a "$output_file" - fi - else - echo "传输协议: tcp" | tee -a "$output_file" - fi - - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "" >> "$output_file" - echo "配置信息已保存至 $output_file" -} - -# 生成 VMess 客户端配置文件 -function display_vmess_config_files() { - local config_file="/usr/local/etc/sing-box/config.json" - local clash_file="/usr/local/etc/sing-box/clash.yaml" - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local transport_type=$(jq -r '.inbounds[0].transport.type' "$config_file") - local transport_path=$(jq -r '.inbounds[0].transport.path' "$config_file") - local transport_service_name=$(jq -r '.inbounds[0].transport.service_name' "$config_file") - local show_clash_message=true - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - for ((i=0; i<${#user_uuids[@]}; i++)); do - user_uuid="${user_uuids[$i]}" - write_phone_client_file - write_win_client_file - generate_vmess_win_client_config - generate_vmess_phone_client_config - - if [[ "$enable_ech" != true && -z "$domain" && -z "$domain_name" && "$transport_type" == "null" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_vmess_tcp_yaml - elif [[ "$enable_ech" != true && -z "$domain" && -z "$domain_name" && "$transport_type" == "ws" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_vmess_ws_yaml - elif [[ "$enable_ech" != true && -z "$domain" && -z "$domain_name" && "$transport_type" == "grpc" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_vmess_grpc_yaml - elif [[ "$enable_ech" != true && ( -n "$domain" || -n "$domain_name" ) && "$transport_type" == "null" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_vmess_tcp_tls_yaml - elif [[ "$enable_ech" != true && ( -n "$domain" || -n "$domain_name" ) && "$transport_type" == "ws" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_vmess_ws_tls_yaml - elif [[ "$enable_ech" != true && ( -n "$domain" || -n "$domain_name" ) && "$transport_type" == "grpc" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_vmess_grpc_tls_yaml - elif [[ "$enable_ech" != true && ( -n "$domain" || -n "$domain_name" ) && "$transport_type" == "http" ]]; then - show_clash_message=false - fi - done - - if [[ "$transport_type" == "http" || "$transport_type" == "httpupgrade" || "$enable_ech" == true ]]; then - echo "手机端配置文件已保存至$phone_client_file,请下载后使用!" - echo "电脑端配置文件已保存至$win_client_file,请下载后使用!" - else - echo "手机端配置文件已保存至$phone_client_file,请下载后使用!" - echo "电脑端配置文件已保存至$win_client_file,请下载后使用!" - echo "Clash配置文件已保存至 $clash_file,请下载使用!" - fi -} - -# 显示 Trojan 节点配置信息 -function display_trojan_config_info() { - local config_file="/usr/local/etc/sing-box/config.json" - local output_file="/usr/local/etc/sing-box/output.txt" - local server_address - local transport_type=$(jq -r '.inbounds[0].transport.type' "$config_file") - local transport_path=$(jq -r '.inbounds[0].transport.path' "$config_file") - local transport_service_name=$(jq -r '.inbounds[0].transport.service_name' "$config_file") - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - if [[ -z "$domain" && -n "$domain_name" ]]; then - server_address="$local_ip" - elif [[ -z "$domain" && -z "$domain_name" ]]; then - server_address="$local_ip" - elif [[ -n "$domain" ]]; then - server_address="$domain" - fi - - echo -e "${CYAN}Trojan 节点配置信息:${NC}" | tee -a "$output_file" - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "服务器地址: $server_address" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "监听端口: $listen_port" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "密码列表:" | tee -a "$output_file" - echo "------------------------------------------------------------------------------" | tee -a "$output_file" - - for ((i = 0; i < ${#user_passwords[@]}; i++)); do - user_password="${user_passwords[i]}" - echo "$user_password" | tee -a "$output_file" - done - - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - - if [[ "$transport_type" != "null" ]]; then - echo "传输协议: $transport_type" | tee -a "$output_file" - if [[ "$transport_type" == "ws" ]]; then - echo "路径: $transport_path" | tee -a "$output_file" - elif [[ "$transport_type" == "httpupgrade" ]]; then - echo "路径: $transport_path" | tee -a "$output_file" - elif [[ "$transport_type" == "grpc" ]]; then - echo "grpc-service-name: $transport_service_name" | tee -a "$output_file" - fi - else - echo "传输协议: tcp" | tee -a "$output_file" - fi - - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "" >> "$output_file" - echo "配置信息已保存至 $output_file" -} - -# 生成 Trojan 客户端配置文件 -function display_trojan_config_files() { - local config_file="/usr/local/etc/sing-box/config.json" - local clash_file="/usr/local/etc/sing-box/clash.yaml" - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local transport_type=$(jq -r '.inbounds[0].transport.type' "$config_file") - local transport_path=$(jq -r '.inbounds[0].transport.path' "$config_file") - local transport_service_name=$(jq -r '.inbounds[0].transport.service_name' "$config_file") - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - for ((i = 0; i < ${#user_passwords[@]}; i++)); do - user_password="${user_passwords[i]}" - write_phone_client_file - write_win_client_file - generate_trojan_win_client_config - generate_trojan_phone_client_config - - if [[ "$enable_ech" != true && ( -n "$domain" || -n "$domain_name" ) && "$transport_type" == "null" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_trojan_tcp_tls_yaml - elif [[ "$enable_ech" != true && ( -n "$domain" || -n "$domain_name" ) && "$transport_type" == "ws" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_trojan_ws_tls_yaml - elif [[ "$enable_ech" != true && ( -n "$domain" || -n "$domain_name" ) && "$transport_type" == "grpc" ]]; then - ensure_clash_yaml - write_clash_yaml - generate_trojan_grpc_tls_yaml - fi - done - - if [[ "$enable_ech" != true && ( -n "$domain" || -n "$domain_name" ) && "$transport_type" != "http" && "$transport_type" != "httpupgrade" ]]; then - echo "Clash配置文件已保存至 $clash_file,请下载使用!" - fi - - echo "手机端配置文件已保存至$phone_client_file,请下载后使用!" - echo "电脑端配置文件已保存至$win_client_file,请下载后使用!" -} - -# 显示 ShadowTLS 节点配置信息 -function display_shadowtls_config_info() { - local config_file="/usr/local/etc/sing-box/config.json" - local output_file="/usr/local/etc/sing-box/output.txt" - local user_input=$(jq -r '.inbounds[0].handshake.server' "$config_file") - local method=$(jq -r '.inbounds[1].method' "$config_file") - - if [[ -n "$ip_v4" ]]; then - local_ip="$ip_v4" - elif [[ -n "$ip_v6" ]]; then - local_ip="$ip_v6" - fi - - echo -e "${CYAN}ShadowTLS 节点配置信息:${NC}" | tee -a "$output_file" - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "服务器地址: $local_ip" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "监听端口: $listen_port" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "加密方式: $method" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "ShadowTLS用户名 ShadowTLS密码" | tee -a "$output_file" - echo "------------------------------------------------------------------------------" | tee -a "$output_file" - - for ((i = 0; i < ${#stls_passwords[@]}; i++)); do - local stls_password="${stls_passwords[i]}" - printf "%-25s %s\n" "$user_name" "$stls_password" | tee -a "$output_file" - done - - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "Shadowsocks 密码: $ss_passwords" | tee -a "$output_file" - echo -e "${CYAN}------------------------------------------------------------------------------${NC}" | tee -a "$output_file" - echo "握手服务器地址: $user_input" | tee -a "$output_file" - echo -e "${CYAN}==============================================================================${NC}" | tee -a "$output_file" - echo "" >> "$output_file" - echo "配置信息已保存至 $output_file" -} - -# 生成 ShadowTLS 客户端配置文件 -function display_shadowtls_config_files() { - local config_file="/usr/local/etc/sing-box/config.json" - local clash_file="/usr/local/etc/sing-box/clash.yaml" - local phone_client_file="/usr/local/etc/sing-box/phone_client.json" - local win_client_file="/usr/local/etc/sing-box/win_client.json" - local user_input=$(jq -r '.inbounds[0].handshake.server' "$config_file") - local method=$(jq -r '.inbounds[1].method' "$config_file") - - for ((i = 0; i < ${#stls_passwords[@]}; i++)); do - local stls_password="${stls_passwords[i]}" - write_phone_client_file - write_win_client_file - generate_shadowtls_win_client_config "$stls_password" - generate_shadowtls_phone_client_config "$stls_password" - ensure_clash_yaml - write_clash_yaml - generate_shadowtls_yaml - done - - echo "手机端配置文件已保存至$phone_client_file,请下载后使用!" - echo "电脑端配置文件已保存至$win_client_file,请下载后使用!" - echo "Clash配置文件已保存至 $clash_file,请下载使用!" -} - -# 查看已保存的配置信息文件 -function view_saved_config() { - local config_paths=( - "/usr/local/etc/sing-box/output.txt" - "/usr/local/etc/juicity/output.txt" - ) - local found=false - - for path in "${config_paths[@]}"; do - if [[ -f "$path" ]]; then - echo "配置信息文件 ($path):" - cat "$path" - found=true - fi - done - - if [[ "$found" == false ]]; then - echo "未找到保存的配置信息文件!" - fi -} - -# 卸载 sing-box -function uninstall_sing_box() { - echo "开始卸载 sing-box..." - systemctl stop sing-box - systemctl disable sing-box - rm -rf /usr/local/bin/sing-box - rm -rf /usr/local/etc/sing-box - rm -rf /etc/systemd/system/sing-box.service - - for table in iptables ip6tables; do - if command -v $table &> /dev/null; then - $table -t nat -F &>/dev/null - fi - done - - systemctl daemon-reload - echo "sing-box 卸载完成。" -} - -# 卸载 juicity -function uninstall_juicity() { - echo "开始卸载 juicity..." - systemctl stop juicity.service - systemctl disable juicity.service - rm -rf /etc/systemd/system/juicity.service - rm -rf /usr/local/etc/juicity - rm -rf /usr/local/bin/juicity-server - echo "juicity 卸载完成。" -} - -# 更新代理工具 -function update_proxy_tool() { - if [[ -e /usr/local/bin/juicity-server ]]; then - install_latest_juicity - fi - - if [[ -e /usr/local/bin/sing-box ]]; then - select_sing_box_install_option - fi -} - -# 卸载已安装的代理工具 -function uninstall() { - local uninstall_sing_box=false - local uninstall_juicity=false - - if [[ -f "/etc/systemd/system/sing-box.service" ]] || [[ -f "/usr/local/bin/sing-box" ]] || [[ -d "/usr/local/etc/sing-box/" ]]; then - uninstall_sing_box=true - fi - - if [[ -f "/etc/systemd/system/juicity.service" ]] || [[ -f "/usr/local/bin/juicity-server" ]] || [[ -d "/usr/local/etc/juicity/" ]]; then - uninstall_juicity=true - fi - - if [[ "$uninstall_sing_box" == true ]]; then - uninstall_sing_box - fi - - if [[ "$uninstall_juicity" == true ]]; then - uninstall_juicity - fi -} - -# 检查 WireGuard 配置 -function check_wireguard_config() { - local config_file="/usr/local/etc/sing-box/config.json" - - if grep -q "wireguard" "$config_file"; then - echo -e "${RED}Warp 已安装,请勿重复安装!${NC}" - exit 1 - fi -} - -# 更新安装脚本 -function Update_Script() { - wget -N -O /usr/local/bin/singbox.sh https://raw.githubusercontent.com/sky22333/shell/main/proxy/singbox.sh && chmod +x /usr/local/bin/singbox.sh && ln -sf /usr/local/bin/singbox.sh /usr/local/bin/singbox -} - -# 添加定时任务以自动更新证书 -function add_cron_job() { - if command -v crontab > /dev/null && crontab -l | grep -q "singbox.sh"; then - echo "Cron job already exists." - else - (crontab -l 2>/dev/null ; echo "0 3 * * 1 /bin/bash /root/singbox.sh 18 >> /usr/local/etc/certificate.log 2>&1") | crontab - - echo "Cron job added successfully." - fi -} - -# 查找 juicity 服务 -function check_juicity_installed() { - if systemctl list-unit-files | grep -q juicity.service && [[ -e /usr/local/etc/juicity ]]; then - echo -e "${RED}juicity 服务已安装,请不要重新安装!${NC}" - return - else - juicity_install - fi -} - -# 安装 Juicity 并配置相关服务 -function juicity_install() { - configure_dns64 - enable_bbr - create_juicity_folder - install_latest_juicity - get_local_ip - generate_juicity_config - add_cron_job - configure_juicity_service - systemctl daemon-reload - systemctl enable juicity.service - systemctl start juicity.service - systemctl restart juicity.service - display_juicity_config -} - -# 安装 Direct 并配置相关服务 -function Direct_install() { - install_sing_box - enable_bbr - log_outbound_config - set_listen_port - set_override_address - set_override_port - generate_Direct_config - modify_config_format - modify_route_rules - check_firewall_configuration - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - get_local_ip - display_Direct_config -} - -# 安装 Shadowsocks 并配置相关服务 -function Shadowsocks_install() { - install_sing_box - enable_bbr - log_outbound_config - set_listen_port - select_encryption_method - set_ss_password - generate_ss_config - modify_config_format - modify_route_rules - check_firewall_configuration - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - get_local_ip - display_Shadowsocks_config_info - display_Shadowsocks_config_files - update_client_file -} - -# 安装 SOCKS 并配置相关服务 -function socks_install() { - install_sing_box - enable_bbr - log_outbound_config - generate_socks_config - modify_config_format - modify_route_rules - check_firewall_configuration - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - get_local_ip - display_socks_config_info - display_socks_config_files - update_client_file -} - -# 安装 NaiveProxy 并配置相关服务 -function NaiveProxy_install() { - install_sing_box - enable_bbr - log_outbound_config - generate_naive_config - add_cron_job - modify_config_format - modify_route_rules - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - display_naive_config_info - generate_naive_config_files -} - -# 安装 HTTP 并配置相关服务 -function http_install() { - install_sing_box - enable_bbr - log_outbound_config - generate_http_config - add_cron_job - modify_config_format - modify_route_rules - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - display_http_config_info - display_http_config_files - update_client_file -} - -# 安装 AnyTLS 并配置相关服务 -function anytls_install() { - install_sing_box - enable_bbr - log_outbound_config - generate_anytls_config - add_cron_job - modify_config_format - modify_route_rules - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - display_anytls_config_info - display_anytls_config_files - update_client_file -} - -# 安装 Tuic 并配置相关服务 -function tuic_install() { - install_sing_box - enable_bbr - log_outbound_config - generate_tuic_config - add_cron_job - modify_config_format - modify_route_rules - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - get_local_ip - display_tuic_config_info - display_tuic_config_files - update_client_file -} - -# 安装 Hysteria 并配置相关服务 -function Hysteria_install() { - install_sing_box - enable_bbr - log_outbound_config - generate_Hysteria_config - add_cron_job - modify_config_format - modify_route_rules - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - display_Hysteria_config_info - display_Hysteria_config_files - update_client_file -} - -# 安装 ShadowTLS 并配置相关服务 -function shadowtls_install() { - install_sing_box - enable_bbr - log_outbound_config - generate_shadowtls_config - modify_config_format - modify_route_rules - check_firewall_configuration - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - get_local_ip - display_shadowtls_config_info - display_shadowtls_config_files - update_client_file -} - -# 安装 Reality 并配置相关服务 -function reality_install() { - install_sing_box - enable_bbr - log_outbound_config - generate_vless_config - modify_config_format - modify_route_rules - check_firewall_configuration - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - get_local_ip - display_reality_config_info - display_reality_config_files - update_client_file -} - -# 安装 Hysteria 2 并配置相关服务 -function Hysteria2_install() { - install_sing_box - enable_bbr - log_outbound_config - generate_Hy2_config - add_cron_job - modify_config_format - modify_route_rules - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - display_Hy2_config_info - display_Hy2_config_files - update_client_file -} - -# 安装 Trojan 并配置相关服务 -function trojan_install() { - install_sing_box - enable_bbr - log_outbound_config - generate_trojan_config - add_cron_job - modify_config_format - modify_route_rules - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - display_trojan_config_info - display_trojan_config_files - update_client_file -} - -# 安装 VMess 并配置相关服务 -function vmess_install() { - install_sing_box - enable_bbr - log_outbound_config - get_local_ip - generate_vmess_config - add_cron_job - modify_config_format - modify_route_rules - systemctl daemon-reload - systemctl enable sing-box - systemctl start sing-box - systemctl restart sing-box - display_vmess_config_info - display_vmess_config_files - update_client_file -} - -# 安装 WireGuard 并配置相关服务 -function wireguard_install() { - check_wireguard_config - check_config_file_existence - select_unlocked_items - geosite=() - update_rule_set - update_route_file - generate_warp_info - extract_variables_and_cleanup - Configure_endpoints - systemctl restart sing-box -} - -# 更新 TLS 证书 -function Update_certificate() { - get_local_ip - extract_tls_info - validate_tls_info - Reapply_certificates -} - -# 自动更新 TLS 证书 -function run_option() { - case "$1" in - "18") - Update_certificate - exit 0 - ;; - esac -} - -# 主菜单 -function main_menu() { -echo "╔════════════════════════════════════════════════════════════════════════╗" -echo -e "║ ${CYAN}脚本快捷方式${NC}: singbox ║" -echo "╠════════════════════════════════════════════════════════════════════════╣" -echo "║ 请选择要执行的操作: ║" -echo -e "║${CYAN} [1]${NC} SOCKS ${CYAN} [2]${NC} Direct ║" -echo -e "║${CYAN} [3]${NC} HTTP ${CYAN} [4]${NC} VMess ║" -echo -e "║${CYAN} [5]${NC} VLESS ${CYAN} [6]${NC} TUIC ║" -echo -e "║${CYAN} [7]${NC} Juicity ${CYAN} [8]${NC} AnyTLS ║" -echo -e "║${CYAN} [9]${NC} Trojan ${CYAN} [10]${NC} Hysteria ║" -echo -e "║${CYAN} [11]${NC} Hysteria2 ${CYAN} [12]${NC} ShadowTLS ║" -echo -e "║${CYAN} [13]${NC} NaiveProxy ${CYAN} [14]${NC} Shadowsocks ║" -echo -e "║${CYAN} [15]${NC} WireGuard ${CYAN} [16]${NC} 更新证书 ║" -echo -e "║${CYAN} [17]${NC} 节点信息 ${CYAN} [18]${NC} 节点管理 ║" -echo -e "║${CYAN} [19]${NC} 更新内核 ${CYAN} [20]${NC} 更新脚本 ║" -echo -e "║${CYAN} [21]${NC} 卸载 ${CYAN} [0]${NC} 退出 ║" -echo "╚════════════════════════════════════════════════════════════════════════╝" - - local choice - read -p "请选择 [0-21]: " choice - - case $choice in - 1) - socks_install - exit 0 - ;; - 2) - Direct_install - exit 0 - ;; - 3) - http_install - exit 0 - ;; - 4) - vmess_install - exit 0 - ;; - 5) - reality_install - exit 0 - ;; - 6) - tuic_install - exit 0 - ;; - 7) - check_juicity_installed - exit 0 - ;; - 8) - anytls_install - exit 0 - ;; - 9) - trojan_install - exit 0 - ;; - 10) - Hysteria_install - exit 0 - ;; - 11) - Hysteria2_install - exit 0 - ;; - 12) - shadowtls_install - exit 0 - ;; - 13) - NaiveProxy_install - exit 0 - ;; - 14) - Shadowsocks_install - exit 0 - ;; - 15) - wireguard_install - exit 0 - ;; - 16) - Update_certificate - ;; - 17) - view_saved_config - exit 0 - ;; - 18) - if delete_choice; then - exit 0 - else - main_menu - fi - ;; - 19) - update_proxy_tool - exit 0 - ;; - 20) - Update_Script - exit 0 - ;; - 21) - uninstall - exit 0 - ;; - 0) - echo "感谢使用脚本。再见!" - exit 0 - ;; - *) - echo -e "${RED}无效的选择,请重新输入。${NC}" - main_menu - ;; - esac -} - -# 检查依赖 -check_dependencies - -[[ ! -f /usr/local/bin/singbox ]] && Update_Script - -if [[ $# -eq 0 ]]; then - main_menu -else - run_option "$1" -fi - -main_menu