news 2026/10/21 16:52:00

Linux域名解析故障排查:从resolv.conf到systemd-resolved的七层链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux域名解析故障排查:从resolv.conf到systemd-resolved的七层链路

1. 项目概述:为什么域名解析是Linux网络里最常被忽略、却最不能出错的一环

“Linux网络基础3(域名解析服务)”这个标题看起来平平无奇,像是教科书目录里一个不起眼的章节编号。但如果你在某次深夜排查线上服务连不上API、某台新部署的服务器死活ping不通内网域名、或者CI/CD流水线突然卡在apt update那一步——十有八九,问题就藏在这“第三讲”里。我带过不少刚从学校出来的新人,他们能手写iptables规则、能调通Docker网络、甚至能搭起K8s集群,可一遇到curl: (6) Could not resolve host: api.internal这种报错,第一反应还是去查防火墙、看端口、翻日志,最后折腾两小时才发现:/etc/resolv.conf里写的DNS服务器早就宕了,或者systemd-resolved和dnsmasq在后台偷偷打架。

域名解析服务,说白了就是把“www.example.com”翻译成“192.0.2.42”的翻译官。它不直接处理业务逻辑,不承载流量,不参与加密握手,但它一旦失职,整个网络通信就卡在起点——就像你拿着一张写满地址的快递单,却找不到邮局在哪。Linux系统里这层翻译机制远比Windows“自动获取DNS”复杂得多:它不是单一配置文件的事,而是/etc/hosts、/etc/resolv.conf、systemd-resolved、nsswitch.conf、dnsmasq、甚至容器运行时自带的DNS代理,多层叠加、相互覆盖、优先级隐晦。更麻烦的是,不同发行版默认策略差异极大:Ubuntu 22.04默认启用systemd-resolved并接管53端口,CentOS 7则长期依赖NetworkManager生成resolv.conf,而Alpine镜像里压根没装systemd,全靠BusyBox的nslookup硬扛。这些细节不会写在面试题里,但会真实出现在你凌晨三点收到的告警页面上。

这篇文章不讲RFC 1034那种理论推导,也不堆砌dig +trace的冗长输出。我会以一个真实运维现场的视角,带你一层层剥开Linux域名解析的洋葱结构:从最底层的/etc/hosts静态映射如何被绕过,到resolv.conf里options timeout:1 attempts:2这些参数怎么决定你的服务启动慢3秒还是快3秒;从systemd-resolved的StubListener模式为何让nslookup和dig结果不一致,到容器内/etc/resolv.conf为何总是指向127.0.0.11——以及你该不该改它。所有内容都基于我过去三年在多个生产环境踩坑、复现、抓包、源码翻查的真实记录,每一步操作都有明确意图,每个参数都有实测依据。适合正在搭建跳板机的运维、调试K8s CoreDNS的SRE、写自动化脚本总被DNS超时打断的DevOps,或者只是想搞懂“为什么我的Linux机器有时能上网有时不能”的技术爱好者。你不需要背命令,只需要理解数据包从getaddrinfo()调用开始,到底经过了几道门、被谁改写了、又在哪个环节悄悄失败了。

2. 域名解析的完整链路拆解:从应用调用到网络响应的七层穿透

要真正掌控Linux的DNS行为,必须跳出“改个resolv.conf就完事”的思维定式。整个解析过程是一条贯穿用户空间到内核空间、横跨多个子系统的数据流,任何一环出问题,都会导致看似相同的命令产生截然不同的结果。我把它拆解为七个关键阶段,每个阶段都对应一个可验证、可干预的控制点。

2.1 阶段一:应用层发起解析请求(glibc的getaddrinfo)

几乎所有Linux应用(curl、wget、python requests、nodejs http模块)都不直接调用gethostbyname这种老接口,而是走POSIX标准的getaddrinfo()。这个函数本身不发网络包,它只做一件事:根据/etc/nsswitch.conf的配置,决定接下来该找谁要IP地址。比如你执行curl https://github.com,glibc会先读nsswitch.conf里hosts:这一行,看到files dns,就明白:先查/etc/hosts,查不到再走DNS协议。这里有个极易被忽视的细节:getaddrinfo默认会同时查询A记录(IPv4)和AAAA记录(IPv6),如果DNS服务器对AAAA响应慢或超时,整个解析就会被拖慢——哪怕你根本不需要IPv6。实测中,某云厂商的公共DNS对AAAA查询平均耗时800ms,而A记录只要20ms,这就导致curl启动延迟明显。解决方案不是禁用IPv6(那会引发更多兼容性问题),而是在/etc/gai.conf里添加precedence ::ffff:0:0/96 100,强制IPv4优先,或者用curl --ipv4显式指定。

