TonyD365 commited on
Commit
bb61b8c
·
verified ·
1 Parent(s): 31f30fb

All url DNS use 8.8.8.8

Browse files
Files changed (1) hide show
  1. dns_resolver.py +30 -32
dns_resolver.py CHANGED
@@ -9,53 +9,48 @@ class DnsManager:
9
 
10
  def __new__(cls, *args, **kwargs):
11
  if not cls._instance:
 
12
  cls._instance = super(DnsManager, cls).__new__(cls)
13
  return cls._instance
14
 
15
  def __init__(self, cache_ttl=600):
16
- # 避免单例模式下重复初始化
17
  if hasattr(self, '_initialized'):
18
  return
19
  self.cache_ttl = cache_ttl
20
- self.cache = {} # 格式: {"hostname": {"ip": "xxx", "expiry": 0}}
21
- # 覆盖 Discord 机器人运行所需的所有关键域名
22
- self.target_hosts = [
23
- 'discord.com',
24
- 'gateway.discord.gg',
25
- 'cdn.discordapp.com',
26
- 'discordapp.com'
27
- ]
28
  self.logger = logging.getLogger("DnsManager")
29
  self._initialized = True
30
 
31
  def _fetch_ip_from_http(self, hostname):
32
- """通过 HTTPS (TCP 443) 绕过系统 UDP DNS 限制获取 IP"""
33
  try:
34
- # 使用 Google DNS API
35
  url = f"https://dns.google/resolve?name={hostname}&type=A"
36
  req = urllib.request.Request(url, headers={"Accept": "application/dns-json"})
37
  with urllib.request.urlopen(req, timeout=5) as response:
38
  data = json.loads(response.read().decode())
39
  if "Answer" in data:
40
- # 找到第一个 A 记录 (IPv4)
41
  for answer in data['Answer']:
42
- if answer['type'] == 1: # A record
43
  return answer['data']
44
  except Exception as e:
45
- self.logger.warning(f"无法通过 HTTP 解析 {hostname}: {e}")
46
  return None
47
 
48
  def get_ip(self, hostname):
49
- """获取 IP,优先使用缓存,过期则自动更新"""
 
 
 
 
50
  current_time = time.time()
51
-
52
  if hostname in self.cache:
53
  if current_time < self.cache[hostname]['expiry']:
54
  return self.cache[hostname]['ip']
55
 
56
- # 尝试更新 IP
57
  new_ip = self._fetch_ip_from_http(hostname)
58
-
59
  if new_ip:
60
  self.cache[hostname] = {
61
  "ip": new_ip,
@@ -64,32 +59,35 @@ class DnsManager:
64
  print(f"🔄 [DNS库] 动态解析成功: {hostname} -> {new_ip}")
65
  return new_ip
66
 
67
- # 如果获取失败,且缓存里有旧的,则延长旧缓存寿命并继续使用
68
  if hostname in self.cache:
69
- self.logger.warning(f"解析失败,正在使用 {hostname} 的过期缓存")
70
  return self.cache[hostname]['ip']
71
-
72
- # 最后的保底 hardcode IP (Discord 常用 IP)
73
  return "162.159.137.232"
74
 
75
  def patch_socket(self):
76
- """核心方法:将补丁注入 Python 局 socket 层"""
77
  original_getaddrinfo = socket.getaddrinfo
78
 
79
  def patched_getaddrinfo(*args, **kwargs):
80
  host = args[0]
81
- # 只有在目标域名列表里且不是正在请求 DNS 接口本身时才拦截
82
- if host in self.target_hosts:
 
 
 
 
 
 
 
83
  latest_ip = self.get_ip(host)
84
- port = args[1]
85
- # 强制返回 IPv4 地址族 (AF_INET),避免 IPv6 解析错误
86
  return [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (latest_ip, port))]
87
-
88
- # 其余请求(访问 MongoDB 或 Google DNS 接口)走原始解析
89
- return original_getaddrinfo(*args, **kwargs)
90
 
91
  socket.getaddrinfo = patched_getaddrinfo
