| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- """
- 通过修复 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()
|