2.2 阶段二:名称服务切换器(nsswitch.conf的决策中枢)

/etc/nsswitch.conf是整个解析链路的“交通指挥中心”。它的hosts:行决定了查询顺序和来源。常见配置有三种典型组合:

  • hosts: files dns(最经典):先查/etc/hosts,失败后走DNS。安全团队常在此处加mdns4_minimal支持mDNS(如.local域名),但要注意mdns4_minimal会拦截所有.local查询,导致无法解析真正的公网xxx.local域名。
  • hosts: files resolve [!UNAVAIL=return] dns(systemd-resolved场景):resolve代表调用systemd-resolved的D-Bus接口,[!UNAVAIL=return]是关键——如果systemd-resolved服务未运行,立即返回失败,不再尝试后面的dns。这意味着你systemctl stop systemd-resolved后,ping可能直接报Unknown host,而不是fallback到resolv.conf。
  • hosts: dns [NOTFOUND=return] files(反向顺序):先DNS,查不到才查/etc/hosts。这在某些需要动态域名管理的场景有用,但会完全绕过/etc/hosts的本地调试能力,不推荐日常使用。

提示:修改nsswitch.conf后无需重启服务,glibc在每次getaddrinfo调用时实时读取。但务必用getent hosts github.com验证效果,ping或curl可能因缓存掩盖问题。

2.3 阶段三:本地静态映射(/etc/hosts的精确制导)

/etc/hosts是解析链路上唯一不发网络包的环节,也是最可靠的调试工具。它的格式极其简单:IP地址 主机名 别名,但有三个魔鬼细节:

  1. 注释与空行:#开头的行和纯空行会被忽略,但127.0.0.1 example.com #comment这种写法,#后面的内容会被当作文本而非注释,可能导致解析失败;
  2. IPv6地址格式:::1必须写全,不能简写为127.0.0.1,否则IPv6应用(如某些Go程序)会忽略;
  3. 主机名匹配逻辑:192.168.1.100 server1 server1.internal中,server1和server1.internal是两个独立条目,ping server1.internal不会自动fallback到server1。

我曾在一个K8s集群调试中发现,coredns的Pod IP被错误写入/etc/hosts,导致所有节点上的kubectl get nodes都返回Connection refused——因为kubectl默认连接https://kubernetes.default.svc.cluster.local,而/etc/hosts里这条记录把域名指向了已销毁的旧Pod IP。解决方法不是删掉/etc/hosts,而是用sed -i '/kubernetes\.default\.svc\.cluster\.local/d' /etc/hosts精准删除,避免误伤其他条目。

2.4 阶段四:DNS客户端配置(resolv.conf的明面战场)

/etc/resolv.conf是大家最熟悉的配置文件,但它早已不是“最终判决书”。现代Linux中,它常是其他服务(NetworkManager、systemd-resolved、dhclient)的输出产物。其核心指令只有三条:

  • nameserver 1.1.1.1:最多允许3个,按顺序使用,前一个超时才试下一个;
  • search example.com internal.net:当解析db时,自动尝试db.example.com、db.internal.net;
  • options timeout:2 attempts:3 rotate:timeout是单次查询等待秒数,attempts是重试次数,rotate开启轮询(避免单点DNS压力过大)。

关键陷阱在于timeout和attempts的乘积。默认timeout:5 attempts:2意味着单域名最大阻塞10秒。在微服务架构中,一个服务启动要解析10个依赖域名,最坏情况就是100秒启动延迟。我们线上将timeout压到1,attempts设为2,配合rotate,实测平均解析时间从3.2秒降至0.8秒,且失败率未上升——因为现代DNS服务器基本能在1秒内响应,超时更多是网络抖动或中间设备丢包所致。

2.5 阶段五:本地DNS代理(systemd-resolved的双面性)

