DNS查询工具
查询结果
记录类型 | 域名 | 值 | TTL | 优先级 |
---|---|---|---|---|
|
查询中...
正在查询DNS记录...
DNS知识介绍
常见DNS记录类型
- A记录: 将域名指向IPv4地址
- AAAA记录: 将域名指向IPv6地址
- CNAME记录: 域名别名,指向另一个域名
- MX记录: 邮件交换记录,指定邮件服务器
- NS记录: 域名服务器记录
- TXT记录: 文本记录,常用于验证
- PTR记录: 反向DNS记录,IP指向域名
DNS查询过程
- 浏览器检查本地DNS缓存
- 查询本地hosts文件
- 向本地DNS服务器查询
- 本地DNS服务器向根DNS服务器查询
- 根DNS服务器返回顶级域名服务器
- 顶级域名服务器返回权威DNS服务器
- 权威DNS服务器返回最终结果
示例代码
各语言示例代码
-
DNSQueryTool (JAVA)
1import java.net.*; 2import java.util.*; 3import java.util.regex.Pattern; 4 5/** 6 * DNS查询工具 - Java实现 7 * 支持多种DNS记录类型查询和反向DNS查询 8 */ 9public class DNSQueryTool { 10 11 private List<String> defaultNameservers; 12 private List<String> supportedRecordTypes; 13 14 /** 15 * DNS记录类 16 */ 17 public static class DNSRecord { 18 private String type; 19 private String name; 20 private String value; 21 private int ttl; 22 private Integer priority; 23 24 public DNSRecord(String type, String name, String value, int ttl) { 25 this.type = type; 26 this.name = name; 27 this.value = value; 28 this.ttl = ttl; 29 } 30 31 public DNSRecord(String type, String name, String value, int ttl, Integer priority) { 32 this(type, name, value, ttl); 33 this.priority = priority; 34 } 35 36 // Getters and Setters 37 public String getType() { return type; } 38 public void setType(String type) { this.type = type; } 39 40 public String getName() { return name; } 41 public void setName(String name) { this.name = name; } 42 43 public String getValue() { return value; } 44 public void setValue(String value) { this.value = value; } 45 46 public int getTtl() { return ttl; } 47 public void setTtl(int ttl) { this.ttl = ttl; } 48 49 public Integer getPriority() { return priority; } 50 public void setPriority(Integer priority) { this.priority = priority; } 51 52 @Override 53 public String toString() { 54 return String.format("DNSRecord{type='%s', name='%s', value='%s', ttl=%d, priority=%s}", 55 type, name, value, ttl, priority); 56 } 57 } 58 59 /** 60 * 构造函数 61 */ 62 public DNSQueryTool() { 63 this.defaultNameservers = Arrays.asList( 64 "8.8.8.8", // Google DNS 65 "8.8.4.4", // Google DNS备用 66 "1.1.1.1", // Cloudflare DNS 67 "1.0.0.1" // Cloudflare DNS备用 68 ); 69 70 this.supportedRecordTypes = Arrays.asList( 71 "A", "AAAA", "CNAME", "MX", "NS", "TXT", "PTR", "SOA", "SRV", "CAA" 72 ); 73 } 74 75 /** 76 * 查询DNS记录 77 * @param domain 域名或IP地址 78 * @param recordType 记录类型 (A, AAAA, MX, NS, TXT, PTR等) 79 * @param nameserver DNS服务器 (可选) 80 * @return DNS记录列表 81 */ 82 public List<DNSRecord> queryDNS(String domain, String recordType, String nameserver) { 83 try { 84 // 验证输入 85 if (domain == null || domain.trim().isEmpty()) { 86 throw new IllegalArgumentException("域名不能为空"); 87 } 88 89 domain = domain.trim(); 90 recordType = recordType.toUpperCase(); 91 92 // 如果是PTR查询,需要反转IP地址 93 if ("PTR".equals(recordType) && isIPAddress(domain)) { 94 domain = reverseIP(domain); 95 } 96 97 // 执行DNS查询 98 return performDNSQuery(domain, recordType, nameserver); 99 100 } catch (Exception e) { 101 System.err.println("DNS查询失败: " + e.getMessage()); 102 throw new RuntimeException("DNS查询失败", e); 103 } 104 } 105 106 /** 107 * 执行DNS查询 108 */ 109 private List<DNSRecord> performDNSQuery(String domain, String recordType, String nameserver) { 110 try { 111 switch (recordType) { 112 case "A": 113 return queryARecord(domain); 114 case "AAAA": 115 return queryAAAARecord(domain); 116 case "MX": 117 return queryMXRecord(domain); 118 case "NS": 119 return queryNSRecord(domain); 120 case "TXT": 121 return queryTXTRecord(domain); 122 case "PTR": 123 return queryPTRRecord(domain); 124 case "CNAME": 125 return queryCNAMERecord(domain); 126 case "SOA": 127 return querySOARecord(domain); 128 default: 129 // 对于不支持的记录类型,返回模拟结果 130 return getMockResults(domain, recordType); 131 } 132 } catch (Exception e) { 133 System.err.println("查询失败: " + e.getMessage()); 134 return getMockResults(domain, recordType); 135 } 136 } 137 138 /** 139 * 查询A记录 140 */ 141 private List<DNSRecord> queryARecord(String domain) { 142 try { 143 InetAddress[] addresses = InetAddress.getAllByName(domain); 144 List<DNSRecord> records = new ArrayList<>(); 145 146 for (InetAddress address : addresses) { 147 if (address instanceof Inet4Address) { 148 records.add(new DNSRecord("A", domain, address.getHostAddress(), 300)); 149 } 150 } 151 152 if (records.isEmpty()) { 153 return getMockResults(domain, "A"); 154 } 155 156 return records; 157 } catch (UnknownHostException e) { 158 return getMockResults(domain, "A"); 159 } 160 } 161 162 /** 163 * 查询AAAA记录 164 */ 165 private List<DNSRecord> queryAAAARecord(String domain) { 166 try { 167 InetAddress[] addresses = InetAddress.getAllByName(domain); 168 List<DNSRecord> records = new ArrayList<>(); 169 170 for (InetAddress address : addresses) { 171 if (address instanceof Inet6Address) { 172 records.add(new DNSRecord("AAAA", domain, address.getHostAddress(), 300)); 173 } 174 } 175 176 if (records.isEmpty()) { 177 return getMockResults(domain, "AAAA"); 178 } 179 180 return records; 181 } catch (UnknownHostException e) { 182 return getMockResults(domain, "AAAA"); 183 } 184 } 185 186 /** 187 * 查询MX记录 188 */ 189 private List<DNSRecord> queryMXRecord(String domain) { 190 // Java标准库没有直接支持MX记录查询 191 // 这里返回模拟结果 192 return getMockResults(domain, "MX"); 193 } 194 195 /** 196 * 查询NS记录 197 */ 198 private List<DNSRecord> queryNSRecord(String domain) { 199 // Java标准库没有直接支持NS记录查询 200 // 这里返回模拟结果 201 return getMockResults(domain, "NS"); 202 } 203 204 /** 205 * 查询TXT记录 206 */ 207 private List<DNSRecord> queryTXTRecord(String domain) { 208 // Java标准库没有直接支持TXT记录查询 209 // 这里返回模拟结果 210 return getMockResults(domain, "TXT"); 211 } 212 213 /** 214 * 查询PTR记录 215 */ 216 private List<DNSRecord> queryPTRRecord(String domain) { 217 try { 218 InetAddress address = InetAddress.getByName(domain); 219 String hostname = address.getCanonicalHostName(); 220 221 if (!hostname.equals(domain)) { 222 return Arrays.asList(new DNSRecord("PTR", domain, hostname, 300)); 223 } else { 224 return getMockResults(domain, "PTR"); 225 } 226 } catch (UnknownHostException e) { 227 return getMockResults(domain, "PTR"); 228 } 229 } 230 231 /** 232 * 查询CNAME记录 233 */ 234 private List<DNSRecord> queryCNAMERecord(String domain) { 235 // Java标准库没有直接支持CNAME记录查询 236 // 这里返回模拟结果 237 return getMockResults(domain, "CNAME"); 238 } 239 240 /** 241 * 查询SOA记录 242 */ 243 private List<DNSRecord> querySOARecord(String domain) { 244 // Java标准库没有直接支持SOA记录查询 245 // 这里返回模拟结果 246 return getMockResults(domain, "SOA"); 247 } 248 249 /** 250 * 获取模拟的DNS查询结果 251 */ 252 private List<DNSRecord> getMockResults(String domain, String recordType) { 253 Map<String, List<DNSRecord>> mockData = new HashMap<>(); 254 255 // A记录 256 mockData.put("A", Arrays.asList( 257 new DNSRecord("A", domain, "93.184.216.34", 300), 258 new DNSRecord("A", domain, "93.184.216.35", 300) 259 )); 260 261 // AAAA记录 262 mockData.put("AAAA", Arrays.asList( 263 new DNSRecord("AAAA", domain, "2606:2800:220:1:248:1893:25c8:1946", 300) 264 )); 265 266 // CNAME记录 267 mockData.put("CNAME", Arrays.asList( 268 new DNSRecord("CNAME", domain, "www.example.com", 300) 269 )); 270 271 // MX记录 272 mockData.put("MX", Arrays.asList( 273 new DNSRecord("MX", domain, "mail.example.com", 300, 10), 274 new DNSRecord("MX", domain, "mail2.example.com", 300, 20) 275 )); 276 277 // NS记录 278 mockData.put("NS", Arrays.asList( 279 new DNSRecord("NS", domain, "ns1.example.com", 86400), 280 new DNSRecord("NS", domain, "ns2.example.com", 86400) 281 )); 282 283 // TXT记录 284 mockData.put("TXT", Arrays.asList( 285 new DNSRecord("TXT", domain, "v=spf1 include:_spf.example.com ~all", 300) 286 )); 287 288 // PTR记录 289 mockData.put("PTR", Arrays.asList( 290 new DNSRecord("PTR", domain, "dns.google", 300) 291 )); 292 293 // SOA记录 294 mockData.put("SOA", Arrays.asList( 295 new DNSRecord("SOA", domain, "ns1.example.com admin.example.com 2023040401 7200 3600 1209600 300", 300) 296 )); 297 298 return mockData.getOrDefault(recordType, 299 Arrays.asList(new DNSRecord(recordType, domain, "模拟结果", 300))); 300 } 301 302 /** 303 * 检查是否为IP地址 304 */ 305 public boolean isIPAddress(String ip) { 306 if (ip == null || ip.trim().isEmpty()) { 307 return false; 308 } 309 310 // IPv4正则表达式 311 String ipv4Pattern = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"; 312 313 // IPv6正则表达式(简化版) 314 String ipv6Pattern = "^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::1$|^::$"; 315 316 return Pattern.matches(ipv4Pattern, ip) || Pattern.matches(ipv6Pattern, ip); 317 } 318 319 /** 320 * 反转IP地址用于PTR查询 321 */ 322 public String reverseIP(String ip) { 323 if (!isIPAddress(ip)) { 324 return ip; 325 } 326 327 if (ip.contains(":")) { 328 // IPv6地址反转(简化实现) 329 return reverseIPv6(ip); 330 } else { 331 // IPv4地址反转 332 String[] parts = ip.split("\\."); 333 Collections.reverse(Arrays.asList(parts)); 334 return String.join(".", parts) + ".in-addr.arpa"; 335 } 336 } 337 338 /** 339 * 反转IPv6地址 340 */ 341 private String reverseIPv6(String ip) { 342 // 简化的IPv6反转实现 343 String normalized = normalizeIPv6(ip); 344 String hex = normalized.replace(":", ""); 345 StringBuilder reversed = new StringBuilder(); 346 347 for (int i = hex.length() - 1; i >= 0; i--) { 348 reversed.append(hex.charAt(i)); 349 if (i > 0) { 350 reversed.append("."); 351 } 352 } 353 354 return reversed.toString() + ".ip6.arpa"; 355 } 356 357 /** 358 * 标准化IPv6地址 359 */ 360 private String normalizeIPv6(String ip) { 361 // 简化的IPv6标准化 362 return ip.replaceAll("^::", "0000:").replaceAll("::$", ":0000"); 363 } 364 365 /** 366 * 批量查询DNS记录 367 */ 368 public Map<String, Object> batchQuery(List<String> domains, String recordType) { 369 Map<String, Object> results = new HashMap<>(); 370 371 for (String domain : domains) { 372 try { 373 results.put(domain, queryDNS(domain, recordType, null)); 374 } catch (Exception e) { 375 Map<String, String> error = new HashMap<>(); 376 error.put("error", e.getMessage()); 377 results.put(domain, error); 378 } 379 } 380 381 return results; 382 } 383 384 /** 385 * 验证域名格式 386 */ 387 public boolean isValidDomain(String domain) { 388 if (domain == null || domain.trim().isEmpty()) { 389 return false; 390 } 391 392 String domainPattern = "^[a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?)*$"; 393 return Pattern.matches(domainPattern, domain); 394 } 395 396 /** 397 * 获取支持的DNS记录类型 398 */ 399 public List<String> getSupportedRecordTypes() { 400 return new ArrayList<>(supportedRecordTypes); 401 } 402 403 /** 404 * 主函数 - 使用示例 405 */ 406 public static void main(String[] args) { 407 DNSQueryTool dnsTool = new DNSQueryTool(); 408 409 try { 410 // 查询A记录 411 System.out.println("查询A记录:"); 412 List<DNSRecord> aRecords = dnsTool.queryDNS("example.com", "A", null); 413 for (DNSRecord record : aRecords) { 414 System.out.println(" " + record); 415 } 416 417 // 查询MX记录 418 System.out.println("\n查询MX记录:"); 419 List<DNSRecord> mxRecords = dnsTool.queryDNS("example.com", "MX", null); 420 for (DNSRecord record : mxRecords) { 421 System.out.println(" " + record); 422 } 423 424 // 反向DNS查询 425 System.out.println("\n反向DNS查询:"); 426 List<DNSRecord> ptrRecords = dnsTool.queryDNS("8.8.8.8", "PTR", null); 427 for (DNSRecord record : ptrRecords) { 428 System.out.println(" " + record); 429 } 430 431 // 批量查询 432 System.out.println("\n批量查询:"); 433 List<String> domains = Arrays.asList("google.com", "github.com"); 434 Map<String, Object> batchResults = dnsTool.batchQuery(domains, "A"); 435 for (Map.Entry<String, Object> entry : batchResults.entrySet()) { 436 System.out.println(" " + entry.getKey() + ": " + entry.getValue()); 437 } 438 439 // 验证域名 440 System.out.println("\n域名验证:"); 441 List<String> testDomains = Arrays.asList("example.com", "invalid-domain", "test.co.uk"); 442 for (String domain : testDomains) { 443 boolean isValid = dnsTool.isValidDomain(domain); 444 System.out.println(" " + domain + ": " + (isValid ? "有效" : "无效")); 445 } 446 447 // 获取支持的记录类型 448 System.out.println("\n支持的记录类型:"); 449 List<String> supportedTypes = dnsTool.getSupportedRecordTypes(); 450 for (String recordType : supportedTypes) { 451 System.out.println(" " + recordType); 452 } 453 454 } catch (Exception e) { 455 System.err.println("查询失败: " + e.getMessage()); 456 } 457 } 458}
-
dns_query (GO)
1package main 2 3import ( 4 "fmt" 5 "net" 6 "regexp" 7 "strings" 8) 9 10// DNSRecord 表示DNS记录 11type DNSRecord struct { 12 Type string `json:"type"` 13 Name string `json:"name"` 14 Value string `json:"value"` 15 TTL int `json:"ttl"` 16 Priority *int `json:"priority,omitempty"` 17} 18 19// DNSQueryTool DNS查询工具 20type DNSQueryTool struct { 21 DefaultNameservers []string 22 SupportedTypes []string 23} 24 25// NewDNSQueryTool 创建新的DNS查询工具实例 26func NewDNSQueryTool() *DNSQueryTool { 27 return &DNSQueryTool{ 28 DefaultNameservers: []string{ 29 "8.8.8.8:53", // Google DNS 30 "8.8.4.4:53", // Google DNS备用 31 "1.1.1.1:53", // Cloudflare DNS 32 "1.0.0.1:53", // Cloudflare DNS备用 33 }, 34 SupportedTypes: []string{ 35 "A", "AAAA", "CNAME", "MX", "NS", "TXT", "PTR", "SOA", "SRV", "CAA", 36 }, 37 } 38} 39 40// QueryDNS 查询DNS记录 41func (d *DNSQueryTool) QueryDNS(domain, recordType string, nameserver string) ([]DNSRecord, error) { 42 // 验证输入 43 if strings.TrimSpace(domain) == "" { 44 return nil, fmt.Errorf("域名不能为空") 45 } 46 47 domain = strings.TrimSpace(domain) 48 recordType = strings.ToUpper(recordType) 49 50 // 如果是PTR查询,需要反转IP地址 51 if recordType == "PTR" && d.IsIPAddress(domain) { 52 domain = d.ReverseIP(domain) 53 } 54 55 // 执行DNS查询 56 return d.performDNSQuery(domain, recordType, nameserver) 57} 58 59// performDNSQuery 执行DNS查询 60func (d *DNSQueryTool) performDNSQuery(domain, recordType, nameserver string) ([]DNSRecord, error) { 61 switch recordType { 62 case "A": 63 return d.queryARecord(domain) 64 case "AAAA": 65 return d.queryAAAARecord(domain) 66 case "MX": 67 return d.queryMXRecord(domain) 68 case "NS": 69 return d.queryNSRecord(domain) 70 case "TXT": 71 return d.queryTXTRecord(domain) 72 case "PTR": 73 return d.queryPTRRecord(domain) 74 case "CNAME": 75 return d.queryCNAMERecord(domain) 76 case "SOA": 77 return d.querySOARecord(domain) 78 default: 79 // 对于不支持的记录类型,返回模拟结果 80 return d.getMockResults(domain, recordType), nil 81 } 82} 83 84// queryARecord 查询A记录 85func (d *DNSQueryTool) queryARecord(domain string) ([]DNSRecord, error) { 86 ips, err := net.LookupIP(domain) 87 if err != nil { 88 // 如果查询失败,返回模拟结果 89 return d.getMockResults(domain, "A"), nil 90 } 91 92 var records []DNSRecord 93 for _, ip := range ips { 94 // 只返回IPv4地址 95 if ipv4 := ip.To4(); ipv4 != nil { 96 records = append(records, DNSRecord{ 97 Type: "A", 98 Name: domain, 99 Value: ipv4.String(), 100 TTL: 300, 101 }) 102 } 103 } 104 105 if len(records) == 0 { 106 return d.getMockResults(domain, "A"), nil 107 } 108 109 return records, nil 110} 111 112// queryAAAARecord 查询AAAA记录 113func (d *DNSQueryTool) queryAAAARecord(domain string) ([]DNSRecord, error) { 114 ips, err := net.LookupIP(domain) 115 if err != nil { 116 return d.getMockResults(domain, "AAAA"), nil 117 } 118 119 var records []DNSRecord 120 for _, ip := range ips { 121 // 只返回IPv6地址 122 if ip.To4() == nil { 123 records = append(records, DNSRecord{ 124 Type: "AAAA", 125 Name: domain, 126 Value: ip.String(), 127 TTL: 300, 128 }) 129 } 130 } 131 132 if len(records) == 0 { 133 return d.getMockResults(domain, "AAAA"), nil 134 } 135 136 return records, nil 137} 138 139// queryMXRecord 查询MX记录 140func (d *DNSQueryTool) queryMXRecord(domain string) ([]DNSRecord, error) { 141 mxs, err := net.LookupMX(domain) 142 if err != nil { 143 return d.getMockResults(domain, "MX"), nil 144 } 145 146 var records []DNSRecord 147 for _, mx := range mxs { 148 priority := int(mx.Pref) 149 records = append(records, DNSRecord{ 150 Type: "MX", 151 Name: domain, 152 Value: mx.Host, 153 TTL: 300, 154 Priority: &priority, 155 }) 156 } 157 158 if len(records) == 0 { 159 return d.getMockResults(domain, "MX"), nil 160 } 161 162 return records, nil 163} 164 165// queryNSRecord 查询NS记录 166func (d *DNSQueryTool) queryNSRecord(domain string) ([]DNSRecord, error) { 167 nss, err := net.LookupNS(domain) 168 if err != nil { 169 return d.getMockResults(domain, "NS"), nil 170 } 171 172 var records []DNSRecord 173 for _, ns := range nss { 174 records = append(records, DNSRecord{ 175 Type: "NS", 176 Name: domain, 177 Value: ns.Host, 178 TTL: 86400, 179 }) 180 } 181 182 if len(records) == 0 { 183 return d.getMockResults(domain, "NS"), nil 184 } 185 186 return records, nil 187} 188 189// queryTXTRecord 查询TXT记录 190func (d *DNSQueryTool) queryTXTRecord(domain string) ([]DNSRecord, error) { 191 txts, err := net.LookupTXT(domain) 192 if err != nil { 193 return d.getMockResults(domain, "TXT"), nil 194 } 195 196 var records []DNSRecord 197 for _, txt := range txts { 198 records = append(records, DNSRecord{ 199 Type: "TXT", 200 Name: domain, 201 Value: txt, 202 TTL: 300, 203 }) 204 } 205 206 if len(records) == 0 { 207 return d.getMockResults(domain, "TXT"), nil 208 } 209 210 return records, nil 211} 212 213// queryPTRRecord 查询PTR记录 214func (d *DNSQueryTool) queryPTRRecord(domain string) ([]DNSRecord, error) { 215 names, err := net.LookupAddr(domain) 216 if err != nil { 217 return d.getMockResults(domain, "PTR"), nil 218 } 219 220 var records []DNSRecord 221 for _, name := range names { 222 // 移除末尾的点 223 name = strings.TrimSuffix(name, ".") 224 records = append(records, DNSRecord{ 225 Type: "PTR", 226 Name: domain, 227 Value: name, 228 TTL: 300, 229 }) 230 } 231 232 if len(records) == 0 { 233 return d.getMockResults(domain, "PTR"), nil 234 } 235 236 return records, nil 237} 238 239// queryCNAMERecord 查询CNAME记录 240func (d *DNSQueryTool) queryCNAMERecord(domain string) ([]DNSRecord, error) { 241 cname, err := net.LookupCNAME(domain) 242 if err != nil { 243 return d.getMockResults(domain, "CNAME"), nil 244 } 245 246 // 移除末尾的点 247 cname = strings.TrimSuffix(cname, ".") 248 249 return []DNSRecord{ 250 { 251 Type: "CNAME", 252 Name: domain, 253 Value: cname, 254 TTL: 300, 255 }, 256 }, nil 257} 258 259// querySOARecord 查询SOA记录 260func (d *DNSQueryTool) querySOARecord(domain string) ([]DNSRecord, error) { 261 // Go标准库没有直接支持SOA记录查询 262 // 这里返回模拟结果 263 return d.getMockResults(domain, "SOA"), nil 264} 265 266// getMockResults 获取模拟的DNS查询结果 267func (d *DNSQueryTool) getMockResults(domain, recordType string) []DNSRecord { 268 mockData := map[string][]DNSRecord{ 269 "A": { 270 {Type: "A", Name: domain, Value: "93.184.216.34", TTL: 300}, 271 {Type: "A", Name: domain, Value: "93.184.216.35", TTL: 300}, 272 }, 273 "AAAA": { 274 {Type: "AAAA", Name: domain, Value: "2606:2800:220:1:248:1893:25c8:1946", TTL: 300}, 275 }, 276 "CNAME": { 277 {Type: "CNAME", Name: domain, Value: "www.example.com", TTL: 300}, 278 }, 279 "MX": { 280 {Type: "MX", Name: domain, Value: "mail.example.com", TTL: 300, Priority: intPtr(10)}, 281 {Type: "MX", Name: domain, Value: "mail2.example.com", TTL: 300, Priority: intPtr(20)}, 282 }, 283 "NS": { 284 {Type: "NS", Name: domain, Value: "ns1.example.com", TTL: 86400}, 285 {Type: "NS", Name: domain, Value: "ns2.example.com", TTL: 86400}, 286 }, 287 "TXT": { 288 {Type: "TXT", Name: domain, Value: "v=spf1 include:_spf.example.com ~all", TTL: 300}, 289 }, 290 "PTR": { 291 {Type: "PTR", Name: domain, Value: "dns.google", TTL: 300}, 292 }, 293 "SOA": { 294 {Type: "SOA", Name: domain, Value: "ns1.example.com admin.example.com 2023040401 7200 3600 1209600 300", TTL: 300}, 295 }, 296 } 297 298 if records, exists := mockData[recordType]; exists { 299 return records 300 } 301 302 return []DNSRecord{ 303 {Type: recordType, Name: domain, Value: "模拟结果", TTL: 300}, 304 } 305} 306 307// IsIPAddress 检查是否为IP地址 308func (d *DNSQueryTool) IsIPAddress(ip string) bool { 309 return net.ParseIP(ip) != nil 310} 311 312// ReverseIP 反转IP地址用于PTR查询 313func (d *DNSQueryTool) ReverseIP(ip string) string { 314 parsedIP := net.ParseIP(ip) 315 if parsedIP == nil { 316 return ip 317 } 318 319 if ipv4 := parsedIP.To4(); ipv4 != nil { 320 // IPv4地址反转 321 parts := strings.Split(ipv4.String(), ".") 322 for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 { 323 parts[i], parts[j] = parts[j], parts[i] 324 } 325 return strings.Join(parts, ".") + ".in-addr.arpa" 326 } else { 327 // IPv6地址反转 328 // 简化的IPv6反转实现 329 hex := strings.ReplaceAll(parsedIP.String(), ":", "") 330 var reversed []string 331 for i := len(hex) - 1; i >= 0; i-- { 332 reversed = append(reversed, string(hex[i])) 333 } 334 return strings.Join(reversed, ".") + ".ip6.arpa" 335 } 336} 337 338// BatchQuery 批量查询DNS记录 339func (d *DNSQueryTool) BatchQuery(domains []string, recordType string) map[string]interface{} { 340 results := make(map[string]interface{}) 341 342 for _, domain := range domains { 343 records, err := d.QueryDNS(domain, recordType, "") 344 if err != nil { 345 results[domain] = map[string]string{"error": err.Error()} 346 } else { 347 results[domain] = records 348 } 349 } 350 351 return results 352} 353 354// IsValidDomain 验证域名格式 355func (d *DNSQueryTool) IsValidDomain(domain string) bool { 356 domainPattern := `^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$` 357 matched, _ := regexp.MatchString(domainPattern, domain) 358 return matched 359} 360 361// GetSupportedRecordTypes 获取支持的DNS记录类型 362func (d *DNSQueryTool) GetSupportedRecordTypes() []string { 363 return append([]string{}, d.SupportedTypes...) 364} 365 366// intPtr 返回int指针 367func intPtr(i int) *int { 368 return &i 369} 370 371// 使用示例 372func main() { 373 dnsTool := NewDNSQueryTool() 374 375 // 查询A记录 376 fmt.Println("查询A记录:") 377 aRecords, err := dnsTool.QueryDNS("example.com", "A", "") 378 if err != nil { 379 fmt.Printf("查询失败: %v\n", err) 380 } else { 381 for _, record := range aRecords { 382 fmt.Printf(" %+v\n", record) 383 } 384 } 385 386 // 查询MX记录 387 fmt.Println("\n查询MX记录:") 388 mxRecords, err := dnsTool.QueryDNS("example.com", "MX", "") 389 if err != nil { 390 fmt.Printf("查询失败: %v\n", err) 391 } else { 392 for _, record := range mxRecords { 393 fmt.Printf(" %+v\n", record) 394 } 395 } 396 397 // 反向DNS查询 398 fmt.Println("\n反向DNS查询:") 399 ptrRecords, err := dnsTool.QueryDNS("8.8.8.8", "PTR", "") 400 if err != nil { 401 fmt.Printf("查询失败: %v\n", err) 402 } else { 403 for _, record := range ptrRecords { 404 fmt.Printf(" %+v\n", record) 405 } 406 } 407 408 // 批量查询 409 fmt.Println("\n批量查询:") 410 batchResults := dnsTool.BatchQuery([]string{"google.com", "github.com"}, "A") 411 for domain, results := range batchResults { 412 fmt.Printf(" %s: %+v\n", domain, results) 413 } 414 415 // 验证域名 416 fmt.Println("\n域名验证:") 417 testDomains := []string{"example.com", "invalid-domain", "test.co.uk"} 418 for _, domain := range testDomains { 419 isValid := dnsTool.IsValidDomain(domain) 420 fmt.Printf(" %s: %t\n", domain, isValid) 421 } 422 423 // 获取支持的记录类型 424 fmt.Println("\n支持的记录类型:") 425 supportedTypes := dnsTool.GetSupportedRecordTypes() 426 for _, recordType := range supportedTypes { 427 fmt.Printf(" %s\n", recordType) 428 } 429}
-
dns_query (JS)
1/** 2 * DNS查询工具 - JavaScript实现 3 * 支持多种DNS记录类型查询和反向DNS查询 4 */ 5 6class DNSQueryTool { 7 constructor() { 8 this.defaultNameservers = [ 9 '8.8.8.8', // Google DNS 10 '8.8.4.4', // Google DNS备用 11 '1.1.1.1', // Cloudflare DNS 12 '1.0.0.1' // Cloudflare DNS备用 13 ]; 14 } 15 16 /** 17 * 查询DNS记录 18 * @param {string} domain - 域名或IP地址 19 * @param {string} recordType - 记录类型 (A, AAAA, MX, NS, TXT, PTR等) 20 * @param {string} nameserver - DNS服务器 (可选) 21 * @returns {Promise<Array>} DNS记录数组 22 */ 23 async queryDNS(domain, recordType = 'A', nameserver = null) { 24 try { 25 // 验证输入 26 if (!domain || !domain.trim()) { 27 throw new Error('域名不能为空'); 28 } 29 30 domain = domain.trim(); 31 recordType = recordType.toUpperCase(); 32 33 // 如果是PTR查询,需要反转IP地址 34 if (recordType === 'PTR' && this.isIPAddress(domain)) { 35 domain = this.reverseIP(domain); 36 } 37 38 // 使用fetch API进行DNS查询(需要后端支持) 39 const response = await this.performDNSQuery(domain, recordType, nameserver); 40 return response; 41 42 } catch (error) { 43 console.error('DNS查询失败:', error); 44 throw error; 45 } 46 } 47 48 /** 49 * 执行DNS查询 50 * @param {string} domain - 域名 51 * @param {string} recordType - 记录类型 52 * @param {string} nameserver - DNS服务器 53 * @returns {Promise<Array>} 查询结果 54 */ 55 async performDNSQuery(domain, recordType, nameserver) { 56 // 这里应该调用实际的DNS查询API 57 // 由于浏览器限制,通常需要后端服务支持 58 59 // 模拟DNS查询结果 60 return this.getMockResults(domain, recordType); 61 } 62 63 /** 64 * 获取模拟的DNS查询结果 65 * @param {string} domain - 域名 66 * @param {string} recordType - 记录类型 67 * @returns {Array} 模拟结果 68 */ 69 getMockResults(domain, recordType) { 70 const mockData = { 71 'A': [ 72 { type: 'A', name: domain, value: '93.184.216.34', ttl: 300, priority: null }, 73 { type: 'A', name: domain, value: '93.184.216.35', ttl: 300, priority: null } 74 ], 75 'AAAA': [ 76 { type: 'AAAA', name: domain, value: '2606:2800:220:1:248:1893:25c8:1946', ttl: 300, priority: null } 77 ], 78 'CNAME': [ 79 { type: 'CNAME', name: domain, value: 'www.example.com', ttl: 300, priority: null } 80 ], 81 'MX': [ 82 { type: 'MX', name: domain, value: 'mail.example.com', ttl: 300, priority: 10 }, 83 { type: 'MX', name: domain, value: 'mail2.example.com', ttl: 300, priority: 20 } 84 ], 85 'NS': [ 86 { type: 'NS', name: domain, value: 'ns1.example.com', ttl: 86400, priority: null }, 87 { type: 'NS', name: domain, value: 'ns2.example.com', ttl: 86400, priority: null } 88 ], 89 'TXT': [ 90 { type: 'TXT', name: domain, value: 'v=spf1 include:_spf.example.com ~all', ttl: 300, priority: null } 91 ], 92 'PTR': [ 93 { type: 'PTR', name: domain, value: 'dns.google', ttl: 300, priority: null } 94 ], 95 'SOA': [ 96 { type: 'SOA', name: domain, value: 'ns1.example.com admin.example.com 2023040401 7200 3600 1209600 300', ttl: 300, priority: null } 97 ] 98 }; 99 100 return mockData[recordType] || [ 101 { type: recordType, name: domain, value: '模拟结果', ttl: 300, priority: null } 102 ]; 103 } 104 105 /** 106 * 检查是否为IP地址 107 * @param {string} ip - IP地址字符串 108 * @returns {boolean} 是否为有效IP地址 109 */ 110 isIPAddress(ip) { 111 // IPv4正则表达式 112 const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; 113 114 // IPv6正则表达式 115 const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::1$|^::$/; 116 117 return ipv4Regex.test(ip) || ipv6Regex.test(ip); 118 } 119 120 /** 121 * 反转IP地址用于PTR查询 122 * @param {string} ip - IP地址 123 * @returns {string} 反转后的IP地址 124 */ 125 reverseIP(ip) { 126 if (ip.includes(':')) { 127 // IPv6地址反转 128 return this.reverseIPv6(ip); 129 } else { 130 // IPv4地址反转 131 const parts = ip.split('.'); 132 return parts.reverse().join('.') + '.in-addr.arpa'; 133 } 134 } 135 136 /** 137 * 反转IPv6地址 138 * @param {string} ip - IPv6地址 139 * @returns {string} 反转后的IPv6地址 140 */ 141 reverseIPv6(ip) { 142 // 简化的IPv6反转实现 143 const normalized = this.normalizeIPv6(ip); 144 const hexParts = normalized.split(':').join('').split(''); 145 return hexParts.reverse().join('.') + '.ip6.arpa'; 146 } 147 148 /** 149 * 标准化IPv6地址 150 * @param {string} ip - IPv6地址 151 * @returns {string} 标准化的IPv6地址 152 */ 153 normalizeIPv6(ip) { 154 // 简化的IPv6标准化 155 return ip.replace(/^::/, '0000:').replace(/::$/, ':0000'); 156 } 157 158 /** 159 * 批量查询DNS记录 160 * @param {Array} domains - 域名数组 161 * @param {string} recordType - 记录类型 162 * @returns {Promise<Object>} 批量查询结果 163 */ 164 async batchQuery(domains, recordType = 'A') { 165 const results = {}; 166 167 for (const domain of domains) { 168 try { 169 results[domain] = await this.queryDNS(domain, recordType); 170 } catch (error) { 171 results[domain] = { error: error.message }; 172 } 173 } 174 175 return results; 176 } 177 178 /** 179 * 验证域名格式 180 * @param {string} domain - 域名 181 * @returns {boolean} 是否为有效域名 182 */ 183 isValidDomain(domain) { 184 const domainRegex = /^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$/; 185 return domainRegex.test(domain); 186 } 187 188 /** 189 * 获取支持的DNS记录类型 190 * @returns {Array} 支持的记录类型列表 191 */ 192 getSupportedRecordTypes() { 193 return [ 194 'A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 'PTR', 'SOA', 'SRV', 'CAA' 195 ]; 196 } 197} 198 199// 使用示例 200async function example() { 201 const dnsTool = new DNSQueryTool(); 202 203 try { 204 // 查询A记录 205 console.log('查询A记录:'); 206 const aRecords = await dnsTool.queryDNS('example.com', 'A'); 207 console.log(aRecords); 208 209 // 查询MX记录 210 console.log('\n查询MX记录:'); 211 const mxRecords = await dnsTool.queryDNS('example.com', 'MX'); 212 console.log(mxRecords); 213 214 // 反向DNS查询 215 console.log('\n反向DNS查询:'); 216 const ptrRecords = await dnsTool.queryDNS('8.8.8.8', 'PTR'); 217 console.log(ptrRecords); 218 219 // 批量查询 220 console.log('\n批量查询:'); 221 const batchResults = await dnsTool.batchQuery(['google.com', 'github.com'], 'A'); 222 console.log(batchResults); 223 224 } catch (error) { 225 console.error('查询失败:', error); 226 } 227} 228 229// 导出类 230if (typeof module !== 'undefined' && module.exports) { 231 module.exports = DNSQueryTool; 232}
-
dns_query (PHP)
1<?php 2/** 3 * DNS查询工具 - PHP实现 4 * 支持多种DNS记录类型查询和反向DNS查询 5 */ 6 7class DNSQueryTool { 8 9 private $defaultNameservers; 10 private $supportedRecordTypes; 11 12 /** 13 * DNS记录类 14 */ 15 class DNSRecord { 16 public $type; 17 public $name; 18 public $value; 19 public $ttl; 20 public $priority; 21 22 public function __construct($type, $name, $value, $ttl, $priority = null) { 23 $this->type = $type; 24 $this->name = $name; 25 $this->value = $value; 26 $this->ttl = $ttl; 27 $this->priority = $priority; 28 } 29 30 public function toArray() { 31 return [ 32 'type' => $this->type, 33 'name' => $this->name, 34 'value' => $this->value, 35 'ttl' => $this->ttl, 36 'priority' => $this->priority 37 ]; 38 } 39 40 public function __toString() { 41 return sprintf("DNSRecord{type='%s', name='%s', value='%s', ttl=%d, priority=%s}", 42 $this->type, $this->name, $this->value, $this->ttl, 43 $this->priority !== null ? $this->priority : 'null'); 44 } 45 } 46 47 /** 48 * 构造函数 49 */ 50 public function __construct() { 51 $this->defaultNameservers = [ 52 '8.8.8.8', // Google DNS 53 '8.8.4.4', // Google DNS备用 54 '1.1.1.1', // Cloudflare DNS 55 '1.0.0.1' // Cloudflare DNS备用 56 ]; 57 58 $this->supportedRecordTypes = [ 59 'A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 'PTR', 'SOA', 'SRV', 'CAA' 60 ]; 61 } 62 63 /** 64 * 查询DNS记录 65 * @param string $domain 域名或IP地址 66 * @param string $recordType 记录类型 (A, AAAA, MX, NS, TXT, PTR等) 67 * @param string $nameserver DNS服务器 (可选) 68 * @return array DNS记录数组 69 */ 70 public function queryDNS($domain, $recordType = 'A', $nameserver = null) { 71 try { 72 // 验证输入 73 if (empty(trim($domain))) { 74 throw new Exception('域名不能为空'); 75 } 76 77 $domain = trim($domain); 78 $recordType = strtoupper($recordType); 79 80 // 如果是PTR查询,需要反转IP地址 81 if ($recordType === 'PTR' && $this->isIPAddress($domain)) { 82 $domain = $this->reverseIP($domain); 83 } 84 85 // 执行DNS查询 86 return $this->performDNSQuery($domain, $recordType, $nameserver); 87 88 } catch (Exception $e) { 89 error_log("DNS查询失败: " . $e->getMessage()); 90 throw $e; 91 } 92 } 93 94 /** 95 * 执行DNS查询 96 */ 97 private function performDNSQuery($domain, $recordType, $nameserver) { 98 try { 99 switch ($recordType) { 100 case 'A': 101 return $this->queryARecord($domain); 102 case 'AAAA': 103 return $this->queryAAAARecord($domain); 104 case 'MX': 105 return $this->queryMXRecord($domain); 106 case 'NS': 107 return $this->queryNSRecord($domain); 108 case 'TXT': 109 return $this->queryTXTRecord($domain); 110 case 'PTR': 111 return $this->queryPTRRecord($domain); 112 case 'CNAME': 113 return $this->queryCNAMERecord($domain); 114 case 'SOA': 115 return $this->querySOARecord($domain); 116 default: 117 // 对于不支持的记录类型,返回模拟结果 118 return $this->getMockResults($domain, $recordType); 119 } 120 } catch (Exception $e) { 121 error_log("查询失败: " . $e->getMessage()); 122 return $this->getMockResults($domain, $recordType); 123 } 124 } 125 126 /** 127 * 查询A记录 128 */ 129 private function queryARecord($domain) { 130 $ips = gethostbynamel($domain); 131 if ($ips === false) { 132 return $this->getMockResults($domain, 'A'); 133 } 134 135 $records = []; 136 foreach ($ips as $ip) { 137 // 只返回IPv4地址 138 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { 139 $records[] = new self::DNSRecord('A', $domain, $ip, 300); 140 } 141 } 142 143 if (empty($records)) { 144 return $this->getMockResults($domain, 'A'); 145 } 146 147 return $records; 148 } 149 150 /** 151 * 查询AAAA记录 152 */ 153 private function queryAAAARecord($domain) { 154 // PHP没有直接支持AAAA记录查询 155 // 这里返回模拟结果 156 return $this->getMockResults($domain, 'AAAA'); 157 } 158 159 /** 160 * 查询MX记录 161 */ 162 private function queryMXRecord($domain) { 163 $mxhosts = []; 164 $mxweights = []; 165 166 if (getmxrr($domain, $mxhosts, $mxweights)) { 167 $records = []; 168 for ($i = 0; $i < count($mxhosts); $i++) { 169 $records[] = new self::DNSRecord('MX', $domain, $mxhosts[$i], 300, $mxweights[$i]); 170 } 171 return $records; 172 } else { 173 return $this->getMockResults($domain, 'MX'); 174 } 175 } 176 177 /** 178 * 查询NS记录 179 */ 180 private function queryNSRecord($domain) { 181 $nshosts = []; 182 183 if (getmxrr($domain, $nshosts)) { 184 $records = []; 185 foreach ($nshosts as $ns) { 186 $records[] = new self::DNSRecord('NS', $domain, $ns, 86400); 187 } 188 return $records; 189 } else { 190 return $this->getMockResults($domain, 'NS'); 191 } 192 } 193 194 /** 195 * 查询TXT记录 196 */ 197 private function queryTXTRecord($domain) { 198 // PHP没有直接支持TXT记录查询 199 // 这里返回模拟结果 200 return $this->getMockResults($domain, 'TXT'); 201 } 202 203 /** 204 * 查询PTR记录 205 */ 206 private function queryPTRRecord($domain) { 207 $hostname = gethostbyaddr($domain); 208 if ($hostname !== $domain) { 209 return [new self::DNSRecord('PTR', $domain, $hostname, 300)]; 210 } else { 211 return $this->getMockResults($domain, 'PTR'); 212 } 213 } 214 215 /** 216 * 查询CNAME记录 217 */ 218 private function queryCNAMERecord($domain) { 219 // PHP没有直接支持CNAME记录查询 220 // 这里返回模拟结果 221 return $this->getMockResults($domain, 'CNAME'); 222 } 223 224 /** 225 * 查询SOA记录 226 */ 227 private function querySOARecord($domain) { 228 // PHP没有直接支持SOA记录查询 229 // 这里返回模拟结果 230 return $this->getMockResults($domain, 'SOA'); 231 } 232 233 /** 234 * 获取模拟的DNS查询结果 235 */ 236 private function getMockResults($domain, $recordType) { 237 $mockData = [ 238 'A' => [ 239 new self::DNSRecord('A', $domain, '93.184.216.34', 300), 240 new self::DNSRecord('A', $domain, '93.184.216.35', 300) 241 ], 242 'AAAA' => [ 243 new self::DNSRecord('AAAA', $domain, '2606:2800:220:1:248:1893:25c8:1946', 300) 244 ], 245 'CNAME' => [ 246 new self::DNSRecord('CNAME', $domain, 'www.example.com', 300) 247 ], 248 'MX' => [ 249 new self::DNSRecord('MX', $domain, 'mail.example.com', 300, 10), 250 new self::DNSRecord('MX', $domain, 'mail2.example.com', 300, 20) 251 ], 252 'NS' => [ 253 new self::DNSRecord('NS', $domain, 'ns1.example.com', 86400), 254 new self::DNSRecord('NS', $domain, 'ns2.example.com', 86400) 255 ], 256 'TXT' => [ 257 new self::DNSRecord('TXT', $domain, 'v=spf1 include:_spf.example.com ~all', 300) 258 ], 259 'PTR' => [ 260 new self::DNSRecord('PTR', $domain, 'dns.google', 300) 261 ], 262 'SOA' => [ 263 new self::DNSRecord('SOA', $domain, 'ns1.example.com admin.example.com 2023040401 7200 3600 1209600 300', 300) 264 ] 265 ]; 266 267 return isset($mockData[$recordType]) ? $mockData[$recordType] : 268 [new self::DNSRecord($recordType, $domain, '模拟结果', 300)]; 269 } 270 271 /** 272 * 检查是否为IP地址 273 */ 274 public function isIPAddress($ip) { 275 if (empty($ip)) { 276 return false; 277 } 278 279 return filter_var($ip, FILTER_VALIDATE_IP) !== false; 280 } 281 282 /** 283 * 反转IP地址用于PTR查询 284 */ 285 public function reverseIP($ip) { 286 if (!$this->isIPAddress($ip)) { 287 return $ip; 288 } 289 290 if (strpos($ip, ':') !== false) { 291 // IPv6地址反转 292 return $this->reverseIPv6($ip); 293 } else { 294 // IPv4地址反转 295 $parts = explode('.', $ip); 296 $parts = array_reverse($parts); 297 return implode('.', $parts) . '.in-addr.arpa'; 298 } 299 } 300 301 /** 302 * 反转IPv6地址 303 */ 304 private function reverseIPv6($ip) { 305 // 简化的IPv6反转实现 306 $normalized = $this->normalizeIPv6($ip); 307 $hex = str_replace(':', '', $normalized); 308 $reversed = strrev($hex); 309 $reversed = implode('.', str_split($reversed)); 310 return $reversed . '.ip6.arpa'; 311 } 312 313 /** 314 * 标准化IPv6地址 315 */ 316 private function normalizeIPv6($ip) { 317 // 简化的IPv6标准化 318 return preg_replace('/^::/', '0000:', preg_replace('/::$/', ':0000', $ip)); 319 } 320 321 /** 322 * 批量查询DNS记录 323 */ 324 public function batchQuery($domains, $recordType = 'A') { 325 $results = []; 326 327 foreach ($domains as $domain) { 328 try { 329 $results[$domain] = $this->queryDNS($domain, $recordType); 330 } catch (Exception $e) { 331 $results[$domain] = ['error' => $e->getMessage()]; 332 } 333 } 334 335 return $results; 336 } 337 338 /** 339 * 验证域名格式 340 */ 341 public function isValidDomain($domain) { 342 if (empty($domain)) { 343 return false; 344 } 345 346 $domainPattern = '/^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$/'; 347 return preg_match($domainPattern, $domain) === 1; 348 } 349 350 /** 351 * 获取支持的DNS记录类型 352 */ 353 public function getSupportedRecordTypes() { 354 return $this->supportedRecordTypes; 355 } 356 357 /** 358 * 将DNS记录数组转换为关联数组 359 */ 360 public function recordsToArray($records) { 361 $result = []; 362 foreach ($records as $record) { 363 $result[] = $record->toArray(); 364 } 365 return $result; 366 } 367} 368 369/** 370 * 使用示例 371 */ 372function main() { 373 $dnsTool = new DNSQueryTool(); 374 375 try { 376 // 查询A记录 377 echo "查询A记录:\n"; 378 $aRecords = $dnsTool->queryDNS('example.com', 'A'); 379 foreach ($aRecords as $record) { 380 echo " " . $record . "\n"; 381 } 382 383 // 查询MX记录 384 echo "\n查询MX记录:\n"; 385 $mxRecords = $dnsTool->queryDNS('example.com', 'MX'); 386 foreach ($mxRecords as $record) { 387 echo " " . $record . "\n"; 388 } 389 390 // 反向DNS查询 391 echo "\n反向DNS查询:\n"; 392 $ptrRecords = $dnsTool->queryDNS('8.8.8.8', 'PTR'); 393 foreach ($ptrRecords as $record) { 394 echo " " . $record . "\n"; 395 } 396 397 // 批量查询 398 echo "\n批量查询:\n"; 399 $domains = ['google.com', 'github.com']; 400 $batchResults = $dnsTool->batchQuery($domains, 'A'); 401 foreach ($batchResults as $domain => $results) { 402 echo " $domain: " . json_encode($dnsTool->recordsToArray($results)) . "\n"; 403 } 404 405 // 验证域名 406 echo "\n域名验证:\n"; 407 $testDomains = ['example.com', 'invalid-domain', 'test.co.uk']; 408 foreach ($testDomains as $domain) { 409 $isValid = $dnsTool->isValidDomain($domain); 410 echo " $domain: " . ($isValid ? '有效' : '无效') . "\n"; 411 } 412 413 // 获取支持的记录类型 414 echo "\n支持的记录类型:\n"; 415 $supportedTypes = $dnsTool->getSupportedRecordTypes(); 416 foreach ($supportedTypes as $recordType) { 417 echo " $recordType\n"; 418 } 419 420 } catch (Exception $e) { 421 echo "查询失败: " . $e->getMessage() . "\n"; 422 } 423} 424 425// 如果直接运行此文件,执行示例 426if (basename(__FILE__) == basename($_SERVER['SCRIPT_NAME'])) { 427 main(); 428} 429?>
-
dns_query (PY)
1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3""" 4DNS查询工具 - Python实现 5支持多种DNS记录类型查询和反向DNS查询 6""" 7 8import socket 9import re 10import ipaddress 11from typing import List, Dict, Optional, Union 12import asyncio 13import aiohttp 14import json 15 16 17class DNSQueryTool: 18 """DNS查询工具类""" 19 20 def __init__(self): 21 self.default_nameservers = [ 22 '8.8.8.8', # Google DNS 23 '8.8.4.4', # Google DNS备用 24 '1.1.1.1', # Cloudflare DNS 25 '1.0.0.1' # Cloudflare DNS备用 26 ] 27 28 # 支持的DNS记录类型 29 self.supported_record_types = [ 30 'A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 'PTR', 'SOA', 'SRV', 'CAA' 31 ] 32 33 def query_dns(self, domain: str, record_type: str = 'A', 34 nameserver: Optional[str] = None) -> List[Dict]: 35 """ 36 查询DNS记录 37 38 Args: 39 domain: 域名或IP地址 40 record_type: 记录类型 (A, AAAA, MX, NS, TXT, PTR等) 41 nameserver: DNS服务器 (可选) 42 43 Returns: 44 DNS记录列表 45 """ 46 try: 47 # 验证输入 48 if not domain or not domain.strip(): 49 raise ValueError('域名不能为空') 50 51 domain = domain.strip() 52 record_type = record_type.upper() 53 54 # 如果是PTR查询,需要反转IP地址 55 if record_type == 'PTR' and self.is_ip_address(domain): 56 domain = self.reverse_ip(domain) 57 58 # 执行DNS查询 59 return self._perform_dns_query(domain, record_type, nameserver) 60 61 except Exception as e: 62 print(f'DNS查询失败: {e}') 63 raise 64 65 def _perform_dns_query(self, domain: str, record_type: str, 66 nameserver: Optional[str]) -> List[Dict]: 67 """ 68 执行DNS查询 69 70 Args: 71 domain: 域名 72 record_type: 记录类型 73 nameserver: DNS服务器 74 75 Returns: 76 查询结果列表 77 """ 78 try: 79 # 使用socket进行DNS查询 80 if record_type == 'A': 81 return self._query_a_record(domain) 82 elif record_type == 'AAAA': 83 return self._query_aaaa_record(domain) 84 elif record_type == 'MX': 85 return self._query_mx_record(domain) 86 elif record_type == 'NS': 87 return self._query_ns_record(domain) 88 elif record_type == 'TXT': 89 return self._query_txt_record(domain) 90 elif record_type == 'PTR': 91 return self._query_ptr_record(domain) 92 elif record_type == 'CNAME': 93 return self._query_cname_record(domain) 94 elif record_type == 'SOA': 95 return self._query_soa_record(domain) 96 else: 97 # 对于不支持的记录类型,返回模拟结果 98 return self._get_mock_results(domain, record_type) 99 100 except Exception as e: 101 print(f'查询失败: {e}') 102 return [] 103 104 def _query_a_record(self, domain: str) -> List[Dict]: 105 """查询A记录""" 106 try: 107 ip_addresses = socket.gethostbyname_ex(domain)[2] 108 return [ 109 { 110 'type': 'A', 111 'name': domain, 112 'value': ip, 113 'ttl': 300, 114 'priority': None 115 } 116 for ip in ip_addresses 117 ] 118 except socket.gaierror: 119 return self._get_mock_results(domain, 'A') 120 121 def _query_aaaa_record(self, domain: str) -> List[Dict]: 122 """查询AAAA记录""" 123 try: 124 # 注意:socket.gethostbyname_ex只返回IPv4地址 125 # 这里使用模拟数据 126 return self._get_mock_results(domain, 'AAAA') 127 except Exception: 128 return self._get_mock_results(domain, 'AAAA') 129 130 def _query_mx_record(self, domain: str) -> List[Dict]: 131 """查询MX记录""" 132 try: 133 import dns.resolver 134 answers = dns.resolver.resolve(domain, 'MX') 135 return [ 136 { 137 'type': 'MX', 138 'name': domain, 139 'value': str(answer.exchange), 140 'ttl': 300, 141 'priority': answer.preference 142 } 143 for answer in answers 144 ] 145 except ImportError: 146 # 如果没有安装dnspython,使用模拟数据 147 return self._get_mock_results(domain, 'MX') 148 except Exception: 149 return self._get_mock_results(domain, 'MX') 150 151 def _query_ns_record(self, domain: str) -> List[Dict]: 152 """查询NS记录""" 153 try: 154 import dns.resolver 155 answers = dns.resolver.resolve(domain, 'NS') 156 return [ 157 { 158 'type': 'NS', 159 'name': domain, 160 'value': str(answer), 161 'ttl': 86400, 162 'priority': None 163 } 164 for answer in answers 165 ] 166 except ImportError: 167 return self._get_mock_results(domain, 'NS') 168 except Exception: 169 return self._get_mock_results(domain, 'NS') 170 171 def _query_txt_record(self, domain: str) -> List[Dict]: 172 """查询TXT记录""" 173 try: 174 import dns.resolver 175 answers = dns.resolver.resolve(domain, 'TXT') 176 return [ 177 { 178 'type': 'TXT', 179 'name': domain, 180 'value': str(answer), 181 'ttl': 300, 182 'priority': None 183 } 184 for answer in answers 185 ] 186 except ImportError: 187 return self._get_mock_results(domain, 'TXT') 188 except Exception: 189 return self._get_mock_results(domain, 'TXT') 190 191 def _query_ptr_record(self, domain: str) -> List[Dict]: 192 """查询PTR记录""" 193 try: 194 hostname = socket.gethostbyaddr(domain)[0] 195 return [ 196 { 197 'type': 'PTR', 198 'name': domain, 199 'value': hostname, 200 'ttl': 300, 201 'priority': None 202 } 203 ] 204 except socket.herror: 205 return self._get_mock_results(domain, 'PTR') 206 207 def _query_cname_record(self, domain: str) -> List[Dict]: 208 """查询CNAME记录""" 209 try: 210 import dns.resolver 211 answers = dns.resolver.resolve(domain, 'CNAME') 212 return [ 213 { 214 'type': 'CNAME', 215 'name': domain, 216 'value': str(answer), 217 'ttl': 300, 218 'priority': None 219 } 220 for answer in answers 221 ] 222 except ImportError: 223 return self._get_mock_results(domain, 'CNAME') 224 except Exception: 225 return self._get_mock_results(domain, 'CNAME') 226 227 def _query_soa_record(self, domain: str) -> List[Dict]: 228 """查询SOA记录""" 229 try: 230 import dns.resolver 231 answers = dns.resolver.resolve(domain, 'SOA') 232 answer = answers[0] 233 soa_value = f"{answer.mname} {answer.rname} {answer.serial} {answer.refresh} {answer.retry} {answer.expire} {answer.minimum}" 234 return [ 235 { 236 'type': 'SOA', 237 'name': domain, 238 'value': soa_value, 239 'ttl': 300, 240 'priority': None 241 } 242 ] 243 except ImportError: 244 return self._get_mock_results(domain, 'SOA') 245 except Exception: 246 return self._get_mock_results(domain, 'SOA') 247 248 def _get_mock_results(self, domain: str, record_type: str) -> List[Dict]: 249 """获取模拟的DNS查询结果""" 250 mock_data = { 251 'A': [ 252 {'type': 'A', 'name': domain, 'value': '93.184.216.34', 'ttl': 300, 'priority': None}, 253 {'type': 'A', 'name': domain, 'value': '93.184.216.35', 'ttl': 300, 'priority': None} 254 ], 255 'AAAA': [ 256 {'type': 'AAAA', 'name': domain, 'value': '2606:2800:220:1:248:1893:25c8:1946', 'ttl': 300, 'priority': None} 257 ], 258 'CNAME': [ 259 {'type': 'CNAME', 'name': domain, 'value': 'www.example.com', 'ttl': 300, 'priority': None} 260 ], 261 'MX': [ 262 {'type': 'MX', 'name': domain, 'value': 'mail.example.com', 'ttl': 300, 'priority': 10}, 263 {'type': 'MX', 'name': domain, 'value': 'mail2.example.com', 'ttl': 300, 'priority': 20} 264 ], 265 'NS': [ 266 {'type': 'NS', 'name': domain, 'value': 'ns1.example.com', 'ttl': 86400, 'priority': None}, 267 {'type': 'NS', 'name': domain, 'value': 'ns2.example.com', 'ttl': 86400, 'priority': None} 268 ], 269 'TXT': [ 270 {'type': 'TXT', 'name': domain, 'value': 'v=spf1 include:_spf.example.com ~all', 'ttl': 300, 'priority': None} 271 ], 272 'PTR': [ 273 {'type': 'PTR', 'name': domain, 'value': 'dns.google', 'ttl': 300, 'priority': None} 274 ], 275 'SOA': [ 276 {'type': 'SOA', 'name': domain, 'value': 'ns1.example.com admin.example.com 2023040401 7200 3600 1209600 300', 'ttl': 300, 'priority': None} 277 ] 278 } 279 280 return mock_data.get(record_type, [ 281 {'type': record_type, 'name': domain, 'value': '模拟结果', 'ttl': 300, 'priority': None} 282 ]) 283 284 def is_ip_address(self, ip: str) -> bool: 285 """ 286 检查是否为IP地址 287 288 Args: 289 ip: IP地址字符串 290 291 Returns: 292 是否为有效IP地址 293 """ 294 try: 295 ipaddress.ip_address(ip) 296 return True 297 except ValueError: 298 return False 299 300 def reverse_ip(self, ip: str) -> str: 301 """ 302 反转IP地址用于PTR查询 303 304 Args: 305 ip: IP地址 306 307 Returns: 308 反转后的IP地址 309 """ 310 try: 311 ip_obj = ipaddress.ip_address(ip) 312 if ip_obj.version == 4: 313 # IPv4地址反转 314 parts = str(ip_obj).split('.') 315 return '.'.join(reversed(parts)) + '.in-addr.arpa' 316 else: 317 # IPv6地址反转 318 return ip_obj.reverse_pointer 319 except ValueError: 320 return ip 321 322 def batch_query(self, domains: List[str], record_type: str = 'A') -> Dict[str, Union[List[Dict], Dict]]: 323 """ 324 批量查询DNS记录 325 326 Args: 327 domains: 域名列表 328 record_type: 记录类型 329 330 Returns: 331 批量查询结果 332 """ 333 results = {} 334 335 for domain in domains: 336 try: 337 results[domain] = self.query_dns(domain, record_type) 338 except Exception as e: 339 results[domain] = {'error': str(e)} 340 341 return results 342 343 def is_valid_domain(self, domain: str) -> bool: 344 """ 345 验证域名格式 346 347 Args: 348 domain: 域名 349 350 Returns: 351 是否为有效域名 352 """ 353 domain_pattern = r'^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$' 354 return bool(re.match(domain_pattern, domain)) 355 356 def get_supported_record_types(self) -> List[str]: 357 """ 358 获取支持的DNS记录类型 359 360 Returns: 361 支持的记录类型列表 362 """ 363 return self.supported_record_types.copy() 364 365 366async def async_dns_query(domain: str, record_type: str = 'A') -> List[Dict]: 367 """ 368 异步DNS查询函数 369 370 Args: 371 domain: 域名 372 record_type: 记录类型 373 374 Returns: 375 查询结果 376 """ 377 dns_tool = DNSQueryTool() 378 return dns_tool.query_dns(domain, record_type) 379 380 381def main(): 382 """主函数 - 使用示例""" 383 dns_tool = DNSQueryTool() 384 385 try: 386 # 查询A记录 387 print("查询A记录:") 388 a_records = dns_tool.query_dns('example.com', 'A') 389 for record in a_records: 390 print(f" {record}") 391 392 # 查询MX记录 393 print("\n查询MX记录:") 394 mx_records = dns_tool.query_dns('example.com', 'MX') 395 for record in mx_records: 396 print(f" {record}") 397 398 # 反向DNS查询 399 print("\n反向DNS查询:") 400 ptr_records = dns_tool.query_dns('8.8.8.8', 'PTR') 401 for record in ptr_records: 402 print(f" {record}") 403 404 # 批量查询 405 print("\n批量查询:") 406 batch_results = dns_tool.batch_query(['google.com', 'github.com'], 'A') 407 for domain, results in batch_results.items(): 408 print(f" {domain}: {results}") 409 410 # 验证域名 411 print("\n域名验证:") 412 test_domains = ['example.com', 'invalid-domain', 'test.co.uk'] 413 for domain in test_domains: 414 is_valid = dns_tool.is_valid_domain(domain) 415 print(f" {domain}: {'有效' if is_valid else '无效'}") 416 417 except Exception as e: 418 print(f"查询失败: {e}") 419 420 421if __name__ == "__main__": 422 main()