☰
DNS解析监测与hosts映射:域名劫持排查实践
2026/10/23 6:05:29 网站建设 项目流程

简介:面向网络管理员、运维人员与安全测试者的域名劫持测试工具包,主要用于模拟和验证DNS解析重定向,可服务于内部网络流量控制、故障排查、网站服务迁移以及DNS配置正确性检查等场景。工具围绕自定义DNS解析展开,支持为特定域名指定目标IP,并提供重定向活动监控与日志记录,便于后续分析与审计;同时可限定用户或网络段实施劫持,并按需要选择临时或长期重定向,以降低对正常服务的影响。压缩包为rar格式,体积约227KB,文件总数显示为0,类型明细暂无数据。已有2245人学习下载,反映出DNS安全测试与网络管理方向对该主题的持续关注。读者可从中了解域名劫持的实现思路、测试边界与恢复方法,掌握重定向配置、日志核查和安全控制等要点,并建立合法授权、测试后及时恢复DNS配置的操作意识。

1. 域名劫持到底是什么:从一次解析跑偏说起

线上服务没动过配置,值班群突然有人说打不开,本机curl却是通的,换个网络又好了——这种“一半人正常一半人异常”的问题,十有八九卡在解析层。域名劫持工具这个叫法容易让人联想到攻击,实际落到运维和开发手里,它做的事是把“域名→IP”这条链路的每一跳展开来看:浏览器缓存、系统缓存、hosts、递归服务器、权威服务器,到底是哪一环返回了不该返回的地址,又是从什么时候开始的。它适合做域名资产维护、上线前解析校验、CDN 切换验证和故障定位的人,也适合自己搭站、天天跟 DNS 记录打交道的人。这里只谈解析的可控、可验证和可回滚,涉及对他人域名做未授权改写的部分不在范围内,也不建议碰。

2. DNS 劫持的四类典型路径:先认清对手再谈工具

装工具之前得先明白一件事:所谓“域名被劫持”,从来不是单一动作,而是链路上某一环的结果被人换掉了。不同环节被换,排查手法、影响范围、恢复速度完全不同。我见过最常见的误区是,出问题就先去改 hosts 或者换 DNS,结果真正的改动在权威侧,折腾半天没碰到根上。

这一章把链路拆开,给出每一环的识别特征和验证命令,后面几章的监测脚本、映射工具都建立在这套基础上。

2.1 一条解析请求到底经过哪几个环节

从一个域名在地址栏敲下回车,到真正发出 TCP 连接,中间至少经过六层:应用或浏览器自身的 DNS 缓存、操作系统的 DNS 缓存、hosts 文件、本机配置的递归服务器(运营商、公共 DNS 或内网 DNS)、根与顶级域的委派、最后是域名自己的权威服务器。每一层都可能返回缓存结果,也每一层都可能被人为改写。

我一般按“影响范围”倒推:只有一个浏览器错,看应用缓存;只有一台机器错,看系统缓存和 hosts;一个办公网或一个运营商网段错,看递归服务器;全网错且各地一致,直奔权威服务器。这个倒推顺序能把定位时间从小时级压到分钟级。

环节维护方被改写后的典型症状快速验证方式
应用/浏览器缓存客户端单个浏览器错,换无痕窗口正常换浏览器、开无痕
系统 DNS 缓存客户端全机错,清缓存或重启解析服务即恢复清缓存前后对比
hosts 文件客户端仅本机错,同事同网络正常直接看文件内容
递归服务器运营商/内网一个网段错,指定其他@server正常多服务器对比查询
权威服务器域名持有方全网错,且各地结果一致直接查权威
证书层站点方解析对但证书域名不匹配openssl s_client校验

表格里最后一行容易被忽略:解析结果是正确的 IP,但 TLS 握手报证书不匹配,这种情况多半是流量在中间被转发到了另一台主机,属于比改记录更隐蔽的一类。遇到“能连上但证书报警”,别急着怀疑证书过期,先比对一下响应 IP 和权威记录是否一致。

2.2 hosts 改写、缓存投毒与权威记录被改:症状不一样

hosts 改写是最容易识别的:改动只影响本机,同网络的其他机器完全正常,文件里往往能直接看到一条不该存在的映射。它的特点是“精确打击单机”,常见于本地开发调试、也常见于某些软件安装时顺手写入。