systemd-resolved是systemd生态的DNS管家,它监听127.0.0.53:53(Stub Listener),对外提供DNS服务,对内聚合多种上游。它的存在让resolv.conf变得“不可信”:当你看到nameserver 127.0.0.53,实际流量并未发往53端口,而是被resolved进程截获,再根据/run/systemd/resolve/resolv.conf(它的上游配置)转发。resolved的强项在于缓存(TTL内零延迟)、DNSSEC验证、LLMNR/mDNS支持;弱点在于调试困难——dig @127.0.0.53 github.com能通,但nslookup github.com却失败,因为nslookup默认用/etc/resolv.conf,而dig可以指定服务器。

要彻底掌控resolved,必须理解它的三层配置:

  • /etc/systemd/resolved.conf:主配置,DNS=定义全局上游,Domains=~.表示对所有域名走此DNS(禁用search域);
  • /run/systemd/resolve/resolv.conf:resolved实际使用的上游列表,由NetworkManager等服务动态更新;
  • /etc/resolv.conf:通常软链接到/run/systemd/resolve/stub-resolv.conf,指向127.0.0.53。

注意:systemctl restart systemd-resolved不会重新加载/etc/systemd/resolved.conf,必须systemctl daemon-reload后再重启,否则配置无效。

2.6 阶段六:网络管理器介入(NetworkManager的自动覆盖)

NetworkManager是桌面版Linux的DNS事实标准。它会在/etc/resolv.conf上打上# Generated by NetworkManager标记,并根据当前连接(Wi-Fi/以太网)的DHCP选项或手动设置,动态生成DNS服务器。问题在于:它默认不读取/etc/systemd/resolved.conf,而是把自己的配置硬写进/run/systemd/resolve/resolv.conf,导致resolved的全局DNS被覆盖。解决方案有两个:

  • 彻底禁用NM的DNS管理:在/etc/NetworkManager/NetworkManager.conf中添加[main] dns=none,然后nmcli dev set eth0 managed no;
  • 让NM配合resolved:在/etc/NetworkManager/conf.d/99-resolved.conf中写[main] dns=systemd-resolved,这样NM会把DHCP获取的DNS写入resolved的上游,而非直接覆盖resolv.conf。

我在线上服务器一律采用第一种方案,因为服务器网络配置稳定,不需要NM的动态能力,反而要杜绝它对DNS的“好心办坏事”。

2.7 阶段七:容器与虚拟化环境(隔离网络下的DNS迷宫)

容器是DNS问题的高发区。Docker默认将宿主机的/etc/resolv.conf复制进容器,但如果宿主机用systemd-resolved,容器内nameserver 127.0.0.53就完全失效(容器网络命名空间里没有resolved服务)。Kubernetes更进一步:kubelet会为每个Pod生成/etc/resolv.conf,nameserver指向CoreDNS Service IP(如10.96.0.10),并注入search域。但若CoreDNS异常,Pod内所有域名解析即刻瘫痪,且nslookup会显示connection timed out而非server failed,让人误以为是网络连通性问题。

实操中,我坚持两条铁律:

  1. 绝不信任容器内的resolv.conf自动生成:Docker启动时用--dns=1.1.1.1 --dns-search=internal.net显式指定;
  2. K8s中为关键Pod添加dnsPolicy: Default(继承Node DNS)或dnsPolicy: None(完全自定义),避免被集群DNS故障波及。曾有一个支付服务因CoreDNS滚动升级失败,所有Pod解析超时,而dnsPolicy: Default的监控Agent Pod仍能正常上报,帮我们快速定位到CoreDNS而非业务代码。

3. 核心实操:五类高频场景的逐行诊断与修复方案

光知道链路不够,得有能立刻上手的诊断武器库。下面五个场景,全部来自我处理过的生产事故,每个都附带3步定位法和1行修复命令,确保你下次遇到同类问题,5分钟内解决。

3.1 场景一:ping通但curl失败——glibc与DNS协议的隐性冲突

现象:ping github.com返回IP并通,但curl https://github.com报Could not resolve host。
根因分析:ping用gethostbyname(仅查A记录),curl用getaddrinfo(查A+AAAA)。若DNS服务器对AAAA记录响应异常(如返回SERVFAIL或超时),getaddrinfo会整体失败,而ping不受影响。

