cloudflare_dns_fix.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. """
  2. 通过修复 DNS 解析问题来使用 Cloudflare Tunnel
  3. """
  4. import subprocess
  5. import time
  6. import os
  7. import signal
  8. import sys
  9. import re
  10. import socket
  11. from pathlib import Path
  12. def setup_dns_resolution():
  13. """设置 DNS 解析"""
  14. print("🔧 Setting up DNS resolution...")
  15. # 临时 DNS 解析方案
  16. hosts_entries = {
  17. 'api.trycloudflare.com': '104.18.22.223', # Cloudflare IP
  18. 'trycloudflare.com': '104.18.22.223'
  19. }
  20. # 写入临时 hosts 文件
  21. temp_hosts = Path.home() / 'zhch' / 'temp_hosts'
  22. with open(temp_hosts, 'w') as f:
  23. for domain, ip in hosts_entries.items():
  24. f.write(f"{ip} {domain}\n")
  25. print(f"✅ Created temporary hosts file: {temp_hosts}")
  26. return str(temp_hosts)
  27. def test_dns_resolution():
  28. """测试 DNS 解析"""
  29. test_domains = [
  30. 'api.trycloudflare.com',
  31. 'google.com',
  32. 'cloudflare.com'
  33. ]
  34. print("🧪 Testing DNS resolution...")
  35. for domain in test_domains:
  36. try:
  37. ip = socket.gethostbyname(domain)
  38. print(f"✅ {domain} -> {ip}")
  39. except socket.gaierror as e:
  40. print(f"❌ {domain} -> Failed: {e}")
  41. def setup_environment_with_dns():
  42. """设置包含 DNS 配置的环境变量"""
  43. proxy_url = "http://172.16.40.16:7280"
  44. env = os.environ.copy()
  45. # 基本代理配置
  46. env.update({
  47. 'HTTP_PROXY': proxy_url,
  48. 'HTTPS_PROXY': proxy_url,
  49. 'http_proxy': proxy_url,
  50. 'https_proxy': proxy_url,
  51. })
  52. # DNS 配置
  53. env.update({
  54. 'GODEBUG': 'netdns=go+1',
  55. 'GOPROXY': 'direct',
  56. 'GOSUMDB': 'off',
  57. })
  58. # 使用公共 DNS
  59. env['NAMESERVER'] = '8.8.8.8'
  60. return env
  61. def download_cloudflared_direct():
  62. """直接下载 cloudflared(绕过 DNS 问题)"""
  63. print("🔄 Downloading cloudflared directly...")
  64. bin_dir = Path.home() / "zhch" / "bin"
  65. bin_dir.mkdir(exist_ok=True, parents=True)
  66. cloudflared_path = bin_dir / "cloudflared"
  67. if cloudflared_path.exists():
  68. print("✅ Cloudflared already exists")
  69. return str(cloudflared_path)
  70. # 使用直接 IP 地址下载(绕过 DNS)
  71. github_ip = "140.82.113.3" # GitHub IP
  72. download_cmd = [
  73. 'curl', '-L', '-k', # -k 忽略 SSL 证书验证
  74. '-H', f'Host: github.com',
  75. f'http://{github_ip}/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64',
  76. '-o', str(cloudflared_path)
  77. ]
  78. try:
  79. env = setup_environment_with_dns()
  80. result = subprocess.run(
  81. download_cmd,
  82. check=True,
  83. env=env,
  84. capture_output=True,
  85. text=True,
  86. timeout=300
  87. )
  88. subprocess.run(['chmod', '+x', str(cloudflared_path)], check=True)
  89. print("✅ Cloudflared downloaded successfully")
  90. return str(cloudflared_path)
  91. except Exception as e:
  92. print(f"❌ Download failed: {e}")
  93. # 备选方案:使用 wget
  94. try:
  95. wget_cmd = [
  96. 'wget', '--no-check-certificate',
  97. '--header', f'Host: github.com',
  98. f'http://{github_ip}/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64',
  99. '-O', str(cloudflared_path)
  100. ]
  101. subprocess.run(wget_cmd, check=True, env=env, timeout=300)
  102. subprocess.run(['chmod', '+x', str(cloudflared_path)], check=True)
  103. print("✅ Cloudflared downloaded with wget")
  104. return str(cloudflared_path)
  105. except Exception as e2:
  106. print(f"❌ Wget also failed: {e2}")
  107. return None
  108. def setup_cloudflare_tunnel_with_dns_fix(port=8101, timeout=120):
  109. """使用 DNS 修复的 Cloudflare Tunnel 设置"""
  110. print(f"🔄 Setting up Cloudflare Tunnel for port {port} with DNS fix...")
  111. # 测试 DNS
  112. test_dns_resolution()
  113. # 下载 cloudflared
  114. cloudflared_path = download_cloudflared_direct()
  115. if not cloudflared_path:
  116. print("❌ Could not download cloudflared")
  117. return None
  118. # 创建日志目录
  119. log_dir = Path.home() / 'zhch' / 'logs'
  120. log_dir.mkdir(exist_ok=True, parents=True)
  121. # 准备命令
  122. tunnel_cmd = [
  123. cloudflared_path, 'tunnel',
  124. '--url', f'http://localhost:{port}',
  125. '--no-autoupdate',
  126. '--logfile', str(log_dir / 'cloudflared.log'),
  127. '--loglevel', 'debug' # 更详细的日志
  128. ]
  129. print(f"🚀 Starting tunnel: {' '.join(tunnel_cmd)}")
  130. try:
  131. env = setup_environment_with_dns()
  132. # 显示环境配置
  133. print("🔧 Environment configuration:")
  134. for key in ['HTTP_PROXY', 'HTTPS_PROXY', 'GODEBUG', 'NAMESERVER']:
  135. print(f" {key}: {env.get(key, 'Not set')}")
  136. process = subprocess.Popen(
  137. tunnel_cmd,
  138. stdout=subprocess.PIPE,
  139. stderr=subprocess.STDOUT,
  140. text=True,
  141. env=env,
  142. bufsize=1,
  143. universal_newlines=True
  144. )
  145. print("⏳ Waiting for tunnel to start...")
  146. start_time = time.time()
  147. while time.time() - start_time < timeout:
  148. if process.poll() is not None:
  149. stdout, _ = process.communicate()
  150. print(f"❌ Process terminated early:")
  151. print(stdout)
  152. return None
  153. try:
  154. line = process.stdout.readline()
  155. if line:
  156. line = line.strip()
  157. print(f"LOG: {line}")
  158. # 查找成功的隧道 URL
  159. if 'trycloudflare.com' in line:
  160. url_match = re.search(r'https://[a-zA-Z0-9-]+\.trycloudflare\.com', line)
  161. if url_match:
  162. url = url_match.group(0)
  163. print(f"✅ Tunnel URL found: {url}")
  164. return url, process
  165. # 检查特定错误
  166. if 'dial tcp: lookup api.trycloudflare.com' in line:
  167. print("❌ DNS lookup failed for api.trycloudflare.com")
  168. print("🔧 Trying DNS workaround...")
  169. break
  170. if 'failed to request quick Tunnel' in line:
  171. print("❌ Failed to create tunnel")
  172. break
  173. except Exception as e:
  174. print(f"Error reading output: {e}")
  175. break
  176. time.sleep(0.5)
  177. print(f"⏰ Timeout after {timeout} seconds")
  178. process.terminate()
  179. return None
  180. except Exception as e:
  181. print(f"❌ Failed to start tunnel: {e}")
  182. return None
  183. def main():
  184. port = 8101
  185. print("🌐 Cloudflare Tunnel Setup with DNS Fix")
  186. print("=" * 60)
  187. # 检查网络连接
  188. print("🔍 Network diagnostics:")
  189. # 检查代理连接
  190. try:
  191. result = subprocess.run(['curl', '-s', '--connect-timeout', '5',
  192. 'http://httpbin.org/ip'],
  193. capture_output=True, text=True)
  194. if result.returncode == 0:
  195. print("✅ Proxy connection working")
  196. else:
  197. print("❌ Proxy connection failed")
  198. except:
  199. print("❌ Could not test proxy")
  200. # 检查本地服务
  201. import socket
  202. try:
  203. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  204. sock.settimeout(2)
  205. result = sock.connect_ex(('localhost', port))
  206. sock.close()
  207. if result == 0:
  208. print(f"✅ Local service running on port {port}")
  209. else:
  210. print(f"⚠️ No service on port {port}")
  211. except Exception as e:
  212. print(f"❌ Error checking local service: {e}")
  213. print()
  214. # 设置隧道
  215. result = setup_cloudflare_tunnel_with_dns_fix(port, timeout=180)
  216. if result:
  217. url, process = result
  218. print(f"\n🎉 Success!")
  219. print(f"🌐 Your service is accessible at: {url}")
  220. print(f"🔗 Test it: {url}/docs")
  221. print("\nPress Ctrl+C to stop")
  222. def signal_handler(sig, frame):
  223. print("\n🛑 Stopping tunnel...")
  224. process.terminate()
  225. try:
  226. process.wait(timeout=5)
  227. except subprocess.TimeoutExpired:
  228. process.kill()
  229. print("✅ Tunnel stopped")
  230. sys.exit(0)
  231. signal.signal(signal.SIGINT, signal_handler)
  232. try:
  233. while process.poll() is None:
  234. try:
  235. line = process.stdout.readline()
  236. if line:
  237. print(f"TUNNEL: {line.strip()}")
  238. except KeyboardInterrupt:
  239. break
  240. finally:
  241. process.terminate()
  242. else:
  243. print("\n❌ All attempts failed")
  244. print("\n🔧 Alternative solutions:")
  245. print("1. Ask network admin to whitelist *.trycloudflare.com")
  246. print("2. Use VS Code built-in port forwarding")
  247. print("3. Set up SSH tunnel to external server")
  248. print("4. Use internal reverse proxy")
  249. if __name__ == "__main__":
  250. main()