脚本中DNS解析检测如何自动化

wen 实用脚本 3

本文目录导读:

脚本中DNS解析检测如何自动化

  1. 核心检测逻辑
  2. 方案一:Shell 脚本(Linux/macOS 环境)
  3. 方案二:Python 脚本(跨平台,更灵活)
  4. 方案三:PowerShell(Windows 环境)
  5. 方案四:使用现成的监控工具(不写脚本)
  6. 高级自动化场景与技巧

在脚本中实现DNS解析检测的自动化,通常是为了监控域名解析的正确性、响应时间、或检测是否存在DNS劫持、污染等问题。

根据你的使用场景(Linux Shell、Python、Windows Batch/PowerShell),以下是几种常见的自动化实现方案:

核心检测逻辑

无论使用什么语言,自动化DNS检测通常包括:

  1. 解析域名:将域名转换为IP地址。
  2. 比对结果:与预期的IP地址或正则表达式进行比对。
  3. 记录结果:输出成功/失败,记录响应时间。
  4. 触发告警:当检测到异常时,执行后续操作(如发邮件、重启服务、切换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 脚本。

使用现成的监控工具(不写脚本)

如果你不想维护脚,可以考虑将这些逻辑集成到成熟的监控系统中:

  1. Prometheus + Blackbox Exporter

    • 支持 dns_probe 模块,可以配置预期响应。
    • 可以自动生成时间序列数据,便于 Grafana 可视化。
    • 支持告警规则 (Alertmanager)。
  2. Zabbix

    • 自带 dns 类型的监控项(net.dns)。
    • 可以设置触发器,当解析失败或IP不符时报警。
  3. Nagios/Icinga

    • 使用 check_dns 插件。

高级自动化场景与技巧

  1. 检测 DNS 劫持/污染

    • 对比法:同时向多个公共DNS(如 8.8.8114.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!")
  2. DNSSEC 验证

    • 使用 dig example.com +dnssec 检查 ad (authentic data) 标志位。
    • 在 Python 中,使用 dns.resolverdnssec 参数。
  3. 大规模域名 / CNAME 链检测

    • 递归解析 CNAME,直到获得 A/AAAA 记录。
    • 检查整个解析链是否指向正确的 CDN 或云服务商。
  4. 结果存储与可视化

    • 将每次检测的 域名、IP、耗时、状态、时间戳 写入数据库 (InfluxDB, MySQL)。
    • 搭建一个简易的 Flask 页面展示历史趋势。
  • 简单快速:用 Shell + dig
  • 灵活可扩展:用 Python + dnspython
  • Windows 集成:用 PowerShell。
  • 生产环境监控:用 Prometheus + Blackbox Exporter 或 Zabbix。

始终建议进行“预期值比对”,而不仅仅是“是否能解析”,这样可以发现重定向、劫持或配置错误。

抱歉,评论功能暂时关闭!