3步定位法:

  1. dig github.com A和dig github.com AAAA对比响应时间与状态码;
  2. getent ahosts github.com(ahosts强制走getaddrinfo路径)验证是否真失败;
  3. strace -e trace=connect,sendto,recvfrom curl -v https://github.com 2>&1 | grep -A5 -B5 "getaddrinfo"看系统调用级失败点。

1行修复命令:

echo 'options single-request-reopen' | sudo tee -a /etc/resolv.conf

single-request-reopen让glibc对A和AAAA查询使用独立socket,避免AAAA阻塞A。实测后curl成功率从42%升至99.8%,且无需重启任何服务。

3.2 场景二:systemd-resolved与dnsmasq端口冲突——53端口的争夺战

现象:systemctl status systemd-resolved显示active,但sudo ss -tuln | grep :53看不到监听,dig @127.0.0.53超时。
根因分析:dnsmasq(常被用作本地DNS缓存)默认监听0.0.0.0:53,抢占了systemd-resolved的127.0.0.53:53。resolved检测到53端口被占,自动降级为127.0.0.54,但resolv.conf仍指向127.0.0.53,导致断连。

3步定位法:

  1. sudo ss -tuln | grep :53查看哪个进程占着53;
  2. sudo systemctl list-units | grep dns检查dnsmasq是否启用;
  3. journalctl -u systemd-resolved -n 50 --no-pager | grep -i "port.*53"看resolved日志中的端口警告。

1行修复命令:

sudo sed -i 's/bind-interfaces/#bind-interfaces/' /etc/dnsmasq.conf && sudo systemctl restart dnsmasq

注释bind-interfaces后,dnsmasq只监听127.0.0.1:53,resolved可安全使用127.0.0.53。若需dnsmasq监听所有接口,则改resolved端口:sudo mkdir -p /etc/systemd/resolved.conf.d && echo -e "[Resolve]\nDNSStubListener=no" | sudo tee /etc/systemd/resolved.conf.d/no-stub.conf,再sudo systemctl restart systemd-resolved。

3.3 场景三:容器内/etc/resolv.conf被覆盖——Docker的静默篡改

现象:Docker容器内cat /etc/resolv.conf显示nameserver 127.0.0.11,但dig @127.0.0.11 google.com超时,宿主机DNS正常。
根因分析:Docker守护进程内置DNS服务器(dockerd的embedded DNS),监听127.0.0.11,负责解析容器间服务名(如redis)。但它不处理外部域名,需转发给上游DNS。若宿主机/etc/resolv.conf为空或无效,dockerd无法获取上游,导致外部解析失败。

3步定位法:

  1. docker info | grep -i "name resolution"确认Docker DNS状态;
  2. cat /etc/resolv.conf(宿主机)检查是否有有效nameserver;
  3. docker run --rm alpine nslookup google.com 127.0.0.11测试Docker DNS转发能力。

1行修复命令:

echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf && sudo systemctl restart docker

强制宿主机resolv.conf有可用DNS,Docker启动时会自动读取并设为上游。注意:不要在容器内改resolv.conf,Docker会覆盖。

3.4 场景四:search域导致解析爆炸——域名拼接的隐形炸弹

现象:curl http://api失败,但curl http://api.internal.net成功;nslookup api返回api.internal.net的IP,而nslookup api.internal.net却失败。
根因分析:/etc/resolv.conf中search internal.net,nslookup api实际查询api.internal.net,但api.internal.net在DNS中不存在,nslookup显示NXDOMAIN;而curl http://api因HTTP Host头是api,后端Nginx按server_name api;匹配,所以能通——这是应用层与DNS层的错位。

3步定位法:

  1. grep search /etc/resolv.conf查看search域;
  2. host -v api显示详细查询过程,看是否拼接了search域;
  3. curl -v http://api 2>&1 | grep "Host:"确认HTTP请求头是否含Host: api。

1行修复命令:

sudo sed -i 's/search.*/search ~./' /etc/resolv.conf

search ~.是特殊语法,表示“不为任何域名拼接search域”,彻底关闭拼接。若需保留部分search,用search internal.net ~example.com,表示example.com及其子域不拼接。

3.5 场景五:/etc/hosts条目被忽略——nsswitch.conf的权限陷阱