缓存投毒影响的是一个递归服务器背后的所有用户,症状是同一运营商、同一内网段的用户集体出错,而指定其他递归服务器查询立刻恢复正常。这类问题的难点在于它会随 TTL 过期自愈,等你赶到现场可能已经好了,所以必须靠留档而不是靠现场观察。

权威记录被改是影响最大的一类:所有递归服务器最终都要回源,回源拿到什么就缓存什么,所以表现为全网一致地错。判定方法很直接——绕开所有递归,直接向该域名的权威服务器发起查询,看记录是否已经变了。

还有一种不涉及记录改动的做法:CNAME 指向的目标域名被人接管,或者对方把一条 CNAME 记录改到了自己的地址上。这种情况下主域名的 A 记录看起来完全正常,问题藏在 CNAME 链的下游。

判定顺序我习惯这么走:

  1. 直接查权威服务器,确认源记录是否被改;
  2. 用两个以上不同网段的递归服务器查询,确认影响范围;
  3. 在本机清缓存前后各查一次,排除本地缓存;
  4. 检查 hosts 和系统代理配置,排除本机改写;
  5. 比对响应 IP 的归属和证书,排除中间转发。

2.3 用 dig 建立解析基线:命令和参数逐条讲

定位任何解析问题,第一步都是建立“正常长什么样”的基线。没有基线的监测等于没有监测,因为你不知道拿到的结果该和谁比。下面这几条命令我基本是条件反射地敲。

# 1. 直接问权威服务器,绕开所有递归缓存 # - 先用 NS 查出权威服务器名字,再指定它查询 A 记录 dig +short NS example.test dig @ns1.example.test example.test A +norecurse # 2. 从两个不同的递归服务器查询,对比结果与 TTL dig @203.0.113.53 example.test A +noall +answer dig @203.0.113.54 example.test A +noall +answer # 3. 跟踪完整解析路径,看委派在哪一层发生变化 dig +trace example.test A # 4. 查询 DNSSEC 签名状态,AD 标志位表示验证通过 dig example.test A +dnssec +multiline # 5. 全类型快照,用于后续比对 dig example.test ANY +noall +answer

参数逐个说清楚:+norecurse表示不让对方代为递归,只返回它自己知道的答案,查权威时必须加,否则拿到的是别人的缓存;+noall +answer只输出答案段,适合脚本解析;+trace会从根开始逐级查询,输出很长但能一眼看出委派在哪一级断了或者指错了;+dnssec会带上RRSIG记录和AD标志,AD为真说明沿途的递归服务器完成了签名验证。

@后面跟的地址建议不要只用一个。我一般准备三个:一个内网递归、一个公共递归、一个直连权威。三者结果一致,基本可以排除解析层;三者不一致,差异本身就是线索。

提示:代码里的203.0.113.x是文档保留地址,实际使用时换成你手上的递归服务器 IP;example.test同理,换成你自己的域名。

2.4 为什么监测脚本比“一键改写”更值得装

一键改写的工具用起来爽,但它只给你一个结果,不给你过程。记录被改之后,你真正需要回答的是三个问题:改了多久、影响了哪些网段、TTL 到期后会不会自动恢复。这三个问题都得靠历史数据回答,靠现场看一眼是答不出来的。

监测类工具的价值就在这里:它按固定频率把多个递归服务器、多个记录类型的应答原文和时间戳存下来,形成一条可回溯的时间线。事故复盘时把时间线拉出来,什么时候开始漂、漂到了哪个 IP、哪个网段先漂,一目了然。

选型上我会看三点:能不能指定多个递归服务器而不是只用自己的系统配置;能不能保存应答原文而不是只存解析后的 IP;能不能区分“记录变了”和“TTL 到期后正常刷新”。第三点尤其关键,很多误报都是把正常的 CDN 调度当成了异常。

3. 搭一套域名解析监测:从基线采样到告警脚本

工具装好只是开始,能不能稳定产出可比对的数据才是分水岭。这一章给一套最小可用的监测方案:一个采样脚本、一套漂移判定规则、一个定时任务。整套东西加起来不到两百行,但能覆盖绝大多数解析异常场景。

3.1 采样脚本:多节点、多记录类型、保留应答原文

采样脚本的核心要求是“可重复”和“可回溯”。同一批域名、同一批服务器、同一批记录类型,每次都按相同顺序查一遍,结果写进带时间戳的文件里。这样两次采样之间的差异才有意义。