92
- print("💉 [DNS库] 全局 Socket 补丁已加载,已绕过系统 DNS")
93
 
94
- # 导出实例
95
  dns_manager = DnsManager()
 
9
 
10
  def __new__(cls, *args, **kwargs):
11
  if not cls._instance:
12
+ # 使用 super() 调用 object 的 __new__ 来创建单例内存
13
  cls._instance = super(DnsManager, cls).__new__(cls)
14
  return cls._instance
15
 
16
  def __init__(self, cache_ttl=600):
 
17
  if hasattr(self, '_initialized'):
18
  return
19
  self.cache_ttl = cache_ttl
20
+ self.cache = {} # 缓存: {"hostname": {"ip": "xxx", "expiry": 0}}
 
 
 
 
 
 
 
21
  self.logger = logging.getLogger("DnsManager")
22
  self._initialized = True
23
 
24
  def _fetch_ip_from_http(self, hostname):
25
+ """核心:通过 HTTPS (TCP 443) 绕过系统 UDP DNS 限制获取 IP"""
26
  try:
27
+ # 注意:这里直接使用 Google DNS API 地址
28
  url = f"https://dns.google/resolve?name={hostname}&type=A"
29
  req = urllib.request.Request(url, headers={"Accept": "application/dns-json"})
30
  with urllib.request.urlopen(req, timeout=5) as response:
31
  data = json.loads(response.read().decode())
32
  if "Answer" in data:
 
33
  for answer in data['Answer']:
34
+ if answer['type'] == 1: # 只要 A 记录 (IPv4)
35
  return answer['data']
36
  except Exception as e:
37
+ self.logger.warning(f"DoH 解析失败 {hostname}: {e}")
38
  return None
39
 
40
  def get_ip(self, hostname):
41
+ """获取 IP 逻辑:缓存 -> DoH -> 保底"""
42
+ # 1. 如果是纯 IP 地址,直接返回
43
+ if hostname.replace('.', '').isdigit():
44
+ return hostname
45
+
46
  current_time = time.time()
47
+ # 2. 检查缓存
48
  if hostname in self.cache:
49
  if current_time < self.cache[hostname]['expiry']:
50
  return self.cache[hostname]['ip']
51
 
52
+ # 3. HTTP 解析
53
  new_ip = self._fetch_ip_from_http(hostname)
 
54
  if new_ip:
55
  self.cache[hostname] = {
56
  "ip": new_ip,
 
59
  print(f"🔄 [DNS库] 动态解析成功: {hostname} -> {new_ip}")
60
  return new_ip
61
 
62
+ # 4. 保底 IP (Discord)
63
  if hostname in self.cache:
 
64
  return self.cache[hostname]['ip']
 
 
65
  return "162.159.137.232"
66
 
67
  def patch_socket(self):
68
+ """注入补丁:除了 dns.google,部强行接管"""
69
  original_getaddrinfo = socket.getaddrinfo
70
 
71
  def patched_getaddrinfo(*args, **kwargs):
72
  host = args[0]
73
+ port = args[1]
74
+
75
+ # 关键排除逻辑:
76
+ # 如果请求的是 dns.google 本身,必须走原始解析,否则会陷入死循环(无限递归)
77
+ if host == "dns.google":
78
+ return original_getaddrinfo(*args, **kwargs)
79
+
80
+ # 其他所有请求(Discord, MongoDB 等)全部走补丁
81
+ try:
82
  latest_ip = self.get_ip(host)
83
+ # 强制返回 IPv4 结构体给系统
 
84
  return [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (latest_ip, port))]
85
+ except Exception:
86
+ # 最后的最后,果补丁崩了,尝试退回原始解析
87
+ return original_getaddrinfo(*args, **kwargs)
88
 
89
  socket.getaddrinfo = patched_getaddrinfo
90
+ print("💉 [DNS库] 全局覆盖模式已加载:除 dns.google 外所有域名解析托管至 DoH")
91
 
92
+ # 导出单例实例
93
  dns_manager = DnsManager()