""" 通过修复 DNS 解析问题来使用 Cloudflare Tunnel """ import subprocess import time import os import signal import sys import re import socket from pathlib import Path def setup_dns_resolution(): """设置 DNS 解析""" print("🔧 Setting up DNS resolution...") # 临时 DNS 解析方案 hosts_entries = { 'api.trycloudflare.com': '104.18.22.223', # Cloudflare IP 'trycloudflare.com': '104.18.22.223' } # 写入临时 hosts 文件 temp_hosts = Path.home() / 'zhch' / 'temp_hosts' with open(temp_hosts, 'w') as f: for domain, ip in hosts_entries.items(): f.write(f"{ip} {domain}\n") print(f"✅ Created temporary hosts file: {temp_hosts}") return str(temp_hosts) def test_dns_resolution(): """测试 DNS 解析""" test_domains = [ 'api.trycloudflare.com', 'google.com', 'cloudflare.com' ] print("🧪 Testing DNS resolution...") for domain in test_domains: try: ip = socket.gethostbyname(domain) print(f"✅ {domain} -> {ip}") except socket.gaierror as e: print(f"❌ {domain} -> Failed: {e}") def setup_environment_with_dns(): """设置包含 DNS 配置的环境变量""" proxy_url = "http://172.16.40.16:7280" env = os.environ.copy() # 基本代理配置 env.update({ 'HTTP_PROXY': proxy_url, 'HTTPS_PROXY': proxy_url, 'http_proxy': proxy_url, 'https_proxy': proxy_url, }) # DNS 配置 env.update({ 'GODEBUG': 'netdns=go+1', 'GOPROXY': 'direct', 'GOSUMDB': 'off', }) # 使用公共 DNS env['NAMESERVER'] = '8.8.8.8' return env def download_cloudflared_direct(): """直接下载 cloudflared(绕过 DNS 问题)""" print("🔄 Downloading cloudflared directly...") bin_dir = Path.home() / "zhch" / "bin" bin_dir.mkdir(exist_ok=True, parents=True) cloudflared_path = bin_dir / "cloudflared" if cloudflared_path.exists(): print("✅ Cloudflared already exists") return str(cloudflared_path) # 使用直接 IP 地址下载(绕过 DNS) github_ip = "140.82.113.3" # GitHub IP download_cmd = [ 'curl', '-L', '-k', # -k 忽略 SSL 证书验证 '-H', f'Host: github.com', f'http://{github_ip}/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64', '-o', str(cloudflared_path) ] try: env = setup_environment_with_dns() result = subprocess.run( download_cmd, check=True, env=env, capture_output=True, text=True, timeout=300 ) subprocess.run(['chmod', '+x', str(cloudflared_path)], check=True) print("✅ Cloudflared downloaded successfully") return str(cloudflared_path) except Exception as e: print(f"❌ Download failed: {e}") # 备选方案:使用 wget try: wget_cmd = [ 'wget', '--no-check-certificate', '--header', f'Host: github.com', f'http://{github_ip}/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64', '-O', str(cloudflared_path) ] subprocess.run(wget_cmd, check=True, env=env, timeout=300) subprocess.run(['chmod', '+x', str(cloudflared_path)], check=True) print("✅ Cloudflared downloaded with wget") return str(cloudflared_path) except Exception as e2: print(f"❌ Wget also failed: {e2}") return None def setup_cloudflare_tunnel_with_dns_fix(port=8101, timeout=120): """使用 DNS 修复的 Cloudflare Tunnel 设置""" print(f"🔄 Setting up Cloudflare Tunnel for port {port} with DNS fix...") # 测试 DNS test_dns_resolution() # 下载 cloudflared cloudflared_path = download_cloudflared_direct() if not cloudflared_path: print("❌ Could not download cloudflared") return None # 创建日志目录 log_dir = Path.home() / 'zhch' / 'logs' log_dir.mkdir(exist_ok=True, parents=True) # 准备命令 tunnel_cmd = [ cloudflared_path, 'tunnel', '--url', f'http://localhost:{port}', '--no-autoupdate', '--logfile', str(log_dir / 'cloudflared.log'), '--loglevel', 'debug' # 更详细的日志 ] print(f"🚀 Starting tunnel: {' '.join(tunnel_cmd)}") try: env = setup_environment_with_dns() # 显示环境配置 print("🔧 Environment configuration:") for key in ['HTTP_PROXY', 'HTTPS_PROXY', 'GODEBUG', 'NAMESERVER']: print(f" {key}: {env.get(key, 'Not set')}") process = subprocess.Popen( tunnel_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, env=env, bufsize=1, universal_newlines=True ) print("⏳ Waiting for tunnel to start...") start_time = time.time() while time.time() - start_time < timeout: if process.poll() is not None: stdout, _ = process.communicate() print(f"❌ Process terminated early:") print(stdout) return None try: line = process.stdout.readline() if line: line = line.strip() print(f"LOG: {line}") # 查找成功的隧道 URL if 'trycloudflare.com' in line: url_match = re.search(r'https://[a-zA-Z0-9-]+\.trycloudflare\.com', line) if url_match: url = url_match.group(0) print(f"✅ Tunnel URL found: {url}") return url, process # 检查特定错误 if 'dial tcp: lookup api.trycloudflare.com' in line: print("❌ DNS lookup failed for api.trycloudflare.com") print("🔧 Trying DNS workaround...") break if 'failed to request quick Tunnel' in line: print("❌ Failed to create tunnel") break except Exception as e: print(f"Error reading output: {e}") break time.sleep(0.5) print(f"⏰ Timeout after {timeout} seconds") process.terminate() return None except Exception as e: print(f"❌ Failed to start tunnel: {e}") return None def main(): port = 8101 print("🌐 Cloudflare Tunnel Setup with DNS Fix") print("=" * 60) # 检查网络连接 print("🔍 Network diagnostics:") # 检查代理连接 try: result = subprocess.run(['curl', '-s', '--connect-timeout', '5', 'http://httpbin.org/ip'], capture_output=True, text=True) if result.returncode == 0: print("✅ Proxy connection working") else: print("❌ Proxy connection failed") except: print("❌ Could not test proxy") # 检查本地服务 import socket try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(2) result = sock.connect_ex(('localhost', port)) sock.close() if result == 0: print(f"✅ Local service running on port {port}") else: print(f"⚠️ No service on port {port}") except Exception as e: print(f"❌ Error checking local service: {e}") print() # 设置隧道 result = setup_cloudflare_tunnel_with_dns_fix(port, timeout=180) if result: url, process = result print(f"\n🎉 Success!") print(f"🌐 Your service is accessible at: {url}") print(f"🔗 Test it: {url}/docs") print("\nPress Ctrl+C to stop") def signal_handler(sig, frame): print("\n🛑 Stopping tunnel...") process.terminate() try: process.wait(timeout=5) except subprocess.TimeoutExpired: process.kill() print("✅ Tunnel stopped") sys.exit(0) signal.signal(signal.SIGINT, signal_handler) try: while process.poll() is None: try: line = process.stdout.readline() if line: print(f"TUNNEL: {line.strip()}") except KeyboardInterrupt: break finally: process.terminate() else: print("\n❌ All attempts failed") print("\n🔧 Alternative solutions:") print("1. Ask network admin to whitelist *.trycloudflare.com") print("2. Use VS Code built-in port forwarding") print("3. Set up SSH tunnel to external server") print("4. Use internal reverse proxy") if __name__ == "__main__": main()