import json import time from datetime import datetime, timezone import dns.resolver import dns.exception # 被测域名清单,按业务重要性排序 TARGETS = [ {"domain": "example.test", "types": ["A", "AAAA", "CNAME", "NS"]}, {"domain": "api.example.test", "types": ["A", "CNAME"]}, ] # 多个递归服务器,至少包含一个内网和一个外部 RESOLVERS = ["203.0.113.53", "203.0.113.54"] # 单次查询超时,太短会误判为无应答,太长会拖慢整轮采样 TIMEOUT = 3.0 def query_one(resolver_ip, domain, rdtype): """对单个服务器发一次查询,返回结构化结果,异常也记录不抛出""" resolver = dns.resolver.Resolver(configure=False) resolver.nameservers = [resolver_ip] resolver.timeout = TIMEOUT resolver.lifetime = TIMEOUT record = { "ts": datetime.now(timezone.utc).isoformat(), "resolver": resolver_ip, "domain": domain, "type": rdtype, } try: answer = resolver.resolve(domain, rdtype, raise_on_no_answer=False) # 保留每条记录的文本形式和 TTL,TTL 是判断缓存层行为的关键 record["answers"] = [ {"data": r.to_text(), "ttl": answer.rrset.ttl} for r in answer.rrset or [] ] record["status"] = "ok" except dns.resolver.NXDOMAIN: record["status"] = "nxdomain" except dns.resolver.NoNameservers: record["status"] = "no_nameservers" except dns.exception.Timeout: record["status"] = "timeout" except Exception as exc: record["status"] = "error" record["error"] = str(exc) return record def main(): out_path = f"dns_sample_{int(time.time())}.jsonl" with open(out_path, "w", encoding="utf-8") as fh: for target in TARGETS: for resolver_ip in RESOLVERS: for rdtype in target["types"]: rec = query_one(resolver_ip, target["domain"], rdtype) fh.write(json.dumps(rec, ensure_ascii=False) + "\n") print(f"written: {out_path}") if __name__ == "__main__": main()

逻辑说明:Resolver(configure=False)是关键,它屏蔽系统/etc/resolv.conf的干扰,保证查询只发往指定服务器。raise_on_no_answer=False让“域名存在但没有该类型记录”不抛异常,否则大量域名会因为没配 AAAA 而中断采样。异常全部落成status字段而不是抛出,这样一轮采样不会因为单个域名超时而整体失败。

参数怎么调:TIMEOUT设 3 秒,跨运营商查询一般 2 秒内返回,超过 3 秒基本可以判定链路有问题;RESOLVERS至少要有一个和你业务用户所在网段接近的服务器,否则采到的结果没有代表性;TARGETS里把 CNAME 单独列出来,因为很多异常是从 CNAME 链下游开始的,只看 A 记录会漏。

3.2 漂移判定:怎么区分正常调度和异常改写

拿到两次采样结果直接做差集,误报会多到没法看。CDN 域名在不同递归服务器上返回不同 IP 是常态,TTL 到期后 IP 变了也是常态。我用的判定规则有下面几条,按优先级从高到低:

判定项正常情况异常信号
权威与递归结果递归结果属于权威记录集合递归返回了权威里不存在的 IP
TTL 数值在配置值附近波动被强制压到很小(如 30 秒以下)且持续
CNAME 链长度固定,与配置一致突然多出一跳指向陌生域名
同一递归多次查询结果稳定短时间内反复跳变
响应 IP 归属与业务部署区域一致落在完全无关的网段

第一条是硬规则:递归服务器缓存的一定是权威给过的记录(除非被改写)。所以只要出现“递归返回的 IP 不在权威记录集合里”,就值得立刻拉出来看。第二条也很有用,某些改写手段为了让自己的结果尽快生效,会把 TTL 强行压低,正常业务很少这么做。

第三条容易被忽略。CNAME 链上多一跳,可能意味着某个中间域名被别人接管了,而主域名的查询结果看起来毫无异常。

注意:CDN 场景下同一域名返回多个 IP 属于正常,判定时要比较“集合”而不是“单个 IP”,否则每天都在误报。

3.3 定时任务与告警落地

采样脚本跑通之后,挂到定时任务上,频率我一般设 5 分钟一次。太密会给自己增加噪声,太疏会漏掉短时改写。数据按天切分文件,方便回溯也方便清理。

