#!/bin/bash # 伪装域名测试脚本 - 优化版本 # 预定义的域名列表 DOMAINS=( "www.cloudflare.com" "www.apple.com" "www.microsoft.com" "www.bing.com" "www.google.com" "developer.apple.com" "www.gstatic.com" "fonts.gstatic.com" "fonts.googleapis.com" "res-1.cdn.office.net" "res.public.onecdn.static.microsoft" "static.cloud.coveo.com" "aws.amazon.com" "www.aws.com" "cloudfront.net" "d1.awsstatic.com" "cdn.jsdelivr.net" "cdn.jsdelivr.org" "polyfill-fastly.io" "beacon.gtv-pub.com" "s7mbrstream.scene7.com" "cdn.bizibly.com" "www.sony.com" "www.nytimes.com" "www.w3.org" "www.wikipedia.org" "ajax.cloudflare.com" "www.mozilla.org" "www.intel.com" "api.snapchat.com" "images.unsplash.com" "edge-mqtt.facebook.com" "video.xx.fbcdn.net" "gstatic.cn" ) # 缓存配置 CACHE_DIR="/tmp/hysteria-domain-cache" CACHE_EXPIRY=3600 # 1小时缓存 MAX_CONCURRENT_JOBS=8 # 创建缓存目录 mkdir -p "$CACHE_DIR" # 获取缓存文件路径 get_cache_file() { local domain=$1 echo "$CACHE_DIR/$(echo "$domain" | tr '.' '_')" } # 检查缓存是否有效 is_cache_valid() { local cache_file=$1 if [[ -f "$cache_file" ]]; then local cache_time=$(stat -c %Y "$cache_file" 2>/dev/null || stat -f %m "$cache_file" 2>/dev/null) local current_time=$(date +%s) if [[ $((current_time - cache_time)) -lt $CACHE_EXPIRY ]]; then return 0 fi fi return 1 } # 从缓存读取结果 read_from_cache() { local cache_file=$1 if [[ -f "$cache_file" ]]; then cat "$cache_file" return 0 fi return 1 } # 写入缓存 write_to_cache() { local cache_file=$1 local result=$2 echo "$result" > "$cache_file" } # 清理过期缓存 cleanup_cache() { find "$CACHE_DIR" -type f -mtime +1 -delete 2>/dev/null } # 智能超时调整 get_adaptive_timeout() { local network_quality=$1 case $network_quality in "fast") echo 2 ;; "medium") echo 3 ;; "slow") echo 5 ;; *) echo 3 ;; esac } # 网络质量检测 detect_network_quality() { local start_time=$(date +%s%3N) if timeout 2 curl -s --connect-timeout 2 google.com >/dev/null 2>&1; then local end_time=$(date +%s%3N) local latency=$((end_time - start_time)) if [[ $latency -lt 500 ]]; then echo "fast" elif [[ $latency -lt 1500 ]]; then echo "medium" else echo "slow" fi else echo "slow" fi } # DNS解析验证函数 test_dns_resolution() { local domain=$1 local timeout_val=${2:-3} # 使用dig验证DNS解析(优先) if command -v dig >/dev/null 2>&1; then if timeout "$timeout_val" dig +short "$domain" A >/dev/null 2>&1; then return 0 fi fi # 使用nslookup作为备用 if command -v nslookup >/dev/null 2>&1; then if timeout "$timeout_val" nslookup "$domain" >/dev/null 2>&1; then return 0 fi fi # 使用host作为最后备用 if command -v host >/dev/null 2>&1; then if timeout "$timeout_val" host "$domain" >/dev/null 2>&1; then return 0 fi fi return 1 } # 测试单个域名延迟(优化版本 + DNS验证) test_domain_latency() { local domain=$1 local timeout_val=${2:-3} local attempts=${3:-2} # 默认尝试2次 local results=() # 检查缓存 local cache_file=$(get_cache_file "$domain") if is_cache_valid "$cache_file"; then local cached_result=$(read_from_cache "$cache_file") # 验证缓存结果是否包含DNS验证状态 if [[ "$cached_result" =~ dns_ok|dns_fail ]]; then echo "$cached_result" return 0 fi fi # 首先验证DNS解析 local dns_status="dns_fail" if test_dns_resolution "$domain" "$timeout_val"; then dns_status="dns_ok" else # DNS解析失败,直接返回失败状态 local result="9999 $domain $dns_status" write_to_cache "$cache_file" "$result" return 1 fi # 多次测试取最佳结果(只有DNS解析成功才测试连接) for ((i=1; i<=attempts; i++)); do local start_time=$(date +%s%3N) if timeout "$timeout_val" openssl s_client -connect "$domain:443" -servername "$domain" /dev/null 2>&1; then local end_time=$(date +%s%3N) local latency=$((end_time - start_time)) results+=($latency) fi done # 如果有成功的测试结果,返回最小值 if [[ ${#results[@]} -gt 0 ]]; then local min_latency=$(printf '%s\n' "${results[@]}" | sort -n | head -1) local result="$min_latency $domain $dns_status" # 写入缓存 write_to_cache "$cache_file" "$result" echo "$result" return 0 fi # SSL连接失败但DNS解析成功 local result="9999 $domain $dns_status" write_to_cache "$cache_file" "$result" return 1 } # 并发测试所有域名(静默版本) test_all_domains_concurrent_silent() { local results_file=$(mktemp) local job_count=0 local total=${#DOMAINS[@]} local completed=0 # 检测网络质量并调整超时 local network_quality=$(detect_network_quality) local timeout_val=$(get_adaptive_timeout "$network_quality") # 并发测试域名 for domain in "${DOMAINS[@]}"; do # 限制并发数 while [[ $(jobs -r | wc -l) -ge $MAX_CONCURRENT_JOBS ]]; do sleep 0.1 done # 启动后台任务 ( if result=$(test_domain_latency "$domain" "$timeout_val" 1); then echo "$result" >> "$results_file" fi ) & done # 等待所有任务完成 wait # 返回排序结果(过滤DNS失败的域名) if [[ -s "$results_file" ]]; then # 只返回DNS解析成功且延迟不是9999的结果 awk '$1 != 9999 && $3 == "dns_ok" {print $1 " " $2 " " $3}' "$results_file" | sort -n local exit_code=0 else local exit_code=1 fi rm -f "$results_file" return $exit_code } # 并发测试所有域名(带进度显示) test_all_domains_concurrent() { local results_file=$(mktemp) local progress_file=$(mktemp) local total=${#DOMAINS[@]} local completed=0 echo -e "${BLUE}正在并发测试 $total 个域名的延迟...${NC}" >&2 echo -e "${BLUE}网络质量: $(detect_network_quality | tr 'a-z' 'A-Z')${NC}" >&2 echo "" >&2 # 检测网络质量并调整超时 local network_quality=$(detect_network_quality) local timeout_val=$(get_adaptive_timeout "$network_quality") # 启动进度监控 { while [[ $completed -lt $total ]]; do completed=$(cat "$progress_file" 2>/dev/null | wc -l) local percentage=$(( (completed * 100) / total )) printf "\r${BLUE}进度: %d/%d (%d%%) - 已完成测试${NC}" $completed $total $percentage >&2 sleep 0.2 done echo "" >&2 } & local monitor_pid=$! # 并发测试域名 for domain in "${DOMAINS[@]}"; do # 限制并发数 while [[ $(jobs -r | wc -l) -ge $MAX_CONCURRENT_JOBS ]]; do sleep 0.1 done # 启动后台任务 ( if result=$(test_domain_latency "$domain" "$timeout_val" 1); then echo "$result" >> "$results_file" fi echo "1" >> "$progress_file" # 标记任务完成 ) & done # 等待所有任务完成 wait # 停止进度监控 kill $monitor_pid 2>/dev/null wait $monitor_pid 2>/dev/null echo "" >&2 echo -e "${GREEN}测试完成!${NC}" >&2 echo "" >&2 # 返回排序结果(过滤DNS失败的域名) if [[ -s "$results_file" ]]; then # 只返回DNS解析成功且延迟不是9999的结果 awk '$1 != 9999 && $3 == "dns_ok" {print $1 " " $2 " " $3}' "$results_file" | sort -n local exit_code=0 else local exit_code=1 fi # 清理临时文件 rm -f "$results_file" "$progress_file" return $exit_code } # 显示测试结果(优化版本) show_test_results() { echo -e "${CYAN}域名延迟测试结果 (前10名):${NC}" echo "" # 清理过期缓存 cleanup_cache local results=$(test_all_domains_concurrent) if [[ -z "$results" ]]; then echo -e "${RED}所有域名测试失败,请检查网络连接${NC}" return 1 fi printf "%-5s %-30s %-8s %-8s %s\n" "排名" "域名" "延迟(ms)" "DNS状态" "评级" echo "---------------------------------------------------------" local rank=1 echo "$results" | head -n 10 | while read -r latency domain dns_status; do # 延迟评级 local rating if [[ $latency -lt 50 ]]; then rating="${GREEN}极佳${NC}" elif [[ $latency -lt 100 ]]; then rating="${GREEN}优秀${NC}" elif [[ $latency -lt 200 ]]; then rating="${YELLOW}良好${NC}" elif [[ $latency -lt 500 ]]; then rating="${YELLOW}一般${NC}" else rating="${RED}较差${NC}" fi # DNS状态显示 local dns_display if [[ "$dns_status" == "dns_ok" ]]; then dns_display="${GREEN}正常${NC}" else dns_display="${RED}失败${NC}" fi printf "%-5d %-30s %-8d %-8s %b\n" "$rank" "$domain" "$latency" "$dns_display" "$rating" rank=$((rank + 1)) done } # 获取最优域名(优化版本) get_best_domain() { local best_result=$(test_all_domains_concurrent_silent | head -n 1) if [[ -n "$best_result" ]]; then local domain=$(echo "$best_result" | awk '{print $2}') local dns_status=$(echo "$best_result" | awk '{print $3}') # 确保DNS解析成功 if [[ "$dns_status" == "dns_ok" ]]; then echo "https://$domain/" else echo "https://news.ycombinator.com/" fi else echo "https://news.ycombinator.com/" fi } # 获取最优域名名称 get_best_domain_name() { local best_result=$(test_all_domains_concurrent_silent | head -n 1) if [[ -n "$best_result" ]]; then local domain=$(echo "$best_result" | awk '{print $2}') local dns_status=$(echo "$best_result" | awk '{print $3}') # 确保DNS解析成功 if [[ "$dns_status" == "dns_ok" ]]; then echo "$domain" else echo "cdn.jsdelivr.net" fi else echo "cdn.jsdelivr.net" fi } # 域名稳定性测试(新增功能) test_domain_stability() { local domain=$1 local test_count=${2:-5} local results=() echo -e "${BLUE}测试域名 $domain 的稳定性 (${test_count}次)...${NC}" for ((i=1; i<=test_count; i++)); do printf "\r测试进度: $i/$test_count" if result=$(test_domain_latency "$domain" 3 1); then local latency=$(echo "$result" | awk '{print $1}') results+=($latency) fi sleep 0.5 done echo "" if [[ ${#results[@]} -gt 0 ]]; then local min_latency=$(printf '%s\n' "${results[@]}" | sort -n | head -1) local max_latency=$(printf '%s\n' "${results[@]}" | sort -n | tail -1) local avg_latency=$(printf '%s\n' "${results[@]}" | awk '{sum+=$1} END {printf "%.0f", sum/NR}') local success_rate=$(( (${#results[@]} * 100) / test_count )) echo -e "${GREEN}稳定性测试结果:${NC}" echo "成功率: ${success_rate}%" echo "最小延迟: ${min_latency}ms" echo "最大延迟: ${max_latency}ms" echo "平均延迟: ${avg_latency}ms" # 稳定性评级 local stability_variance=$((max_latency - min_latency)) if [[ $stability_variance -lt 50 ]] && [[ $success_rate -eq 100 ]]; then echo -e "稳定性评级: ${GREEN}极佳${NC}" elif [[ $stability_variance -lt 100 ]] && [[ $success_rate -ge 80 ]]; then echo -e "稳定性评级: ${GREEN}良好${NC}" elif [[ $success_rate -ge 60 ]]; then echo -e "稳定性评级: ${YELLOW}一般${NC}" else echo -e "稳定性评级: ${RED}较差${NC}" fi else echo -e "${RED}稳定性测试失败${NC}" fi } # 交互式域名选择(优化版本) interactive_domain_selection() { echo -e "${BLUE}域名延迟测试和选择${NC}" echo "" echo -e "${BLUE}正在测试域名延迟,请稍候...${NC}" local results=$(test_all_domains_concurrent_silent | head -n 15) if [[ -z "$results" ]]; then echo -e "${RED}域名测试失败,使用默认域名${NC}" echo "默认域名: news.ycombinator.com" return fi echo "" echo -e "${CYAN}可用域名列表:${NC}" echo "" printf "%-5s %-30s %-8s %s\n" "编号" "域名" "延迟(ms)" "评级" echo "------------------------------------------------" local domains_array=() local index=1 while IFS= read -r line; do if [[ -n "$line" ]]; then local latency=$(echo "$line" | awk '{print $1}') local domain=$(echo "$line" | awk '{print $2}') local dns_status=$(echo "$line" | awk '{print $3}') if [[ "$latency" =~ ^[0-9]+$ ]] && [[ -n "$domain" ]] && [[ ! "$domain" =~ [[:space:]] ]] && [[ "$dns_status" == "dns_ok" ]]; then # 延迟评级 local rating if [[ $latency -lt 100 ]]; then rating="${GREEN}优秀${NC}" elif [[ $latency -lt 200 ]]; then rating="${YELLOW}良好${NC}" else rating="${RED}一般${NC}" fi printf "%-5d %-30s %-8d %b\n" "$index" "$domain" "$latency" "$rating" domains_array+=("$domain") index=$((index + 1)) fi fi done <<< "$results" echo "" echo -e "${GREEN}0.${NC} 使用默认域名 (news.ycombinator.com)" echo -e "${BLUE}s.${NC} 测试选定域名的稳定性" echo "" echo -n -e "${BLUE}请选择域名编号 [0-${#domains_array[@]}/s]: ${NC}" read -r choice if [[ "$choice" == "s" ]]; then echo -n -e "${BLUE}请输入要测试稳定性的域名编号: ${NC}" read -r stability_choice if [[ "$stability_choice" =~ ^[0-9]+$ ]] && [[ $stability_choice -ge 1 ]] && [[ $stability_choice -le ${#domains_array[@]} ]]; then local test_domain="${domains_array[$((stability_choice-1))]}" test_domain_stability "$test_domain" fi elif [[ "$choice" =~ ^[0-9]+$ ]] && [[ $choice -ge 1 ]] && [[ $choice -le ${#domains_array[@]} ]]; then local selected_domain="${domains_array[$((choice-1))]}" echo -e "${GREEN}已选择: $selected_domain${NC}" if [[ -f "$CONFIG_PATH" ]]; then echo -n -e "${BLUE}是否更新当前配置文件中的伪装域名? [y/N]: ${NC}" read -r update_config if [[ $update_config =~ ^[Yy]$ ]]; then update_masquerade_domain "$selected_domain" fi fi else echo -e "${BLUE}使用默认域名: news.ycombinator.com${NC}" fi echo "" } # 更新配置文件中的伪装域名(增加验证) update_masquerade_domain() { local new_domain=$1 local new_url="https://$new_domain/" if [[ ! -f "$CONFIG_PATH" ]]; then echo -e "${RED}配置文件不存在${NC}" return 1 fi # 验证域名格式 if [[ ! "$new_domain" =~ ^[a-zA-Z0-9][a-zA-Z0-9.-]*[a-zA-Z0-9]$ ]]; then echo -e "${RED}域名格式无效${NC}" return 1 fi # 备份配置文件(带校验和) local backup_file="$CONFIG_PATH.backup.$(date +%Y%m%d_%H%M%S)" cp "$CONFIG_PATH" "$backup_file" sha256sum "$CONFIG_PATH" > "${backup_file}.checksum" 2>/dev/null # 更新伪装URL if sed -i.bak "s|url: https://.*|url: $new_url|g" "$CONFIG_PATH"; then echo -e "${GREEN}配置文件已更新${NC}" echo -e "${YELLOW}新的伪装域名: $new_url${NC}" echo -e "${BLUE}备份文件: $backup_file${NC}" # 验证配置文件语法 if command -v hysteria >/dev/null && hysteria server --config "$CONFIG_PATH" --check 2>/dev/null; then echo -e "${GREEN}配置文件语法验证通过${NC}" else echo -e "${YELLOW}警告: 无法验证配置文件语法${NC}" fi # 询问是否重启服务 if systemctl is-active --quiet hysteria-server.service 2>/dev/null; then echo -n -e "${BLUE}是否重启服务以应用新配置? [y/N]: ${NC}" read -r restart_service if [[ $restart_service =~ ^[Yy]$ ]]; then if systemctl restart hysteria-server.service; then echo -e "${GREEN}服务已重启${NC}" else echo -e "${RED}服务重启失败,正在恢复配置...${NC}" cp "$backup_file" "$CONFIG_PATH" fi fi fi else echo -e "${RED}配置文件更新失败${NC}" rm -f "$backup_file" "${backup_file}.checksum" return 1 fi } # 批量测试自定义域名(优化版本) test_custom_domains() { echo -e "${BLUE}测试自定义域名${NC}" echo "" echo "请输入要测试的域名,每行一个,输入空行结束:" echo "提示: 可以输入 'file:域名文件路径' 来从文件加载域名" local custom_domains=() while true; do echo -n "域名: " read -r domain if [[ -z "$domain" ]]; then break fi # 支持从文件读取域名 if [[ "$domain" =~ ^file: ]]; then local file_path="${domain#file:}" if [[ -f "$file_path" ]]; then while IFS= read -r line; do [[ -n "$line" ]] && custom_domains+=("$line") done < "$file_path" echo "已从 $file_path 加载 $((${#custom_domains[@]})) 个域名" else echo -e "${RED}文件不存在: $file_path${NC}" fi else custom_domains+=("$domain") fi done if [[ ${#custom_domains[@]} -eq 0 ]]; then echo -e "${YELLOW}未输入任何域名${NC}" return fi echo "" echo -e "${BLUE}开始并发测试 ${#custom_domains[@]} 个自定义域名...${NC}" echo "" printf "%-30s %-10s %-8s %s\n" "域名" "延迟(ms)" "DNS状态" "状态" echo "-------------------------------------------------------" local results_file=$(mktemp) local network_quality=$(detect_network_quality) local timeout_val=$(get_adaptive_timeout "$network_quality") # 并发测试自定义域名 for domain in "${custom_domains[@]}"; do while [[ $(jobs -r | wc -l) -ge $MAX_CONCURRENT_JOBS ]]; do sleep 0.1 done ( if result=$(test_domain_latency "$domain" "$timeout_val" 1); then local latency=$(echo "$result" | awk '{print $1}') local dns_status=$(echo "$result" | awk '{print $3}') local dns_display if [[ "$dns_status" == "dns_ok" ]]; then dns_display="${GREEN}正常${NC}" else dns_display="${RED}失败${NC}" fi printf "%-30s %-10d %-8s %s\n" "$domain" "$latency" "$dns_display" "${GREEN}成功${NC}" echo "$result" >> "$results_file" else printf "%-30s %-10s %-8s %s\n" "$domain" "-" "${RED}失败${NC}" "${RED}失败${NC}" fi ) & done wait if [[ -s "$results_file" ]]; then echo "" local best=$(sort -n "$results_file" | head -n 1) local best_domain=$(echo "$best" | awk '{print $2}') local best_latency=$(echo "$best" | awk '{print $1}') echo -e "${GREEN}最优域名: $best_domain (${best_latency}ms)${NC}" echo "" echo -n -e "${BLUE}是否使用最优域名更新配置? [y/N]: ${NC}" read -r update_choice if [[ $update_choice =~ ^[Yy]$ ]]; then update_masquerade_domain "$best_domain" fi fi rm -f "$results_file" echo "" } # 缓存管理功能(新增) manage_cache() { echo -e "${BLUE}域名测试缓存管理${NC}" echo "" local cache_count=$(find "$CACHE_DIR" -type f 2>/dev/null | wc -l) local cache_size=$(du -sh "$CACHE_DIR" 2>/dev/null | cut -f1) echo "缓存目录: $CACHE_DIR" echo "缓存文件数: $cache_count" echo "缓存大小: ${cache_size:-0}" echo "" echo -e "${GREEN}1.${NC} 清理过期缓存" echo -e "${GREEN}2.${NC} 清理所有缓存" echo -e "${GREEN}3.${NC} 查看缓存详情" echo -e "${RED}0.${NC} 返回" echo "" echo -n -e "${BLUE}请选择操作 [0-3]: ${NC}" read -r choice case $choice in 1) cleanup_cache echo -e "${GREEN}过期缓存已清理${NC}" ;; 2) rm -rf "$CACHE_DIR"/* echo -e "${GREEN}所有缓存已清理${NC}" ;; 3) echo -e "${BLUE}缓存文件列表:${NC}" find "$CACHE_DIR" -type f -exec ls -lh {} \; 2>/dev/null ;; 0) return ;; esac echo "" } # 主测试函数(优化版本) test_masquerade_domains() { while true; do echo -e "${BLUE}伪装域名测试 - 优化版本${NC}" echo "" echo -e "${GREEN}1.${NC} 测试预设域名并显示结果" echo -e "${GREEN}2.${NC} 交互式选择域名" echo -e "${GREEN}3.${NC} 测试自定义域名" echo -e "${GREEN}4.${NC} 快速获取最优域名" echo -e "${GREEN}5.${NC} 域名稳定性测试" echo -e "${GREEN}6.${NC} 缓存管理" echo -e "${RED}0.${NC} 返回主菜单" echo "" echo -n -e "${BLUE}请选择操作 [0-6]: ${NC}" read -r choice case $choice in 1) show_test_results echo "" ;; 2) interactive_domain_selection ;; 3) test_custom_domains ;; 4) echo -e "${BLUE}正在获取最优域名...${NC}" best_domain=$(get_best_domain_name) best_url=$(get_best_domain) echo -e "${GREEN}最优域名: $best_domain${NC}" echo -e "${GREEN}完整URL: $best_url${NC}" echo "" ;; 5) echo -n -e "${BLUE}请输入要测试的域名: ${NC}" read -r test_domain if [[ -n "$test_domain" ]]; then test_domain_stability "$test_domain" fi echo "" ;; 6) manage_cache ;; 0) break ;; *) echo -e "${RED}无效选项${NC}" sleep 1 ;; esac done }