用逆向方法:排除一例 NFS (网络文件系统)罕见故障
作者:高玉涵
时间:2021.12.20 09:47
博客:blog.csdn.net/cg_i
环境:
1 号机: HP-UX B.11.31 U ia64
2 号机:Linux 4.19.90-24.4.v2101.ky10.x86_64
前言
手头项目需要 HP-UX 和 LINUX 系统,远程访问同一存储。系统部同事给出的办法是,使用 Sun 的网络文件系统(NFS)协议。NFS 协议被设计为适合于不同的机器、操作系统、网络体系和传输协议。此协议的实现已存在于上述系统上(NFSv3),且允许把远程目录链接到本地文件系统进行透明的远程访问(客户端访问该共享与访问本地文件系统没有任何差别)。
NFS 卡住了
症状描述:HP-UX 能正常挂载、卸载共享。挂载共享后,能进入目录(CD)、创建目录(MKDIR)、创建文件(TOUCH 1.txt)、写入文件(ECHO “2” >> 1.txt)、删除文件或目录(RM)。但,诡异的是浏览(LS)文件或目录时,命令会被无限挂起,只能用 CTRL+C 强行中断。而 LINUX 系统下访问共享一切正常。
这究竟是什么原因导致的呢?其实我也是 HP-UX 菜鸟,虽然尝试过全网搜索 “nfs hang” 等关键词,但是没找到相关信息。走投无路之下,就只能硬肯 RFC 文档,通过 tcpdump 抓包,并用 WireShark 分析每一个网络包。
tcpdump 抓包
从图 2 中 info 一栏可以看到 WireShark 已经提供了详细的解析。不过这里我翻译成更直白的对话。
- mount -F nfs 192.168.0.200:/hxxt /nasdata(挂载共享目录)
包号 1 和 2(见图 2):
客户端:我想连接你的 NFS 进程,应该用哪个端口啊?
服务端:我的 NFS 端口是 2050
包号 3 和 4(见图 2):
客户端:那我试一下 NFS 进程能否连上。
服务端:收到了,能连上。
包号 7 和 8(见图 2):
客户端:我想连接你的 MOUNT 服务,应该用哪个端口啊?
服务端:我的 MOUNT 端口号是 2049 。
包号 11 和 13(见图 2):
客户端:那我试一下 MOUNT 进程能否连上。
服务端:收到,能连上。
包号 5 和 6(见图 2):
客户端:我要挂载 /hxxt 共享目录。
服务端:你的请求被批准了。以后请用 FileHandle:0xf2bf1c8c 来访问本目录(见图 3)。
包号 19 和 21(见图 2):
客户端:我想看看这个文件系统的属性。
服务端:给,都在这里。
以上便是 NFS 挂载的全过程。可以看到 Portmap 和 MOUNT 请求都得到及时响应,说明网络通畅服务正常。即然问题出在浏览文件或目录上(LS),那就应该检查该共享的访问控制。
- touch f.txt(root 用户创建一个新文件)
NFS 安全机制设置较为简单,对客户端的访问、对用户权限的控制,都是通过 IP 地址来实现的,创建共享目录时,可以指定哪些 IP 允许读写、哪些 IP 只允许读,还有哪些 IP 连挂载都不允许。
包号 42 和 43:(见图 4)
客户端:我要在路径 0xcc292702 内创建一个新文件,它的名字叫 f.txt。还有我的 UID: 0 ,GID:3 (见图 5)。
服务端:收到,允许创建。
图 5 的 Credentials 信息可知,客户端A用户创建文件时并未使用 root 这个用户名,而是用了 root 的 UID:0 来代表自己的身份(用户名与 UID 对应关系是由客户端 /ect/passwd 决定的)。也就是说 NFS 协议是用 UID 来区分用户的,当 root 通过客户端创建一个文件其 UID:0 就会被写到文件里,成为 owner 信息。
而当客户端B上的用户查看该文件属性时,看的其实也是 UID:0 。如果客户端B上的 /etc/passwd 文件和客户端A上的不一样,或显示客户端B对应的用户名称,或只显示 UID 数值,为了防止这类问题,建议用户和 UID 的关系在每台客户端上都保持一致。
- ls -al(查看所有文件或目录)
(图 6)
图 6 所示客户端能及时收到响应,查看响应包内容信息也正常。较为明显的是,明明我只执行了一次命令,而机器确不断重复发送、接收包,就如同进入“死循环”一样,这就不难解释在用户界面下,操作被挂起,直能通过 CTRL+C 强行中断操作了。
像福尔摩斯一样思考
神探福尔摩斯的破案秘诀是“逆因推理”——先观察所有细节,比如鞋根上的泥疙瘩甚至烟灰;然后作出多种推理和假设;接着刨去各种不可能,最后剩下的“无论多么难以置信,肯定没错。”用 WireShark 分析网络包时也类似,我们先要在网络包中寻找各种线索,然后根据网络协议作出推理,接着刨去人为(有意或无意)掩盖的证据,才能得到最后的真想。尤其是进不了机房,找不到文档,所以一切线索只能自己在包里找,感觉就更像破案了。
既然数据包正常。那最大嫌疑就是 LS 这个命令了。会不会是 LS 无法识别响应的数据包呢?我知道这种概率很小,但概率小不代表不会发生。LS 命令的操作和内核有关,而命令参数与返回值与字符串有关,字符串又和系统字符集有关,为了验证这种猜想,我使用 locale 命令,查询当前系统支持的所有字符集,并挑选 en_GB.utf8 设置为当前用户默认的字符集。
locale -a (查询到系统当前支持的字符集)
export LANG="en_GB.utf8"
故障排除!困扰了我数周的问题终于解决了!高兴啊!
注:我查看了一下 LINUX 的机器,它默认环境是使用 zh_CN.UTF-8,我初次将 HP-UX 也设置成和它一样的但故障依旧,通过设置成 en_GB.utf8 后正常。