# 每 5 分钟采样一次,日志按月归档 */5 * * * * cd /opt/dns-watch && \ /usr/bin/python3 sample.py >> /var/log/dns-watch/run.log 2>&1 # 每天凌晨把前一天的数据压缩归档,保留 90 天 30 0 * * * find /opt/dns-watch -name "dns_sample_*.jsonl" -mtime +1 \ -exec gzip {} \; -exec mv {}.gz /data/archive/ \;

告警这块有个血泪经验:不要每条异常都发。第一次上线时我配的是“有任何差异就告警”,结果一天几百条,第三天就没人看了。后来改成按域名聚合、按异常类型去重、同一域名同一类型 30 分钟内只发一次,有效告警才真正被处理。

去重的实现思路很简单:告警前先读一个状态文件,记录每个“域名+异常类型”组合的上次发送时间,未超过窗口期就跳过,超过就发并更新时间戳。窗口期设 30 分钟对大多数业务够用。

还有一条:告警内容里必须带上采样时间、递归服务器 IP、期望值和实际值。只发一句“解析异常”,收到的人还得自己去查,等于没告警。

3.4 把证据保全下来:应答原文与时间戳

解析类问题的麻烦之处在于它会自愈。TTL 一过,缓存刷新,现场就没了。所以采样时保存应答原文比保存解析结果重要得多——原文里有 TTL、有 CNAME 链、有权威段,这些都是事后复盘的依据。

我一般要求采样文件里至少保留:查询时刻(UTC)、递归服务器 IP、域名、记录类型、完整应答文本、TTL、状态。字段不多,但每一条在复盘时都用得上。尤其是 UTC 时间戳,跨时区协作时能省掉大量换算。

数据保留周期按业务定,域名资产变动不频繁的话,90 天足够覆盖一次完整的变更和回滚周期。

4. 本地域名映射工具怎么用:hosts 管理与开发环境调试

监测是“看”,映射是“改”。开发调试、灰度验证、上线前预演,都离不开在本地把某个域名指到指定 IP。这一章讲 hosts 的正确用法、批量维护脚本,以及什么时候该从 hosts 升级到本地 DNS 服务。

4.1 hosts 的生效顺序与三个容易忽略的细节

大多数 Linux 发行版的名称解析顺序由/etc/nsswitch.conf里的hosts:行决定,默认是files dns,也就是先查 hosts 文件、查不到再走 DNS。这意味着 hosts 的优先级高于任何 DNS 记录,写进去就立刻覆盖。

三个细节经常翻车。第一是 IPv6:域名同时有 A 和 AAAA 记录时,只写 IPv4 的 hosts 条目,某些客户端仍会优先走 AAAA 查询并拿到真实地址,看起来像 hosts 没生效。稳妥做法是 A 和 AAAA 都写上,不需要 IPv6 就写::1或直接屏蔽。

第二是尾部点。example.test.和example.test在部分工具里被视为不同名字,写 hosts 时统一不带尾点。

第三是缓存刷新。Linux 上 systemd-resolved 会缓存,改完 hosts 要执行resolvectl flush-caches;macOS 需要sudo dscacheutil -flushcache配合sudo killall -HUP mDNSResponder;Windows 是ipconfig /flushdns。不刷缓存就断言“hosts 不生效”,是很常见的误判。

还有一个使用习惯:hosts 里给自己维护的条目加统一注释前缀,比如# dev-managed,这样批量更新和清理时不会误删系统或软件写入的行。

4.2 用脚本批量维护映射条目

手工改 hosts 在条目少的时候没问题,超过十条就容易冲突、重复、漏删。我一般用一个带标记块的脚本管理,只操作自己那段,其他内容原样保留。