现象:/etc/hosts里写了192.168.1.100 db-prod,但ping db-prod报Unknown host,getent hosts db-prod无输出。
根因分析:nsswitch.conf中hosts:行漏掉了files,如写成hosts: dns,则完全跳过/etc/hosts。或者/etc/hosts权限错误(非644),glibc会拒绝读取。

3步定位法:

  1. cat /etc/nsswitch.conf | grep hosts检查files是否存在;
  2. ls -l /etc/hosts确认权限为-rw-r--r--;
  3. strace -e trace=openat ping db-prod 2>&1 | grep hosts看ping是否尝试打开/etc/hosts。

1行修复命令:

sudo chmod 644 /etc/hosts && sudo sed -i 's/hosts:.*/hosts: files dns/' /etc/nsswitch.conf

权限修正+强制files优先,双保险。注意:nsswitch.conf修改后立即生效,无需重启。

4. 深度避坑指南:那些文档里不会写的12个致命细节

以下是我三年来在数十个生产环境反复验证的“血泪教训”,每一条都对应一个曾让我加班到凌晨的故障。它们不写在man page里,但比任何命令都重要。

4.1resolv.conf的符号链接陷阱:/etc/resolv.conf可能是软链,但内容未必可信

很多发行版(如Ubuntu)将/etc/resolv.conf软链接到/run/systemd/resolve/stub-resolv.conf,而后者由systemd-resolved生成。但resolved有个隐藏行为:当它检测到上游DNS不可达时,会主动清空/run/systemd/resolve/resolv.conf里的nameserver,导致stub-resolv.conf也变空。此时cat /etc/resolv.conf显示空白,但ping仍能工作——因为nsswitch.conf的files还在,/etc/hosts条目生效。这种“表面故障实则正常”的状态,会让新手疯狂重装resolved。正确做法是:永远用readlink -f /etc/resolv.conf确认真实路径,再检查该路径内容;若为空,直接sudo systemd-resolve --status看上游状态,而非盲目重启服务。

4.2systemd-resolved的缓存污染:TTL过期前,错误记录永久生效

systemd-resolved缓存遵循DNS TTL,但有个例外:当它收到SERVFAIL响应时,会缓存该错误长达30秒(硬编码,不可配)。这意味着,若某次DNS查询因临时网络抖动返回SERVFAIL,接下来30秒内所有相同域名查询都会直接失败,无论网络是否已恢复。实测中,我们用sudo systemd-resolve --flush-caches清缓存后,故障立即消失。但更治本的方法是:在/etc/systemd/resolved.conf中添加Cache=yes(确保开启)和DNSStubListener=yes,并监控ResolvedCacheHit指标,发现缓存命中率异常高时,主动flush-caches。

4.3 容器DNS的--dns-opt参数:ndots:5让K8s服务发现变慢5倍

Docker的--dns-opt ndots:N控制域名中“点号”数量阈值。默认ndots:5,意味着redis(0个点)会被当作相对域名,拼接search域查询redis.default.svc.cluster.local,而K8s的search域有4层(default.svc.cluster.local svc.cluster.local cluster.local),导致最多4次DNS查询才能得到结果。线上我们将ndots设为1:docker run --dns-opt ndots:1 ...,这样redis直接查A记录,redis.default.svc.cluster.local才走search拼接,解析耗时从平均120ms降至22ms。

4.4getent命令的隐藏开关:-s参数可绕过nsswitch.conf

getent hosts github.com按nsswitch.conf顺序查,但getent -s files hosts github.com强制只查/etc/hosts,getent -s dns hosts github.com强制只走DNS。这在调试nsswitch.conf配置是否生效时极有用——比如你怀疑files被跳过,直接getent -s files hosts db-prod,若返回IP,说明/etc/hosts本身没问题,问题在nsswitch.conf或files模块加载失败。

4.5dig与nslookup的本质区别:一个走系统配置,一个走自定义服务器

nslookup github.com默认读/etc/resolv.conf,dig github.com默认走系统DNS(即getaddrinfo路径)。所以当systemd-resolved启用时,nslookup可能失败(因resolv.conf指向127.0.0.53而resolved异常),但dig仍成功(因dig内部实现绕过了resolv.conf,直连resolved的D-Bus)。因此,DNS调试必须用dig @127.0.0.53 github.com(指定服务器)和getent ahosts github.com(走系统路径)双验证,单用nslookup会得出错误结论。

