本文目录导读:

- 核心检测逻辑
- 方案一:Shell 脚本(Linux/macOS 环境)
- 方案二:Python 脚本(跨平台,更灵活)
- 方案三:PowerShell(Windows 环境)
- 方案四:使用现成的监控工具(不写脚本)
- 高级自动化场景与技巧
在脚本中实现DNS解析检测的自动化,通常是为了监控域名解析的正确性、响应时间、或检测是否存在DNS劫持、污染等问题。
根据你的使用场景(Linux Shell、Python、Windows Batch/PowerShell),以下是几种常见的自动化实现方案:
核心检测逻辑
无论使用什么语言,自动化DNS检测通常包括:
- 解析域名:将域名转换为IP地址。
- 比对结果:与预期的IP地址或正则表达式进行比对。
- 记录结果:输出成功/失败,记录响应时间。
- 触发告警:当检测到异常时,执行后续操作(如发邮件、重启服务、切换DNS)。
Shell 脚本(Linux/macOS 环境)
适合服务器本地监控、Cron定时任务。
场景:检测域名是否解析到正确的IP地址
#!/bin/bash
# 配置区域
DOMAIN="example.com"
EXPECTED_IP="1.2.3.4"
DNS_SERVER="8.8.8.8" # 可选,不指定用系统默认
LOG_FILE="/var/log/dns_check.log"
# 1. 使用 dig 命令解析(推荐,信息更详细)
RESOLVED_IP=$(dig +short "$DOMAIN" @$DNS_SERVER | tail -n1)
# 或者使用 host 命令
# RESOLVED_IP=$(host "$DOMAIN" $DNS_SERVER | grep "has address" | awk '{print $4}')
# 2. 检测是否为空(解析失败)
if [ -z "$RESOLVED_IP" ]; then
echo "$(date) - ERROR: DNS resolution failed for $DOMAIN" >> $LOG_FILE
# 这里可以触发告警, curl -X POST https://alert.manager ...
exit 1
fi
# 3. 比对IP
if [ "$RESOLVED_IP" == "$EXPECTED_IP" ]; then
echo "$(date) - OK: $DOMAIN -> $RESOLVED_IP" >> $LOG_FILE
else
echo "$(date) - MISMATCH: Expected $EXPECTED_IP, but got $RESOLVED_IP for $DOMAIN" >> $LOG_FILE
# 触发告警
fi
# 4. (可选) 检测解析耗时
# RESOLVE_TIME=$(dig +time=5 +tries=1 "$DOMAIN" @$DNS_SERVER | grep "Query time:" | awk '{print $4}')
# if [ "$RESOLVE_TIME" -gt 500 ]; then
# echo "$(date) - SLOW: Resolution took ${RESOLVE_TIME}ms for $DOMAIN" >> $LOG_FILE
# fi
自动化执行:
# 添加到 crontab,每5分钟执行一次 */5 * * * * /path/to/your_dns_check_script.sh
Python 脚本(跨平台,更灵活)
Python拥有强大的库,适合复杂逻辑、多域名批量检测、结果分析。
场景:批量检测多个域名,分析响应时间
#!/usr/bin/env python3
import dns.resolver
import time
import json
import logging
# 配置区域
DOMAINS = ["google.com", "github.com", "your-own-app.com"]
EXPECTED_IPS = {
"google.com": ["142.250.80.142", "142.250.80.132"], # 允许存在多个IP
"github.com": ["140.82.121.3"],
}
DNS_SERVERS = ["8.8.8.8", "1.1.1.1"]
TIMEOUT = 2 # 秒
logging.basicConfig(filename='dns_check.log', level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s')
def check_dns(domain, expected_ips, dns_servers):
resolver = dns.resolver.Resolver()
resolver.nameservers = dns_servers
resolver.timeout = TIMEOUT
resolver.lifetime = TIMEOUT
try:
start = time.time()
answers = resolver.resolve(domain, 'A')
elapsed = (time.time() - start) * 1000 # ms
resolved_ips = [str(answer) for answer in answers]
logging.info(f"Check {domain}: Resolved to {resolved_ips} in {elapsed:.2f}ms")
# 比对
if expected_ips:
# 检查解析出的IP是否在预期IP列表内
match = any(ip in expected_ips for ip in resolved_ips)
if match:
logging.info(f"Result: MATCH for {domain}")
return True
else:
logging.warning(f"Result: MISMATCH for {domain}. Expected {expected_ips}, Got {resolved_ips}")
return False
else:
# 未配置预期IP,仅检查是否能解析成功
logging.info(f"Result: RESOLVED for {domain} (no expected IP configured)")
return True
except dns.resolver.NoAnswer:
logging.error(f"Result: FAIL - No answer for {domain}")
return False
except dns.resolver.NXDOMAIN:
logging.error(f"Result: FAIL - Domain {domain} does not exist")
return False
except dns.exception.Timeout:
logging.error(f"Result: FAIL - Timeout resolving {domain}")
return False
except Exception as e:
logging.error(f"Result: FAIL - Exception: {e}")
return False
# 主循环
if __name__ == "__main__":
results = {}
for domain in DOMAINS:
result = check_dns(domain, EXPECTED_IPS.get(domain), DNS_SERVERS)
results[domain] = result
# 汇总报告
failures = [k for k, v in results.items() if not v]
if failures:
logging.error(f"Summary: Failed domains: {failures}")
# 此处可调用 webhook 发送告警
# import requests
# requests.post("https://hooks.slack.com/...", json={"text": f"DNS Check Failed: {failures}"})
else:
logging.info("Summary: All checks passed.")
安装依赖:
pip install dnspython
自动化执行:
# 使用 systemd timer 或 crontab 定时执行 python 脚本 # * * * * * /usr/bin/python3 /path/to/dns_check.py
PowerShell(Windows 环境)
场景:单域名检测,输出到 Windows 事件日志
# 配置
$Domain = "example.com"
$ExpectedIP = "1.2.3.4"
$DnsServer = "8.8.8.8"
# 1. 解析 DNS
$Result = Resolve-DnsName -Name $Domain -Server $DnsServer -Type A -ErrorAction SilentlyContinue
if ($Result -eq $null) {
Write-EventLog -LogName Application -Source "DNS Monitor" -EventId 1001 -EntryType Error -Message "DNS resolution failed for $Domain"
Exit 1
}
$ResolvedIP = $Result.IPAddress
# 2. 比对
if ($ResolvedIP -eq $ExpectedIP) {
Write-EventLog -LogName Application -Source "DNS Monitor" -EventId 1000 -EntryType Information -Message "DNS OK: $Domain -> $ResolvedIP"
} else {
Write-EventLog -LogName Application -Source "DNS Monitor" -EventId 1002 -EntryType Error -Message "DNS Mismatch for $Domain. Expected $ExpectedIP, Got $ResolvedIP"
}
自动化执行:
- 使用 Windows Task Scheduler 定时执行 PS1 脚本。
使用现成的监控工具(不写脚本)
如果你不想维护脚,可以考虑将这些逻辑集成到成熟的监控系统中:
-
Prometheus + Blackbox Exporter:
- 支持
dns_probe模块,可以配置预期响应。 - 可以自动生成时间序列数据,便于 Grafana 可视化。
- 支持告警规则 (Alertmanager)。
- 支持
-
Zabbix:
- 自带
dns类型的监控项(net.dns)。 - 可以设置触发器,当解析失败或IP不符时报警。
- 自带
-
Nagios/Icinga:
- 使用
check_dns插件。
- 使用
高级自动化场景与技巧
-
检测 DNS 劫持/污染:
- 对比法:同时向多个公共DNS(如
8.8.8、114.114.114、本地DNS)发起查询。 - 如果本地DNS结果与公共DNS结果不一致,且本地返回的IP是广告页面或非预期IP,则说明可能被劫持。
- 脚本逻辑:分别解析,
set运算对比。
# Python 示例 local_result = set(["1.1.1.1"]) public_result = set(["2.2.2.2", "3.3.3.3"]) if local_result != public_result: print("Suspicious: Possible DNS Hijacking detected!") - 对比法:同时向多个公共DNS(如
-
DNSSEC 验证:
- 使用
dig example.com +dnssec检查ad(authentic data) 标志位。 - 在 Python 中,使用
dns.resolver的dnssec参数。
- 使用
-
大规模域名 / CNAME 链检测:
- 递归解析 CNAME,直到获得 A/AAAA 记录。
- 检查整个解析链是否指向正确的 CDN 或云服务商。
-
结果存储与可视化:
- 将每次检测的
域名、IP、耗时、状态、时间戳写入数据库 (InfluxDB, MySQL)。 - 搭建一个简易的 Flask 页面展示历史趋势。
- 将每次检测的
- 简单快速:用 Shell +
dig。 - 灵活可扩展:用 Python +
dnspython。 - Windows 集成:用 PowerShell。
- 生产环境监控:用 Prometheus + Blackbox Exporter 或 Zabbix。
始终建议进行“预期值比对”,而不仅仅是“是否能解析”,这样可以发现重定向、劫持或配置错误。