import re from pathlib import Path HOSTS = Path("/etc/hosts") BEGIN = "# >>> dev-managed >>>" END = "# <<< dev-managed <<<" # 映射清单:域名 -> IP,按环境分组维护 MAPPINGS = { "example.test": "203.0.113.10", "api.example.test": "203.0.113.11", "static.example.test": "203.0.113.12", } def render_block(): lines = [BEGIN] for domain, ip in MAPPINGS.items(): lines.append(f"{ip}\t{domain}\t# dev") lines.append(END) return "\n".join(lines) def update_hosts(): text = HOSTS.read_text(encoding="utf-8") block = render_block() pattern = re.compile( re.escape(BEGIN) + r".*?" + re.escape(END), re.S ) if pattern.search(text): # 已有标记块则原地替换,不影响文件其他部分 new_text = pattern.sub(block, text) else: # 没有标记块则追加到文件末尾,保留原有内容 new_text = text.rstrip("\n") + "\n\n" + block + "\n" HOSTS.write_text(new_text, encoding="utf-8") print("hosts updated, remember to flush dns cache") if __name__ == "__main__": update_hosts()

逻辑说明:用成对标记把托管区域圈起来,正则匹配时开启re.S让.能跨行,实现整块替换。没有标记块时追加而不是覆盖,避免把系统原有条目冲掉。

参数说明:MAPPINGS按环境拆成多个字典更实用,比如DEV、STAGING,切换环境时换一个字典重跑即可。写文件需要 root 权限,实际使用建议先写临时文件再原子替换,避免中途失败导致 hosts 被截断。

提示:脚本只负责写,不负责刷缓存。写完记得按平台执行对应的刷新命令,否则改动不会立刻生效。

4.3 从 hosts 升级到本地 DNS 服务

hosts 的局限很明显:只对单机生效、不支持通配符、不支持按域名后缀批量转发。当需要模拟整个子域、或者要在一个小团队内共享同一套映射时,本地 DNS 服务更合适。

常见做法是用 dnsmasq 起一个轻量解析服务,配置文件里写死几条映射,其余请求转发到上游。配置很短:

# /etc/dnsmasq.d/dev-mapping.conf # 只监听本地和测试网段,别开在公网口上 listen-address=127.0.0.1,203.0.113.1 # 单条静态映射 address=/api.example.test/203.0.113.11 # 整个子域指向同一地址,hosts 做不到这一点 address=/internal.example.test/203.0.113.20 # 其余域名转发到上游递归服务器 server=203.0.113.53

address=的语义是:匹配到该域名(含其子域)就直接返回指定地址,不再向上游查询。server=指定默认上游。配置改完systemctl reload dnsmasq生效,不需要重启。

这套方案的好处是可以让测试网段的所有机器统一走这台 DNS,映射一次全组生效。代价是多了一个需要维护的服务,所以只在确实有多机共享需求时才上,单机调试用 hosts 更省事。

5. 排查与避坑:六个真实翻车现场

工具用起来之后,坑基本都出在“以为它应该这样”和“实际它那样”之间。这一章把踩过的六次记下来,按现象、原因、解决三段写,遇到类似症状可以直接对照。

5.1 采样环节的两个坑

现象一:采样脚本跑了一晚上,第二天打开文件发现只有几十条记录,大量域名状态是timeout。

原因是脚本对所有查询共用一个 Resolver 实例,超时时间又是全局的,第一个慢查询把后续查询的预算吃掉了。另外部分递归服务器对短时间内的高频查询会限速,连续打过去直接不回应。

解决是把 Resolver 实例化放到每次查询内部,让每次查询独立计时;同时在服务器之间加 100 到 200 毫秒的间隔,避免触发限速。改完之后同样一批域名,超时率从三成降到不足百分之一。

现象二:某个域名的监测结果每天都在跳,一会儿多一个 IP,一会儿少一个,但人工查又是正常的。

原因是这个域名配了 CDN,不同递归服务器、不同时刻拿到的 IP 本来就不一样,而判定脚本用的是“集合完全相等”。这类误报最消耗信任,几次之后就没人看告警了。

解决办法是判定逻辑改成子集判断:只要递归返回的 IP 全部落在权威记录集合内就算正常,超出的才报。另外把 TTL 也纳入比对,正常调度的 TTL 是稳定的,异常改写往往伴随 TTL 异常。

5.2 判定与告警环节的两个坑

现象三:告警集中在凌晨触发,白天一条没有,看起来像定时被改。

原因是凌晨有批量任务会集中查询,采样脚本和业务任务撞在一起,本地递归服务器压力大,部分查询超时后返回空结果,被判定成“记录丢失”。这属于自己制造的问题。

解决是给采样单独指定一个递归服务器,不跟业务共用;同时在判定时把timeout和nxdomain分开处理,超时不计入异常,只在连续多次超时的时候单独告警。把“查不到”和“查到了但不是预期”混为一谈,是判定逻辑里最常见的错。

