Browse Source

feat(zhch): 添加 Cloudflare Tunnel 设置脚本,修复 DNS 解析问题

zhch158_admin 3 months ago
parent
commit
a38b7d7071
1 changed files with 304 additions and 0 deletions
  1. 304 0
      zhch/cloudflare_dns_fix.py

+ 304 - 0
zhch/cloudflare_dns_fix.py

@@ -0,0 +1,304 @@
+"""
+通过修复 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()