4.6chattr +i锁死/etc/resolv.conf:安全加固的反效果

有些安全规范要求chattr +i /etc/resolv.conf防止篡改,但这会导致NetworkManager、systemd-resolved等服务无法更新DNS,所有动态网络(如DHCP)失效。线上环境应避免+i,改用chmod 444 /etc/resolv.conf(只读)+chown root:root,既防误改,又允许可信服务(如systemd-resolved)通过chown临时修改权限再写入。

4.7nsswitch.conf的compat源:+号引入的NIS风险

hosts: files dns是安全的,但hosts: compat会启用NIS(网络信息服务),/etc/hosts中+开头的行(如+@netgroup)会触发NIS查询。若NIS服务器不可达,getaddrinfo会阻塞数秒。生产环境必须禁用compat,grep -r "+" /etc/hosts清理所有+行,nsswitch.conf中hosts行严禁出现compat。

4.8resolv.conf的options edns0:EDNS协议扩展的双刃剑

options edns0启用EDNS0协议,支持大于512字节的DNS响应(如DNSSEC)。但某些老旧防火墙会丢弃EDNS0包,导致查询超时。若遇到dig +short google.com成功,但dig +short google.com @8.8.8.8失败,大概率是EDNS0被拦截。临时解决:echo "options no-edns0" | sudo tee -a /etc/resolv.conf。

4.9systemd-resolved的LLMNR:局域网内.local域名的隐形杀手

LLMNR(链路本地多播DNS)默认开启,会响应.local域名查询。但若网络中有Apple设备(用Bonjour),它们也响应.local,导致resolved和Bonjour抢答,解析结果随机。企业内网应禁用:sudo mkdir -p /etc/systemd/resolved.conf.d && echo -e "[Resolve]\nLLMNR=no" | sudo tee /etc/systemd/resolved.conf.d/no-llmnr.conf。

4.10getaddrinfo的AI_ADDRCONFIG标志:IPv6环境下的连接黑洞

glibc的getaddrinfo默认带AI_ADDRCONFIG标志,意思是“只返回与本机配置匹配的地址族”。若机器有IPv6地址但网络不支持IPv6路由,getaddrinfo会过滤掉所有AAAA记录,但某些应用(如旧版Java)会因AI_ADDRCONFIG缺失而尝试连接IPv6地址,导致超时。统一方案:在/etc/gai.conf末尾加precedence ::ffff:0:0/96 100,强制IPv4优先,比改应用代码更可靠。

4.11resolv.conf的rotate与timeout组合:轮询不等于负载均衡

options rotate让nameserver轮询,但timeout是单次查询时限。若nameserver 1.1.1.1超时(1秒),nameserver 8.8.8.8立即被尝试,这看起来是负载均衡。但若1.1.1.1偶尔慢(如200ms),8.8.8.8永远得不到机会,因为rotate只在超时后触发。真正均衡的做法是:options timeout:1 attempts:1 rotate,每次只试1次,超时就轮到下一个,确保每个DNS服务器都有均等机会。

4.12systemd-resolved的DNSSEC验证:安全与可用性的终极权衡

DNSSEC开启(DNSSEC=allow-downgrade)能防DNS劫持,但会增加解析延迟(需验证签名),且某些CDN(如Cloudflare)的DNSSEC配置错误会导致SERVFAIL。线上我们设为DNSSEC=allow-downgrade:当上游支持DNSSEC时验证,不支持时降级为普通查询,兼顾安全与可用性。验证命令:systemd-resolve --statistics | grep DNSSEC。

5. 实战案例复盘:一次跨机房DNS故障的72小时攻坚

最后分享一个完整案例,它浓缩了前述所有知识点。这不是理论推演,而是我在某金融客户现场的真实记录。

5.1 故障初现:告警风暴与表象迷惑

周三上午10:23,监控平台突现告警:所有跨机房服务调用失败,错误日志清一色java.net.UnknownHostException: api.prod.internal。第一反应是网络中断,但ping各机房网关IP全通,telnet api.prod.internal 443却报Connection refused——等等,telnet需要IP,它怎么知道api.prod.internal的IP?原来telnet也走getaddrinfo,所以问题在DNS,不在网络层。我们立刻登录跳板机执行dig api.prod.internal @10.10.1.1(主DNS),返回NOERROR,IP正确;但getent ahosts api.prod.internal无输出。矛盾出现了:dig能查,getent不能查。