现象四:某个域名告警了整整两天,人工核查却发现解析完全正常。

原因是这个域名在半年前换过一次服务商,旧的权威服务器还留着一条过期记录,采样时偶尔会路由到旧服务器上。两套权威返回不同结果,判定脚本自然认为是异常。

解决是采样时先查 NS 记录确认当前权威列表,只向列表内的服务器发起查询;同时在域名变更流程里加一条“旧权威下线确认”,避免僵尸记录长期存在。这类问题不解决,会一直消耗排查精力。

5.3 配置与生效环节的两个坑

现象五:hosts 改完,ping生效了,但业务程序连的还是老地址。

原因是业务程序用的是自己的 DNS 解析库,有些语言的运行时会在进程启动时缓存解析结果,还有些程序直接读自己的配置文件而不走系统解析。ping走的是系统解析,两者根本不是一条路径。

解决办法是先确认目标程序用的是哪套解析机制:Java 有自己的缓存策略,Node.js 有dns.lookup和dns.resolve两条不同路径。确认之后再决定是改 hosts、改程序配置还是重启进程。只验证ping是不够的,必须用程序自身的连通性测试来验证。

现象六:dnsmasq 配好之后,本机正常,同事的机器还是解析到真实地址。

原因是同事的机器根本没指向这台 DNS,还在用默认的运营商递归。配置只在本机resolv.conf生效,没有下发到测试网段。

解决办法是二选一:要么在 DHCP 里把 DNS 指向这台机器,让网段内自动生效;要么让同事手动改网络配置。同时注意resolv.conf可能被网络管理服务覆盖,需要确认它是不是被某个服务托管,直接在文件里改会被冲掉。

这六条的共同点在于:每一条都不是工具本身的问题,而是对“哪一层在起作用”判断错了。排查解析问题,先把链路画出来,再确定自己在哪一层动手,比直接改配置有效得多。

6. 把防护做进流程:DNSSEC、CAA 与证书透明日志的日常检查

监测能发现异常,但防不住异常发生。真正降低风险的是把几项配置检查固化进日常流程,让问题在被人利用之前暴露。我一般在域名上线和季度巡检时各跑一遍下面这套检查。

检查项命令或入口通过标准
DNSSEC 签名dig +dnssec看AD标志标志为真,链上无断点
CAA 记录dig CAA只允许已知 CA 签发
证书域名openssl s_client -connect主题与 SAN 均匹配
证书透明日志按域名检索签发记录无未知签发记录
NS 记录一致性多个递归对比 NS权威列表一致且无残留

DNSSEC 这块,AD标志为假不一定代表没配,也可能是你用的递归服务器不做验证。判断时要区分“域名未签名”和“验证未通过”,前者看有没有RRSIG记录,后者看递归服务器自身是否开启验证。

CAA 记录的作用是告诉证书颁发机构“只允许这几家给我签发”。配置很简单,一条记录就够:example.test. CAA 0 issue "letsencrypt.org"。它的价值在于,即使有人通过其他途径申请到了该域名的证书,正规 CA 也会因为 CAA 不匹配而拒绝签发。

证书透明日志是另一道保险。每次有 CA 签发证书,都会写入公开日志。定期按自己的域名检索一遍,出现不认识的签发记录就要立刻排查。这一步不需要任何工具,浏览器检索入口就能查。

# 一次性快照:DNSSEC 状态 + CAA + 证书有效期 dig example.test A +dnssec +short dig example.test CAA +short echo | openssl s_client -connect example.test:443 -servername example.test 2>/dev/null \ | openssl x509 -noout -subject -dates -ext subjectAltName

这三条命令我一般放在变更前和变更后各跑一次,输出存档。变更后 DNSSEC 的AD标志消失,往往意味着签名没跟上记录更新,这种情况在上线窗口里发现,比等用户反馈要好得多。

有个习惯是被一次事故逼出来的:那次改完解析记录,忘了同步更新 DNSSEC 签名,结果部分做验证的递归服务器直接返回解析失败,而没做验证的线路一切正常,问题隐藏了将近一天才被定位。从那以后我每次动解析记录,都强制把 DNSSEC 状态、CAA 记录、证书有效期这三项走一遍,输出和变更单一起存档。看起来多花十分钟,但省下的是整晚的排查。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询