VPN 上的 CIFS 挂载失败,原因是 nsswitch 顺序
共享按地址能响应,按名字却卡住,因此查找在 SMB 开始之前就死了。先比较 getent 与 host,再按顺序读 hosts 那一行。
隧道是通的。文件服务器按地址能回应 ping。接着用主机名跑 mount.cifs 会卡上一会儿,然后报主机不可达,你于是开始重建一个从来不是问题所在的 VPN 配置。在 Linux 上,名字在任何一个 SMB 包出现之前就由 glibc 解析,而那个解析器里的顺序可能在 DNS 被问到之前就结束查找。以下是我走的路径,从失败的那条命令开始,而不是从客户端开始。
在正确的位置读失败
两个工具用不同的路径解析同一个名字,比较它们只花一条命令。getent 会走配置好的名字服务栈;host 和 dig 直接查询 DNS,无视那个栈。如果直接查询返回地址而 getent 什么都不返回,说明 DNS 服务器可达,失败的是你的解析器配置。
getent hosts fileserver.corp.example
host fileserver.corp.example 10.61.0.1
getent -s dns hosts fileserver.corp.example
第三条命令是裁决者:它强制走 DNS 源并跳过栈的其余部分。当它成功而普通的 getent 失败时,你就证明了错在顺序,而不在隧道,也不在服务器。
hosts 那一行是一串会提前停下的序列
glibc 解析器读取 /etc/nsswitch.conf,并从左到右走 hosts: 这一项。许多发行版给出的行把 multicast 查找放在最前,还挂着一个提前返回的动作。这个动作不是装饰:当 mDNS 回答 “not found” 时,[NOTFOUND=return] 会结束整个查找,于是公司名字根本不会送到 VPN 推送来的解析器。没有任何东西记录它,因为根本没有发出让解析器拒绝的查询。这就是为什么挂载看起来卡住,随后报告主机不可达。
cat /etc/nsswitch.conf | grep '^hosts:'
# illustrative repair: dns before the early-return action
hosts: files myhostname mdns4_minimal dns [NOTFOUND=return] wins mdns4
把 DNS 挪到提前返回动作之前,而不是删掉 mDNS,并通过配置管理来改。手工改一次能撑到下一次镜像构建,然后同一张工单又会从另一台不记得这个修法的机器上过来。
解析器不是搜索域
解析还需要让名字被尝试。像 fileserver 这样的非限定名,只有在承载查询的接口挂上搜索域之后才会变成 fileserver.corp.example。只推送 DNS 服务器却不给搜索列表的 VPN,会造成一种非常特定的分裂:完全限定名能解析,而每个短名都失败.
改配置之前先把两种形式都测一遍,因为两种失败指向不同方向。在 systemd-resolved 主机上,隧道链路拥有自己的服务器和路由域,所以要读链路,而不是全局文件。
resolvectl status
resolvectl query fileserver.corp.example
resolvectl dns
resolvectl domain
如果查询被归到一个不承载隧道的链路上,那么即使 DNS 地址在,路由域也是缺的。这是 resolved 配置里的策略问题,不是隧道里的路由问题。
容器自带一份答案副本
从通用镜像构建的容器通常带一个固定的 resolv.conf。宿主机上改的解析器到不了它那里,搜索域也一样,于是通过隧道挂载共享的构建任务会失败,而同一条命令在容器外却能跑。请在 compose 文件或 run 参数里给容器自己的 DNS 与搜索设置,而不只是写在宿主机配置里。
先怪镜像之前,进容器里查。两条命令几秒钟就能复现整套诊断,第二条还能证明到底是哪个解析器在回答。
到这时才去看共享和过滤器
名字一旦解析成功,剩下的失败就是普通网络问题。SMB 需要到服务器的 TCP 445,而浏览工作组列表依赖隧道多半不会转发的名字服务。按主机名映射,别等列表自己长出来,并让客户端告诉你它走到了哪一步。拒绝连接和静默超时也值得分开,因为前者通常意味着有东西回应了,后者意味着什么都没回应。
getent hosts fileserver.corp.example
nc -vz fileserver.corp.example 445
mount -t cifs //fileserver.corp.example/share /mnt/share \
-o vers=3.1.1,username=svc_mount,uid=1000
地址解析成功但 445 端口被拒绝或超时,那是另一侧的防火墙或监听问题。名字解析不了才是解析器的问题。而能认证却返回权限错误的挂载两者都不是,因此会话一旦建立,就别再回头翻网络问题。
结论要和证据一样窄。地址能用而名字不能时,隧道在干它该干的事,修法属于解析器顺序、搜索域,或者容器自己的配置。