#!/bin/bash RED='\033[0;31m' CYAN='\033[0;36m' YELLOW='\033[0;33m' NC='\033[0m' disable_option=false listen_port="" override_port="" ip_v4="" ip_v6="" record_content="" record_type="" record_name="" obfs_password="" user_names=() user_passwords=() user_uuids=() ss_passwords=() stls_passwords=() short_ids=() domain="" domain_name="" up_mbps="" down_mbps="" certificate_path="" private_key_path="" public_key="" private_key="" function configure_dns64() { local ipv4_address local ipv6_address ipv4_address=$(curl -s4 ifconfig.co) ipv6_address=$(curl -s6 ifconfig.co) if [[ -n $ipv4_address ]]; then return fi if [[ -n $ipv6_address ]]; then echo "Check that the machine is IPv6 single-stack network, configure DNS64..." sed -i '/^nameserver /s/^/#/' /etc/resolv.conf echo "nameserver 2001:67c:2b0::4" >> /etc/resolv.conf echo "nameserver 2001:67c:2b0::6" >> /etc/resolv.conf echo "DNS64 configuration is complete." fi } function check_firewall_configuration() { local os_name=$(uname -s) local firewall 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="ip6tables" 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-persistent" elif systemctl is-active --quiet iptables.service; then firewall="iptables-service" 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..." case $firewall in ufw) if ! ufw status | grep -q "Status: active" 2>/dev/null; then ufw enable > /dev/null 2>&1 fi if ! ufw status | grep -q " $listen_port" 2>/dev/null; then ufw allow "$listen_port" > /dev/null 2>&1 fi if ! ufw status | grep -q " $override_port" 2>/dev/null; then ufw allow "$override_port" > /dev/null 2>&1 fi if ! ufw status | grep -q " $fallback_port" 2>/dev/null; then ufw allow "$fallback_port" > /dev/null 2>&1 fi if ! ufw status | grep -q " 80" 2>/dev/null; then ufw allow 80 > /dev/null 2>&1 fi echo "Firewall configuration has been updated." ;; iptables | iptables-persistent | iptables-service) if ! iptables -C INPUT -p tcp --dport "$listen_port" -j ACCEPT >/dev/null 2>&1; then iptables -A INPUT -p tcp --dport "$listen_port" -j ACCEPT > /dev/null 2>&1 fi if ! iptables -C INPUT -p udp --dport "$listen_port" -j ACCEPT >/dev/null 2>&1; then iptables -A INPUT -p udp --dport "$listen_port" -j ACCEPT > /dev/null 2>&1 fi if ! iptables -C INPUT -p tcp --dport "$override_port" -j ACCEPT >/dev/null 2>&1; then iptables -A INPUT -p tcp --dport "$override_port" -j ACCEPT > /dev/null 2>&1 fi if ! iptables -C INPUT -p udp --dport "$override_port" -j ACCEPT >/dev/null 2>&1; then iptables -A INPUT -p udp --dport "$override_port" -j ACCEPT > /dev/null 2>&1 fi if ! iptables -C INPUT -p tcp --dport "$fallback_port" -j ACCEPT >/dev/null 2>&1; then iptables -A INPUT -p tcp --dport "$fallback_port" -j ACCEPT > /dev/null 2>&1 fi if ! iptables -C INPUT -p udp --dport "$fallback_port" -j ACCEPT >/dev/null 2>&1; then iptables -A INPUT -p udp --dport "$fallback_port" -j ACCEPT > /dev/null 2>&1 fi if ! iptables -C INPUT -p tcp --dport 80 -j ACCEPT >/dev/null 2>&1; then iptables -A INPUT -p tcp --dport 80 -j ACCEPT > /dev/null 2>&1 fi if ! iptables -C INPUT -p udp --dport 80 -j ACCEPT >/dev/null 2>&1; then iptables -A INPUT -p udp --dport 80 -j ACCEPT > /dev/null 2>&1 fi if ! ip6tables -C INPUT -p tcp --dport "$listen_port" -j ACCEPT >/dev/null 2>&1; then ip6tables -A INPUT -p tcp --dport "$listen_port" -j ACCEPT > /dev/null 2>&1 fi if ! ip6tables -C INPUT -p udp --dport "$listen_port" -j ACCEPT >/dev/null 2>&1; then ip6tables -A INPUT -p udp --dport "$listen_port" -j ACCEPT > /dev/null 2>&1 fi if ! ip6tables -C INPUT -p tcp --dport "$override_port" -j ACCEPT >/dev/null 2>&1; then ip6tables -A INPUT -p tcp --dport "$override_port" -j ACCEPT > /dev/null 2>&1 fi if ! ip6tables -C INPUT -p udp --dport "$override_port" -j ACCEPT >/dev/null 2>&1; then ip6tables -A INPUT -p udp --dport "$override_port" -j ACCEPT > /dev/null 2>&1 fi if ! ip6tables -C INPUT -p tcp --dport "$fallback_port" -j ACCEPT >/dev/null 2>&1; then ip6tables -A INPUT -p tcp --dport "$fallback_port" -j ACCEPT > /dev/null 2>&1 fi if ! ip6tables -C INPUT -p udp --dport "$fallback_port" -j ACCEPT >/dev/null 2>&1; then ip6tables -A INPUT -p udp --dport "$fallback_port" -j ACCEPT > /dev/null 2>&1 fi if ! ip6tables -C INPUT -p tcp --dport 80 -j ACCEPT >/dev/null 2>&1; then ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT > /dev/null 2>&1 fi if ! ip6tables -C INPUT -p udp --dport 80 -j ACCEPT >/dev/null 2>&1; then ip6tables -A INPUT -p udp --dport 80 -j ACCEPT > /dev/null 2>&1 fi if [[ -e /etc/iptables/rules.v4 ]]; then iptables-save > /etc/iptables/rules.v4 elif [[ -e /etc/sysconfig/iptables ]]; then iptables-save > /etc/sysconfig/iptables fi if [[ -e /etc/iptables/rules.v6 ]]; then ip6tables-save > /etc/iptables/rules.v6 elif [[ -e /etc/sysconfig/ip6tables ]]; then ip6tables-save > /etc/sysconfig/ip6tables fi echo "Firewall configuration has been updated." ;; firewalld) if ! firewall-cmd --zone=public --list-ports | grep -q "$listen_port/tcp" 2>/dev/null; then firewall-cmd --zone=public --add-port="$listen_port/tcp" --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "$listen_port/udp" 2>/dev/null; then firewall-cmd --zone=public --add-port="$listen_port/udp" --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "$override_port/tcp" 2>/dev/null; then firewall-cmd --zone=public --add-port="$override_port/tcp" --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "$override_port/udp" 2>/dev/null; then firewall-cmd --zone=public --add-port="$override_port/udp" --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "$fallback_port/tcp" 2>/dev/null; then firewall-cmd --zone=public --add-port="$fallback_port/tcp" --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "$fallback_port/udp" 2>/dev/null; then firewall-cmd --zone=public --add-port="$fallback_port/udp" --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "80/tcp" 2>/dev/null; then firewall-cmd --zone=public --add-port=80/tcp --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "80/udp" 2>/dev/null; then firewall-cmd --zone=public --add-port=80/udp --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "$listen_port/tcp" 2>/dev/null; then firewall-cmd --zone=public --add-port="$listen_port/tcp" --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "$listen_port/udp" 2>/dev/null; then firewall-cmd --zone=public --add-port="$listen_port/udp" --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "$override_port/tcp" 2>/dev/null; then firewall-cmd --zone=public --add-port="$override_port/tcp" --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "$override_port/udp" 2>/dev/null; then firewall-cmd --zone=public --add-port="$override_port/udp" --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "$fallback_port/tcp" 2>/dev/null; then firewall-cmd --zone=public --add-port="$fallback_port/tcp" --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "$fallback_port/udp" 2>/dev/null; then firewall-cmd --zone=public --add-port="$fallback_port/udp" --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "80/tcp" 2>/dev/null; then firewall-cmd --zone=public --add-port=80/tcp --permanent > /dev/null 2>&1 fi if ! firewall-cmd --zone=public --list-ports | grep -q "80/udp" 2>/dev/null; then firewall-cmd --zone=public --add-port=80/udp --permanent > /dev/null 2>&1 fi firewall-cmd --reload echo "Firewall configuration has been updated." ;; esac } function create_sing_box_folder() { local folder="/usr/local/etc/sing-box" if [[ ! -d "$folder" ]]; then mkdir -p "$folder" fi touch "$folder/config.json" } function create_ssl_folder() { local ssl_folder="/etc/ssl/private" if [[ ! -d "$ssl_folder" ]]; then mkdir -p "$ssl_folder" fi } function create_juicity_folder() { local folder="/usr/local/etc/juicity" if [[ ! -d "$folder" ]]; then mkdir -p "$folder" fi } function ensure_clash_yaml() { local dir="/usr/local/etc/sing-box" local clash_yaml="${dir}/clash.yaml" if [ ! -e "${clash_yaml}" ]; then touch "${clash_yaml}" fi } 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 } 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 } function check_sing_box_existence() { if [[ -f "/usr/local/bin/sing-box" ]]; then return 1 else return 0 fi } function install_sing_box() { check_sing_box_existence local result=$? if [[ $result -eq 0 ]]; then configure_dns64 select_sing_box_install_option configure_sing_box_service create_sing_box_folder create_ssl_folder fi } 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,默认Y)? " -i "y" response response=${response:-"y"} 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 } function select_sing_box_install_option() { while true; do echo "请选择 sing-box 的安装方式(默认1):" echo "1). 下载安装 sing-box(Latest 版本)" echo "2). 下载安装 sing-box(Beta 版本)" echo "3). 编译安装 sing-box(完整功能版本)" local install_option 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 ;; 3) install_go compile_install_sing_box break ;; *) echo -e "${RED}无效的选择,请重新输入!${NC}" ;; esac done } function install_go() { if ! command -v go &> /dev/null; then echo "Downloading Go..." local go_arch case $(uname -m) in x86_64) go_arch="amd64" ;; i686) go_arch="386" ;; aarch64) go_arch="arm64" ;; armv6l) go_arch="armv6l" ;; *) echo -e "${RED}不支持的架构: $(uname -m)${NC}" exit 1 ;; esac local go_version go_version=$(curl -sL "https://golang.org/VERSION?m=text" | grep -o 'go[0-9]\+\.[0-9]\+\.[0-9]\+') local go_download_url="https://go.dev/dl/$go_version.linux-$go_arch.tar.gz" wget -qO- "$go_download_url" | tar -xz -C /usr/local echo 'export PATH=$PATH:/usr/local/go/bin' | tee -a /etc/profile >/dev/null source /etc/profile go version echo "Go has been installed." else echo "Go is already installed, skipping installation." fi } function compile_install_sing_box() { local go_install_command="go install -v -tags \ with_quic,\ with_grpc,\ with_dhcp,\ with_wireguard,\ with_shadowsocksr,\ with_ech,\ with_utls,\ with_reality_server,\ with_acme,\ with_clash_api,\ with_v2ray_api,\ with_gvisor,\ with_lwip \ github.com/sagernet/sing-box/cmd/sing-box@latest" echo "Compiling and installing sing-box, please wait..." $go_install_command if [[ $? -eq 0 ]]; then mv ~/go/bin/sing-box /usr/local/bin/ chmod +x /usr/local/bin/sing-box echo "sing-box has been compiled and installed successfully." else echo -e "${RED}sing-box compilation and installation failed.${NC}" exit 1 fi } function install_latest_sing_box() { local arch=$(uname -m) local url="https://api.github.com/repos/SagerNet/sing-box/releases/latest" local download_url 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}" 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 retrieve the download URL for Sing-Box.${NC}" return 1 fi } 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 } 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" } function get_temp_config_file() { temp_file=$(mktemp) curl -sSL "https://api.zeroteam.top/warp?format=sing-box" > "$temp_file" } 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." } 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 "请输入监听端口 (默认443): " new_listen_port new_listen_port=${new_listen_port:-443} if [[ $new_listen_port =~ ^[1-9][0-9]{0,4}$ && $new_listen_port -le 65535 ]]; then echo "监听端口:$new_listen_port" break 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") } 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 } 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" } 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 || openssl rand -hex 16 | awk '{print substr($1,1,8) "-" substr($1,9,4) "-" substr($1,13,4) "-" substr($1,17,4) "-" substr($1,21)}') 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 "请输入目标端口 (默认443): " new_override_port new_override_port=${new_override_port:-443} 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" } 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 } 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 } 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 } 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" } 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 } 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 } 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 } 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 } 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.fan-2000.com): " fake_domain fake_domain=${fake_domain:-"www.fan-2000.com"} if curl --output /dev/null --silent --head --fail "$fake_domain"; then echo "伪装网址: $fake_domain" break else echo -e "${RED}伪装网址无效或不可用,请重新输入!${NC}" fi done } 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 } 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 } 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") 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 == *"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 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" } 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+ 请选择[1-3]: " choices if [[ "$choices" =~ ^[123]+$ ]]; then selected=($(echo "$choices" | sed 's/./& /g')) break else echo -e "${RED}错误:无效的选择,请重新输入!${NC}" fi done } function update_geosite_array() { for choice in "${selected[@]}"; do case $choice in 1) geosite+=("\"openai\"") ;; 2) geosite+=("\"netflix\"") ;; 3) geosite+=("\"disney\"") ;; *) echo -e "${RED}无效的选择: $choice${NC}" ;; esac done } function select_outbound() { while true; do read -p "请选择出站网络 (默认1) 1). warp-IPv4 2). warp-IPv6 请选择[1-2]: " outbound_choice case $outbound_choice in 1|"") outbound="warp-IPv4-out" break ;; 2) outbound="warp-IPv6-out" break ;; *) echo -e "${RED}错误:无效的选项,请重新输入!${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 } function select_vmess_type() { while true; do read -p "请选择节点类型(默认1): 1). VMess+TCP 2). VMess+WebSocket 3). VMess+gRPC 4). VMess+TCP+TLS 5). VMess+WebSocket+TLS 6). VMess+H2C+TLS 7). VMess+gRPC+TLS 请选择 [1-7]: " node_type case $node_type in "" | 1) transport_removed=true tls_enabled=false break ;; 2) transport_removed=false tls_enabled=false break ;; 3) transport_removed=false tls_enabled=false break ;; 4) transport_removed=true tls_enabled=true break ;; 5) transport_removed=false tls_enabled=true break ;; 6) transport_removed=false tls_enabled=true break ;; 7) transport_removed=false tls_enabled=true break ;; *) echo -e "${RED}无效的选择,请重新输入!${NC}" ;; esac done } function select_vless_type() { while true; do read -p "请选择节点类型 (默认1): 1). VLESS+TCP 2). VLESS+WebSocket 3). VLESS+gRPC 4). VLESS+Vision+REALITY 5). VLESS+H2C+REALITY 6). VLESS+gRPC+REALITY 请选择[1-6]: " flow_option case $flow_option in "" | 1) flow_type="" transport_removed=true reality_enabled=false break ;; 2) flow_type="" transport_removed=false reality_enabled=false break ;; 3) flow_type="" transport_removed=false reality_enabled=false break ;; 4) flow_type="xtls-rprx-vision" transport_removed=true reality_enabled=true break ;; 5) flow_type="" transport_removed=false reality_enabled=true break ;; 6) flow_type="" transport_removed=false reality_enabled=true break ;; *) echo -e "${RED}错误的选项,请重新输入!${NC}" >&2 ;; esac done } function select_trojan_type() { while true; do read -p "请选择节点类型(默认1): 1). Trojan+TCP 2). Trojan+WebSocket 3). Trojan+gRPC 4). Trojan+TCP+TLS 5). Trojan+WebSocket+TLS 6). Trojan+H2C+TLS 7). Trojan+gRPC+TLS 请选择 [1-7]: " setup_type case $setup_type in "" | 1) transport_removed=true tls_enabled=false break ;; 2) transport_removed=false tls_enabled=false break ;; 3) transport_removed=false tls_enabled=false break ;; 4) transport_removed=true tls_enabled=true break ;; 5) transport_removed=false tls_enabled=true break ;; 6) transport_removed=false tls_enabled=true break ;; 7) transport_removed=false tls_enabled=true break ;; *) echo -e "${RED}无效的选择,请重新输入!${NC}" ;; esac done } 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") } function set_short_ids() { while true; do set_short_id for ((i=0; i<${#short_ids[@]}; i++)); do short_id="${short_ids[$i]}" done read -p "是否继续添加 short id?(Y/N,默认N): " -e choice if [[ -z "$choice" ]]; then choice="N" fi if [[ "$choice" == "N" || "$choice" == "n" ]]; then short_Ids+=" \"$short_id\"" break elif [[ "$choice" == "Y" || "$choice" == "y" ]]; then short_Ids+=" \"$short_id\"," continue else echo -e "${RED}无效的输入,请重新输入!${NC}" fi done } 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 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+=" { \"name\": \"$user_name\", \"uuid\": \"$user_uuid\", \"password\": \"$user_password\" }" break elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then users+=" { \"name\": \"$user_name\", \"uuid\": \"$user_uuid\", \"password\": \"$user_password\" }," continue else echo -e "${RED}无效的输入,请重新输入!${NC}" fi done } function vmess_multiple_users() { while true; do set_uuid for ((i=0; i<${#user_uuids[@]}; i++)); do user_uuid="${user_uuids[$i]}" done 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+=" { \"uuid\": \"$user_uuid\", \"alterId\": 0 }" break elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then users+=" { \"uuid\": \"$user_uuid\", \"alterId\": 0 }," continue else echo -e "${RED}无效的输入,请重新输入!${NC}" fi done } function vless_multiple_users() { while true; do set_uuid for ((i=0; i<${#user_uuids[@]}; i++)); do user_uuid="${user_uuids[$i]}" done 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+=" { \"uuid\": \"$user_uuid\", \"flow\": \"$flow_type\" }" break elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then users+=" { \"uuid\": \"$user_uuid\", \"flow\": \"$flow_type\" }," continue else echo -e "${RED}无效的输入,请重新输入!${NC}" fi done } 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 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+=" { \"username\": \"$user_name\", \"password\": \"$user_password\" }" break elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then users+=" { \"username\": \"$user_name\", \"password\": \"$user_password\" }," continue else echo -e "${RED}无效的输入,请重新输入!${NC}" fi done } 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 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+=" { \"name\": \"$user_name\", \"auth_str\": \"$user_password\" }" break elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then users+=" { \"name\": \"$user_name\", \"auth_str\": \"$user_password\" }," continue else echo -e "${RED}无效的输入,请重新输入!${NC}" fi done } 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 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+=" { \"name\": \"$user_name\", \"password\": \"$user_password\" }" break elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then users+=" { \"name\": \"$user_name\", \"password\": \"$user_password\" }," continue else echo -e "${RED}无效的输入,请重新输入!${NC}" fi done } function trojan_multiple_users() { while true; do set_user_password for ((i=0; i<${#user_passwords[@]}; i++)); do user_password="${user_passwords[$i]}" done 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+=" { \"password\": \"$user_password\" }" break elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then users+=" { \"password\": \"$user_password\" }," continue else echo -e "${RED}无效的输入,请重新输入!${NC}" fi done } 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 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+=" { \"name\": \"$user_name\", \"password\": \"$stls_password\" }" break elif [[ "$add_multiple_users" == "Y" || "$add_multiple_users" == "y" ]]; then users+=" { \"name\": \"$user_name\", \"password\": \"$stls_password\" }," continue else echo -e "${RED}无效的输入,请重新输入!${NC}" fi done } function generate_transport_config() { if [[ $node_type == 2 || $node_type == 5 || $flow_option == 2 || $setup_type == 2 || $setup_type == 5 ]]; 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=" \"transport\": { \"type\": \"ws\", \"path\": \"$transport_path\", \"max_early_data\": 2048, \"early_data_header_name\": \"Sec-WebSocket-Protocol\" }," elif [[ $node_type == 3 || $node_type == 7 || $flow_option == 3 || $flow_option == 6 || $setup_type == 3 || $setup_type == 7 ]]; then service_name=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 8) transport_config=" \"transport\": { \"type\": \"grpc\", \"service_name\": \"$service_name\" }," elif [[ $node_type == 6 || $flow_option == 5 || $setup_type == 6 ]]; then transport_config=" \"transport\": { \"type\": \"http\" }," else transport_config="" fi } function generate_tls_config() { if [[ $node_type == 4 || $node_type == 5 || $node_type == 6 || $node_type == 7 || $setup_type == 4 || $setup_type == 5 || $setup_type == 6 || $setup_type == 7 ]]; then tls_enabled=true select_certificate_option else tls_enabled=false 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=", \"tls\": { \"enabled\": true, \"server_name\": \"$server_name\", \"certificate_path\": \"$certificate_path\", \"key_path\": \"$private_key_path\" }" else tls_config="" fi } function generate_reality_config() { if [[ $flow_option == 4 || $flow_option == 5 || $flow_option == 6 ]]; then reality_enabled=true set_server_name set_target_server generate_private_key set_short_ids else reality_enabled=false fi if [ "$reality_enabled" = true ]; then reality_config=", \"tls\": { \"enabled\": true, \"server_name\": \"$server_name\", \"reality\": { \"enabled\": true, \"handshake\": { \"server\": \"$target_server\", \"server_port\": 443 }, \"private_key\": \"$private_key\", \"short_id\": [$short_Ids ] } }" else reality_config="" fi } 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=" \"obfs\": { \"type\": \"salamander\", \"password\": \"$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_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=" \"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 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" } 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 extract_variables_and_cleanup() { server=$(jq -r '.server' "$temp_file") server_port=$(jq -r '.server_port' "$temp_file") local_address_ipv4=$(jq -r '.local_address[0]' "$temp_file") local_address_ipv6=$(jq -r '.local_address[1]' "$temp_file") private_key=$(jq -r '.private_key' "$temp_file") peer_public_key=$(jq -r '.peer_public_key' "$temp_file") reserved=$(jq -c '.reserved' "$temp_file") mtu=$(jq -r '.mtu' "$temp_file") rm "$temp_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 },' "$config_file" sed -i '/"outbounds": \[/!b;n;c\ {\n "type": "direct",\n "tag": "direct"\n }\n ]' "$config_file" fi } function modify_format_inbounds_and_outbounds() { file_path="/usr/local/etc/sing-box/config.json" start_line_inbounds=$(grep -n '"inbounds": \[' "$file_path" | cut -d: -f1) start_line_outbounds=$(grep -n '"outbounds": \[' "$file_path" | cut -d: -f1) if [ -n "$start_line_inbounds" ]; then line_to_modify_inbounds=$((start_line_inbounds - 3)) if [ "$line_to_modify_inbounds" -ge 1 ]; then sed -i "$line_to_modify_inbounds s/,//" "$file_path" fi fi 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 } function generate_Direct_config() { local config_file="/usr/local/etc/sing-box/config.json" local tag_label generate_unique_tag local found_rules=0 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" ' /"rules": \[/{found_rules=1} /"inbounds": \[/{found_inbounds=1} {print} found_rules && /"rules": \[/{print " {"; print " \"inbound\": [\"" tag_label "\"],"; print " \"outbound\": \"direct\""; print " },"; found_rules=0} found_inbounds && /"inbounds": \[/{print " {"; print " \"type\": \"direct\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"sniff\": true,"; print " \"sniff_override_destination\": true,"; print " \"sniff_timeout\": \"300ms\","; 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" } function generate_ss_config() { local config_file="/usr/local/etc/sing-box/config.json" local tag_label generate_unique_tag local found_rules=0 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" ' /"rules": \[/{found_rules=1} /"inbounds": \[/{found_inbounds=1} {print} found_rules && /"rules": \[/{print " {"; print " \"inbound\": [\"" tag_label "\"],"; print " \"outbound\": \"direct\""; print " },"; found_rules=0} found_inbounds && /"inbounds": \[/{print " {"; print " \"type\": \"shadowsocks\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"sniff\": true,"; print " \"sniff_override_destination\": true,"; print " \"method\": \"" ss_method "\","; print " \"password\": \"" ss_password "\""; print " },"; found_inbounds=0} ' "$config_file" > "$config_file.tmp" mv "$config_file.tmp" "$config_file" } 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 get_local_ip generate_tls_config local cert_path="$certificate_path" local key_path="$private_key_path" check_firewall_configuration local found_rules=0 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" ' /"rules": \[/{found_rules=1} /"inbounds": \[/{found_inbounds=1} {print} found_rules && /"rules": \[/{print " {"; print " \"inbound\": [\"" tag_label "\"],"; print " \"outbound\": \"direct\""; print " },"; found_rules=0} found_inbounds && /"inbounds": \[/{print " {"; print " \"type\": \"vmess\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"sniff\": true,"; print " \"sniff_override_destination\": true," transport_config ""; print " \"users\": [" users ""; print " ]" tls_config ""; print " },"; found=0} ' "$config_file" > "$config_file.tmp" mv "$config_file.tmp" "$config_file" } 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_rules=0 local found_inbounds=0 awk -v tag_label="$tag_label" -v listen_port="$listen_port" -v users="$users" ' /"rules": \[/{found_rules=1} /"inbounds": \[/{found_inbounds=1} {print} found_rules && /"rules": \[/{print " {"; print " \"inbound\": [\"" tag_label "\"],"; print " \"outbound\": \"direct\""; print " },"; found_rules=0} found_inbounds && /"inbounds": \[/{print " {"; print " \"type\": \"socks\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"sniff\": true,"; print " \"sniff_override_destination\": true,"; print " \"users\": [" users ""; print " ]"; print " },"; found_inbounds=0} ' "$config_file" > "$config_file.tmp" mv "$config_file.tmp" "$config_file" } 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_rules=0 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" ' /"rules": \[/{found_rules=1} /"inbounds": \[/{found_inbounds=1} {print} found_rules && /"rules": \[/{print " {"; print " \"inbound\": [\"" tag_label "\"],"; print " \"outbound\": \"direct\""; print " },"; found_rules=0} found_inbounds && /"inbounds": \[/{print " {"; print " \"type\": \"naive\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"sniff\": true,"; print " \"sniff_override_destination\": true,"; 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" } 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 select_certificate_option local cert_path="$certificate_path" local key_path="$private_key_path" local found_rules=0 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" ' /"rules": \[/{found_rules=1} /"inbounds": \[/{found_inbounds=1} {print} found_rules && /"rules": \[/{print " {"; print " \"inbound\": [\"" tag_label "\"],"; print " \"outbound\": \"direct\""; print " },"; found_rules=0} found_inbounds && /"inbounds": \[/{print " {"; print " \"type\": \"tuic\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"sniff\": true,"; print " \"sniff_override_destination\": true,"; 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 "\""; print " }"; print " },"; found_inbounds=0} ' "$config_file" > "$config_file.tmp" mv "$config_file.tmp" "$config_file" } 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 select_certificate_option local cert_path="$certificate_path" local key_path="$private_key_path" local found_rules=0 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" ' /"rules": \[/{found_rules=1} /"inbounds": \[/{found_inbounds=1} {print} found_rules && /"rules": \[/{print " {"; print " \"inbound\": [\"" tag_label "\"],"; print " \"outbound\": \"direct\""; print " },"; found_rules=0} found_inbounds && /"inbounds": \[/{print " {"; print " \"type\": \"hysteria\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"sniff\": true,"; print " \"sniff_override_destination\": true,"; 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 "\""; print " }"; print " },"; found_inbounds=0} ' "$config_file" > "$config_file.tmp" mv "$config_file.tmp" "$config_file" } 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 local found_rules=0 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" ' /"rules": \[/{found_rules=1} /"inbounds": \[/{found_inbounds=1} {print} found_rules && /"rules": \[/{print " {"; print " \"inbound\": [\"" tag_label1 "\"],"; print " \"outbound\": \"direct\""; print " },"; found_rules=0} 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 " \"network\": \"tcp\","; print " \"method\": \"" ss_method "\","; print " \"password\": \"" ss_password "\""; print " },"; found=0} ' "$config_file" > "$config_file.tmp" mv "$config_file.tmp" "$config_file" } function generate_juicity_config() { local config_file="/usr/local/etc/juicity/config.json" local users="" set_listen_port set_uuid set_user_password users="\"$user_uuids\": \"$user_passwords\"" select_congestion_control get_local_ip select_certificate_option local cert_path="$certificate_path" local key_path="$private_key_path" echo "{ \"listen\": \":$listen_port\", \"users\": { $users }, \"certificate\": \"$certificate_path\", \"private_key\": \"$private_key_path\", \"congestion_control\": \"$congestion_control\", \"log_level\": \"info\" }" > "$config_file" } 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 local found_rules=0 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" ' /"rules": \[/{found_rules=1} /"inbounds": \[/{found_inbounds=1} {print} found_rules && /"rules": \[/{print " {"; print " \"inbound\": [\"" tag_label "\"],"; print " \"outbound\": \"direct\""; print " },"; found_rules=0} found_inbounds && /"inbounds": \[/{print " {"; print " \"type\": \"vless\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"sniff\": true,"; print " \"sniff_override_destination\": true," transport_config ""; print " \"users\": [" users ""; print " ]"reality_config""; print " },"; found=0} ' "$config_file" > "$config_file.tmp" mv "$config_file.tmp" "$config_file" } 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 select_certificate_option local cert_path="$certificate_path" local key_path="$private_key_path" local found_rules=0 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" ' /"rules": \[/{found_rules=1} /"inbounds": \[/{found_inbounds=1} {print} found_rules && /"rules": \[/{print " {"; print " \"inbound\": [\"" tag_label "\"],"; print " \"outbound\": \"direct\""; print " },"; found_rules=0} found_inbounds && /"inbounds": \[/{print " {"; print " \"type\": \"hysteria2\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"sniff\": true,"; print " \"sniff_override_destination\": true,"; 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 "\""; print " }"; print " },"; found=0} ' "$config_file" > "$config_file.tmp" mv "$config_file.tmp" "$config_file" } 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 get_local_ip generate_tls_config local cert_path="$certificate_path" local key_path="$private_key_path" check_firewall_configuration local found_rules=0 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" ' /"rules": \[/{found_rules=1} /"inbounds": \[/{found_inbounds=1} {print} found_rules && /"rules": \[/{print " {"; print " \"inbound\": [\"" tag_label "\"],"; print " \"outbound\": \"direct\""; print " },"; found_rules=0} found_inbounds && /"inbounds": \[/{print " {"; print " \"type\": \"trojan\","; print " \"tag\": \"" tag_label "\","; print " \"listen\": \"::\","; print " \"listen_port\": " listen_port ","; print " \"sniff\": true,"; print " \"sniff_override_destination\": true," transport_config ""; print " \"users\": [" users ""; print " ]" tls_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 "${geosite[*]}") local geosite_formatted=$(sed 's/,/,\\n /g' <<< "$geosite_list") sed -i '/"rules": \[/!b;a\ {\ "geosite": [\ '"$geosite_formatted"'\ ],\ "outbound": "'"$1"'"\ },' "$config_file" } function update_outbound_file() { 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 ~ /"outbounds": \[/) { print $0 for (i=1; i<=4; i++) { getline if (i == 4) { print "" $0 "," } else { print $0 } } print " {"; print " \"type\": \"direct\","; print " \"tag\": \"warp-IPv4-out\","; print " \"detour\": \"wireguard-out\","; print " \"domain_strategy\": \"ipv4_only\""; print " },"; print " {"; print " \"type\": \"direct\","; print " \"tag\": \"warp-IPv6-out\","; print " \"detour\": \"wireguard-out\","; print " \"domain_strategy\": \"ipv6_only\""; print " },"; print " {"; print " \"type\": \"wireguard\","; print " \"tag\": \"wireguard-out\","; print " \"server\": \"" server "\","; print " \"server_port\": " server_port ","; print " \"system_interface\": false,"; print " \"interface_name\": \"wg0\","; print " \"local_address\": ["; print " \"" local_address_ipv4 "\","; print " \"" local_address_ipv6 "\"" ; print " ],"; print " \"private_key\": \"" private_key "\","; print " \"peer_public_key\": \"" peer_public_key "\","; print " \"reserved\": " reserved ","; print " \"mtu\": " mtu; print " }" } else { print $0 } } ' "$config_file" > "$config_file.tmp" mv "$config_file.tmp" "$config_file" echo "warp配置完成。" } 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\": \"warn\","; print " \"timestamp\": true"; print " },"; print " \"dns\": {"; print " \"servers\": ["; print " {"; print " \"tag\": \"dns_proxy\","; print " \"address\": \"https://1.1.1.1/dns-query\","; print " \"address_resolver\": \"dns_local\","; print " \"strategy\": \"ipv4_only\","; print " \"detour\": \"select\""; print " },"; print " {"; print " \"tag\": \"dns_direct\","; print " \"address\": \"https://dns.alidns.com/dns-query\","; print " \"address_resolver\": \"dns_local\","; print " \"strategy\": \"ipv4_only\","; print " \"detour\": \"direct\""; print " },"; print " {"; print " \"tag\": \"dns_local\","; print " \"address\": \"223.5.5.5\","; print " \"detour\": \"direct\""; print " },"; print " {"; print " \"tag\": \"dns_block\","; print " \"address\": \"rcode://success\""; print " }"; print " ],"; print " \"rules\": ["; print " {"; print " \"outbound\": \"any\","; print " \"server\": \"dns_local\""; print " },"; print " {"; print " \"geosite\": \"category-ads-all\","; print " \"server\": \"dns_block\","; print " \"disable_cache\": true"; print " },"; print " {"; print " \"geosite\": ["; print " \"cn\","; print " \"private\""; print " ],"; print " \"server\": \"dns_direct\""; print " }"; print " ]"; print " },"; print " \"route\": {"; print " \"geoip\": {"; print " \"download_url\": \"https://github.com/soffchen/sing-geoip/releases/latest/download/geoip.db\","; print " \"download_detour\": \"select\""; print " },"; print " \"geosite\": {"; print " \"download_url\": \"https://github.com/soffchen/sing-geosite/releases/latest/download/geosite.db\","; print " \"download_detour\": \"select\""; print " },"; print " \"rules\": ["; print " {"; print " \"protocol\": \"dns\","; print " \"outbound\": \"dns-out\""; print " },"; print " {"; print " \"geosite\": \"category-ads-all\","; print " \"outbound\": \"block\""; print " },"; print " {"; print " \"geosite\": \"cn\","; print " \"geoip\": ["; print " \"cn\","; print " \"private\""; print " ],"; print " \"outbound\": \"direct\""; print " }"; print " ],"; print " \"auto_detect_interface\": true"; print " },"; print " \"inbounds\": ["; print " {"; print " \"type\": \"tun\","; print " \"tag\": \"tun-in\","; print " \"inet4_address\": \"172.19.0.1/30\","; print " \"inet6_address\": \"fdfe:dcba:9876::1/126\","; print " \"mtu\": 1400,"; print " \"auto_route\": true,"; print " \"strict_route\": true,"; print " \"stack\": \"gvisor\","; print " \"sniff\": true,"; print " \"sniff_override_destination\": 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\": \"select\","; print " \"outbounds\": ["; print " \"auto\""; print " ],"; print " \"default\": \"auto\","; print " \"interrupt_exist_connections\": false"; print " },"; print " {"; print " \"type\": \"direct\","; print " \"tag\": \"direct\""; print " },"; print " {"; print " \"type\": \"block\","; print " \"tag\": \"block\""; print " },"; print " {"; print " \"type\": \"dns\","; print " \"tag\": \"dns-out\""; print " }"; print " ],"; print " \"ntp\": {"; print " \"enabled\": true,"; print " \"server\": \"time.apple.com\","; print " \"server_port\": 123,"; print " \"interval\": \"30m\","; print " \"detour\": \"direct\""; print " }"; print "}" }' > "${phone_client}" fi } 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\": \"warn\","; print " \"timestamp\": true"; print " },"; print " \"dns\": {"; print " \"servers\": ["; print " {"; print " \"tag\": \"dns_proxy\","; print " \"address\": \"https://1.1.1.1/dns-query\","; print " \"address_resolver\": \"dns_local\","; print " \"strategy\": \"ipv4_only\","; print " \"detour\": \"select\""; print " },"; print " {"; print " \"tag\": \"dns_direct\","; print " \"address\": \"https://dns.alidns.com/dns-query\","; print " \"address_resolver\": \"dns_local\","; print " \"strategy\": \"ipv4_only\","; print " \"detour\": \"direct\""; print " },"; print " {"; print " \"tag\": \"dns_local\","; print " \"address\": \"223.5.5.5\","; print " \"detour\": \"direct\""; print " },"; print " {"; print " \"tag\": \"dns_block\","; print " \"address\": \"rcode://success\""; print " }"; print " ],"; print " \"rules\": ["; print " {"; print " \"outbound\": \"any\","; print " \"server\": \"dns_local\""; print " },"; print " {"; print " \"geosite\": \"category-ads-all\","; print " \"server\": \"dns_block\","; print " \"disable_cache\": true"; print " },"; print " {"; print " \"geosite\": ["; print " \"cn\","; print " \"private\""; print " ],"; print " \"server\": \"dns_direct\""; print " }"; print " ]"; print " },"; print " \"route\": {"; print " \"geoip\": {"; print " \"download_url\": \"https://github.com/soffchen/sing-geoip/releases/latest/download/geoip.db\","; print " \"download_detour\": \"select\""; print " },"; print " \"geosite\": {"; print " \"download_url\": \"https://github.com/soffchen/sing-geosite/releases/latest/download/geosite.db\","; print " \"download_detour\": \"select\""; print " },"; print " \"rules\": ["; print " {"; print " \"protocol\": \"dns\","; print " \"outbound\": \"dns-out\""; print " },"; print " {"; print " \"geosite\": \"category-ads-all\","; print " \"outbound\": \"block\""; print " },"; print " {"; print " \"geosite\": \"cn\","; print " \"geoip\": ["; print " \"cn\","; print " \"private\""; print " ],"; print " \"outbound\": \"direct\""; print " }"; print " ],"; print " \"auto_detect_interface\": true"; print " },"; print " \"inbounds\": ["; print " {"; print " \"type\": \"mixed\","; print " \"tag\": \"mixed-in\","; print " \"listen\": \"::\","; print " \"listen_port\": 1080,"; print " \"sniff\": true,"; 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\": \"select\","; print " \"outbounds\": ["; print " \"auto\""; print " ],"; print " \"default\": \"auto\","; print " \"interrupt_exist_connections\": false"; print " },"; print " {"; print " \"type\": \"direct\","; print " \"tag\": \"direct\""; print " },"; print " {"; print " \"type\": \"block\","; print " \"tag\": \"block\""; print " },"; print " {"; print " \"type\": \"dns\","; print " \"tag\": \"dns-out\""; print " }"; print " ],"; print " \"ntp\": {"; print " \"enabled\": true,"; print " \"server\": \"time.apple.com\","; print " \"server_port\": 123,"; print " \"interval\": \"30m\","; print " \"detour\": \"direct\""; print " }"; print "}" }' > "${win_client}" fi } function write_clash_yaml() { local dir="/usr/local/etc/sing-box" local clash_yaml="${dir}/clash.yaml" local api_pass=$(head /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 16) if [ ! -s "${clash_yaml}" ]; then awk -v api_pass="$api_pass" 'BEGIN { print "mixed-port: 10801"; print "allow-lan: true"; print "bind-address: \"*\""; print "find-process-mode: strict"; print "mode: rule"; print "geox-url:"; print " geoip: \"https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat\""; print " geosite: \"https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat\""; print " mmdb: \"https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.metadb\""; print "log-level: debug"; print "ipv6: true"; print "external-controller: 0.0.0.0:9093"; print "secret: \"" api_pass "\""; print "global-client-fingerprint: chrome"; 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: false"; print " mtu: 9000"; print " strict-route: true"; print "profile:"; print " store-selected: false"; print " store-fake-ip: true"; print "sniffer:"; print " enable: true"; print " override-destination: false"; print " sniff:"; print " TLS:"; print " ports: [443, 8443]"; print " HTTP:"; print " ports: [80, 8080-8880]"; print " override-destination: true"; print " force-domain:"; print " - +.v2ex.com"; print "dns:"; print " enable: true"; print " prefer-h3: true"; print " listen: 0.0.0.0:53"; print " ipv6: true"; print " ipv6-timeout: 300"; print " default-nameserver:"; print " - 114.114.114.114"; print " - 8.8.8.8"; print " - tls://1.12.12.12:853"; print " - tls://223.5.5.5:853"; print " - system"; print " enhanced-mode: fake-ip"; print " fake-ip-range: 198.18.0.1/16"; print " nameserver:"; print " - https://dns.alidns.com/dns-query"; print " - https://223.5.5.5/dns-query"; print " - https://doh.pub/dns-query"; print " - https://dns.alidns.com/dns-query#h3=true"; print " - quic://dns.adguard.com:784"; print " fallback:"; print " - tls://dns.google"; print " - https://1.1.1.1/dns-query"; print " - https://cloudflare-dns.com/dns-query"; print " - https://dns.google/dns-query"; print " fallback-filter:"; print " geoip: true"; print " geoip-code: CN"; print " geosite:"; print " - gfw"; print " ipcidr:"; print " - 240.0.0.0/4"; print " domain:"; print " - \"+.google.com\""; print " - \"+.facebook.com\""; print " - \"+.youtube.com\""; print " nameserver-policy:"; print " \"geosite:cn,private,apple\":"; print " - https://doh.pub/dns-query"; print " - https://dns.alidns.com/dns-query"; print " \"geosite:category-ads-all\": rcode://success"; print " \"www.baidu.com,+.google.cn\": [223.5.5.5, https://dns.alidns.com/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 " - DOMAIN,clash.razord.top,DIRECT"; print " - DOMAIN,yacd.haishan.me,DIRECT"; print " - GEOSITE,private,DIRECT"; print " - GEOSITE,category-ads-all,REJECT"; print " - GEOSITE,cn,DIRECT"; print " - GEOIP,cn,DIRECT"; print " - MATCH,Proxy"; }' > "${clash_yaml}" sed -i'' -e '/^ - "+\.google\.com"/s/"/'\''/g' "${clash_yaml}" sed -i'' -e '/^ - "+\.facebook\.com"/s/"/'\''/g' "${clash_yaml}" sed -i'' -e '/^ - "+\.youtube\.com"/s/"/'\''/g' "${clash_yaml}" fi } 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" } function generate_shadowsocks_win_client_config() { local win_client_file="/usr/local/etc/sing-box/win_client.json" 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" "$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" ' /^ "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 "\", "; print " \"multiplex\": {"; print " \"enabled\": true,"; print " \"protocol\": \"smux\","; print " \"max_connections\": 4,"; print " \"min_streams\": 4,"; print " \"max_streams\": 0"; 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" } function generate_shadowsocks_phone_client_config() { local phone_client_file="/usr/local/etc/sing-box/phone_client.json" 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" "$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" ' /^ "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 "\", "; print " \"multiplex\": {"; print " \"enabled\": true,"; print " \"protocol\": \"smux\","; print " \"max_connections\": 4,"; print " \"min_streams\": 4,"; print " \"max_streams\": 0"; 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" } 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 "\""; 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" } 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 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" ' /^ "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 " ]"; 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" } function generate_tuic_win_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 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" ' /^ "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 " ]"; 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" } 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; 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" } 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" } 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" } 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; 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" } 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 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 if [ -n "$obfs_password" ]; then obfs_config=" \"obfs\": \"$obfs_password\"," else obfs_config="" fi awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -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" ' /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"hysteria\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; 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 " ]"; 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" } 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 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 if [ -n "$obfs_password" ]; then obfs_config=" \"obfs\": \"$obfs_password\"," else obfs_config="" fi awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -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" ' /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"hysteria\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; 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 " ]"; 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" } 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 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 if [ -n "$obfs_password" ]; then obfs_config=" obfs: $obfs_password" else obfs_config="" fi awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -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; 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\""; 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" } 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 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" ' /^ "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 "\" "; print " },"; print " \"security\": \"auto\","; print " \"alter_id\": 0,"; print " \"packet_encoding\": \"xudp\" "; 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" ' /^ "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\" "; 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" } 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 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" ' /^ "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 "\" "; print " },"; print " \"security\": \"auto\","; print " \"alter_id\": 0,"; print " \"packet_encoding\": \"xudp\" "; 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" ' /^ "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\" "; 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" } 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"; 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" } 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; 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" } 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"; 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" } 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"; 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" } 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 "\""; 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" } 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 "\""; 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" } 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 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 if [ -n "$obfs_password" ]; then obfs_config=" \"obfs\": { \"type\": \"salamander\", \"password\": \"$obfs_password\" }," else obfs_config="" fi awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -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" ' /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"hysteria2\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; 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 " ]"; 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" } 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 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 if [ -n "$obfs_password" ]; then obfs_config=" \"obfs\": { \"type\": \"salamander\", \"password\": \"$obfs_password\" }," else obfs_config="" fi awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -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" ' /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"hysteria2\","; print " \"tag\": \"" proxy_name "\","; print " \"server\": \"" server_value "\", "; print " \"server_port\": " listen_port ","; 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 " ]"; 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" } 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 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 if [ -n "$obfs_password" ]; then obfs_config=" obfs: salamander obfs-password: $obfs_password" else obfs_config="" fi awk -v proxy_name="$proxy_name" -v server_value="$server_value" -v server_name="$server_name" -v listen_port="$listen_port" -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; 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\""; 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" } 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") 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" ' /^ "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 " }"; 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" ' /^ "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 "\""; 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" } 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") 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" ' /^ "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 " }"; 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" ' /^ "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 "\""; 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" } 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"; 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" } 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"; 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" } 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 "\""; 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" } 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; 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" } 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 "\""; 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" } 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 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" ' /^ "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 "\" "; print " }"; 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" ' /^ "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 "\""; 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" } 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 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" ' /^ "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 "\" "; print " }"; 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" ' /^ "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 "\""; 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" } 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"; 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" } 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; 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" } 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 "\""; 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" } function generate_shadowtls_win_client_config() { local win_client_file="/usr/local/etc/sing-box/win_client.json" local proxy_name local shadowtls_out 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" ' /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"shadowsocks\","; print " \"tag\": \"" proxy_name "\","; print " \"method\": \"" method "\", "; print " \"password\": \"" ss_password "\","; print " \"detour\": \"" shadowtls_out "\", "; print " \"multiplex\": {"; print " \"enabled\": true,"; print " \"max_connections\": 4,"; print " \"min_streams\": 4 "; print " }"; 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" } function generate_shadowtls_phone_client_config() { local phone_client_file="/usr/local/etc/sing-box/phone_client.json" local proxy_name local shadowtls_out 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" ' /^ "outbounds": \[/ {print; getline; print " {"; print " \"type\": \"shadowsocks\","; print " \"tag\": \"" proxy_name "\","; print " \"method\": \"" method "\", "; print " \"password\": \"" ss_password "\","; print " \"detour\": \"" shadowtls_out "\", "; print " \"multiplex\": {"; print " \"enabled\": true,"; print " \"max_connections\": 4,"; print " \"min_streams\": 4 "; print " }"; 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" } 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"; 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" } 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 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> /usr/local/etc/certificate.log 2>&1") | crontab - fi } function main_menu() { echo "╔════════════════════════════════════════════════════════════════════════╗" echo -e "║ ${CYAN}作者${NC}: Mr. xiao ║" echo -e "║ ${CYAN}项目地址${NC}: https://github.com/TinrLin ║" echo -e "║ ${CYAN}Telegram 群组${NC}: https://t.me/mrxiao758 ║" echo -e "║ ${CYAN}YouTube频道${NC}: https://youtube.com/@Mr_xiao502 ║" echo "╠════════════════════════════════════════════════════════════════════════╣" echo "║ 请选择要执行的操作: ║" echo -e "║${CYAN} [1]${NC} SOCKS ${CYAN} [2]${NC} Direct ║" echo -e "║${CYAN} [3]${NC} VMess ${CYAN} [4]${NC} VLESS ║" echo -e "║${CYAN} [5]${NC} TUIC ${CYAN} [6]${NC} Juicity ║" echo -e "║${CYAN} [7]${NC} Trojan ${CYAN} [8]${NC} Hysteria ║" echo -e "║${CYAN} [9]${NC} Hysteria2 ${CYAN} [10]${NC} ShadowTLS ║" echo -e "║${CYAN} [11]${NC} NaiveProxy ${CYAN} [12]${NC} Shadowsocks ║" echo -e "║${CYAN} [13]${NC} WireGuard ${CYAN} [14]${NC} 查看节点信息 ║" echo -e "║${CYAN} [15]${NC} 更新内核 ${CYAN} [16]${NC} 更新脚本 ║" echo -e "║${CYAN} [17]${NC} 更新证书 ${CYAN} [18]${NC} 重启服务 ║" echo -e "║${CYAN} [19]${NC} 卸载 ${CYAN} [0]${NC} 退出 ║" echo "╚════════════════════════════════════════════════════════════════════════╝" local choice read -p "请选择 [0-19]: " choice case $choice in 1) socks_install exit 0 ;; 2) Direct_install exit 0 ;; 3) vmess_install exit 0 ;; 4) reality_install exit 0 ;; 5) tuic_install exit 0 ;; 6) juicity_install exit 0 ;; 7) trojan_install exit 0 ;; 8) Hysteria_install exit 0 ;; 9) Hysteria2_install exit 0 ;; 10) shadowtls_install exit 0 ;; 11) NaiveProxy_install exit 0 ;; 12) Shadowsocks_install exit 0 ;; 13) wireguard_install exit 0 ;; 14) view_saved_config exit 0 ;; 15) update_proxy_tool exit 0 ;; 16) Update_Script exit 0 ;; 17) Update_certificate ;; 18) check_and_restart_services exit 0 ;; 19) uninstall exit 0 ;; 0) echo "感谢使用 Mr. xiao 安装脚本!再见!" exit 0 ;; *) echo -e "${RED}无效的选择,请重新输入。${NC}" main_menu ;; esac } function run_option() { case "$1" in "17") Update_certificate exit 0 ;; esac } if [ $# -eq 0 ]; then main_menu else run_option "$1" fi main_menu