5.2 链路分段:七层穿透式排查

按前述七层链路,我们逐层验证:

  • 阶段一(应用层):strace -e trace=getaddrinfo telnet api.prod.internal 443确认getaddrinfo被调用;
  • 阶段二(nsswitch):cat /etc/nsswitch.conf | grep hosts显示hosts: files dns,正常;
  • 阶段三(/etc/hosts):grep api.prod.internal /etc/hosts为空,排除;
  • 阶段四(resolv.conf):cat /etc/resolv.conf显示nameserver 10.10.1.1,且search prod.internal,正常;
  • 阶段五(systemd-resolved):systemctl status systemd-resolvedactive,但sudo ss -tuln | grep :53无监听——resolved没起来!journalctl -u systemd-resolved | tail -20显示Failed to bind to 127.0.0.53:53: Address already in use。查ss -tuln | grep :53,发现dnsmasq在监听0.0.0.0:53。这就是场景二的端口冲突!

5.3 根因锁定:dnsmasq的bind-interfaces失效

我们以为dnsmasq配置了bind-interfaces,应只监听127.0.0.1。但cat /etc/dnsmasq.conf | grep bind发现#bind-interfaces被注释了!原因是上周安全扫描工具自动备份并修改了配置文件,但未重启dnsmasq,所以旧进程仍在运行,新配置未生效。kill -9旧进程后,dnsmasq按新配置启动,释放53端口,systemd-resolved自动监听127.0.0.53,getent ahosts api.prod.internal立即返回IP。

5.4 深度复盘:为什么故障持续72小时?

问题解决了,但为什么从周三上午到周五下午才定位?因为dnsmasq的bind-interfaces注释是扫描工具所为,而dnsmasq

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 16:51:45

享元模式详解:用共享技术解决对象爆炸与内存优化

写代码写久了,尤其是做后端或者图形渲染这类重对象业务,会经常遇到同一个问题:内存不受控。我印象很深的一次排查,是一个批量导出模块在高峰期内存飙升,堆占用肉眼可见地往上涨,最后只能靠重启扛过去。用转…

作者头像 李华
网站建设 2026/10/21 16:51:41

项目资料缺失?补齐标题正文关键词与摘要

您好,我没收到可用的项目内容。这次输入里的【项目标题】等内容都是空白的,所以暂时无法生成对应的博文。麻烦您补充一下:项目标题项目正文(可以是零散的原始描述)关键词摘要描述内容主题不限,科技、生活、…

作者头像 李华
网站建设 2026/10/21 16:51:39

AM解调仿真:包络检波与相干解调原理、噪声响应及工程实现

简介:本资源是一份面向通信工程专业本科生的《通信原理》课程设计报告,聚焦AM调制信号的两种核心解调方式——包络检波与相干解调的MATLAB/Simulink建模仿真与性能对比。报告完整呈现从信源生成(1kHz基带1MHz载波)、加性高斯白噪声…

作者头像 李华
网站建设 2026/10/21 16:49:41

lingbot-map:轻量级机器人地图数据管理与查询实战指南

1. 从“lingbot-map”这个名字说起:它到底想解决什么问题 第一次看到“lingbot-map”这个项目名,我的直觉是:这大概率是一个把“机器人(bot)”和“地图(map)”绑在一起的工具,而且“…

作者头像 李华
网站建设 2026/10/21 16:49:04

51单片机智能加湿器毕设实战:从原理图到闭环控制

简介:本资源是一份面向计算机应用技术(嵌入式方向)专业高年级学生与单片机初学者的毕业设计论文文档,聚焦解决传统加湿器依赖人工操作、缺乏环境感知与安全保护的问题。论文以AT89C51单片机为核心,完整实现温湿度自动监…

作者头像 李华
网站建设 2026/10/21 16:47:45

把学习当项目来记录:从零散笔记到可复用的知识体系

记录一下学习说起来也挺有意思的,以前我总觉得自己学得挺努力——书架上堆着翻了一半的技术书,浏览器里躺着几十个收藏夹,网盘里存了几个T的视频课程。可每次到了要动手做个什么东西的时候,脑子里就只剩下一片空白,要么…

作者头像 李华