![如何排除 Linux 内核 dns_resolver 故障](https://linux22.com/image/610362/%E5%A6%82%E4%BD%95%E6%8E%92%E9%99%A4%20Linux%20%E5%86%85%E6%A0%B8%20dns_resolver%20%E6%95%85%E9%9A%9C.png)
Linux 提供了一种功能,允许内核及其模块通过用户空间工具来解析 DNS 名称。例如,CIFS 使用此功能来支持 DFS 中的引用。
我看到的问题是我无法让内核解析特定的 DNS 名称,而且我不明白它为什么会失败。
为了了解根本原因,我通过运行以下命令在 CIFS 和内核 DNS 解析器中启用了调试输出:
echo "1" > /sys/module/dns_resolver/parameters/debug # dns_resolver
echo "7" > /proc/fs/cifs/cifsFYI # CIFS
以下是发生故障时我在 dmesg 中看到的内容:
fs/cifs/cifs_dfs_ref.c: DFS: ref path: \ESOTEST\dfstest\FS_SERV
fs/cifs/cifs_dfs_ref.c: DFS: node path: \FS\FS_SERV
fs/cifs/cifs_dfs_ref.c: DFS: fl: 2, srv_type: 0
fs/cifs/cifs_dfs_ref.c: DFS: ref_flags: 0, path_consumed: 24
fs/cifs/netmisc.c: address conversion returned 0 for FS
fs/cifs/netmisc.c: address conversion returned 0 for FS
[ls ] ==> dns_query((null),FS,2,(null))
fs/cifs/dns_resolve.c: dns_resolve_server_name_to_ip: unable to resolve: FS
fs/cifs/cifs_dfs_ref.c: cifs_compose_mount_options: Failed to resolve server part of \\FS\FS_SERV to IP:
-22
这是成功解析的输出:
fs/cifs/cifs_dfs_ref.c: DFS: node path: \ESOTEST\File-Server
fs/cifs/cifs_dfs_ref.c: DFS: fl: 2, srv_type: 0
fs/cifs/cifs_dfs_ref.c: DFS: ref_flags: 0, path_consumed: 28
fs/cifs/netmisc.c: address conversion returned 0 for ESOTEST
fs/cifs/netmisc.c: address conversion returned 0 for ESOTEST
[ls ] ==> dns_query((null),ESOTEST,7,(null))
[ls ] call request_key(,ESOTEST,)
[ls ] ==> dns_resolver_match(ESOTEST,ESOTEST)
[ls ] <== dns_resolver_match() = 1
[ls ] <== dns_query() = 14
fs/cifs/dns_resolve.c: dns_resolve_server_name_to_ip: resolved: ESOTEST to 192.168.56.102
fs/cifs/cifsfs.c: Devname: \\ESOTEST\File-Server flags: 0
我使用 Windows 作为 DNS 服务器,并且可以从机器解析名称“FS”:
$ ping FS
PING FS.esodomain.com (192.168.56.104) 56(84) bytes of data.
64 bytes from fs.esodomain.com (192.168.56.104): icmp_seq=1 ttl=128 time=1.37 ms
64 bytes from fs.esodomain.com (192.168.56.104): icmp_seq=2 ttl=128 time=0.630 ms
我也尝试过使用 key.dns_resolver 手动执行测试,它似乎有效:
$ key.dns_resolver -vv -D "FS" 'hello'
I: Key description: 'dns_resolver;-1;-1;0;FS'
I: Callout info: 'hello'
D: Get A/AAAA RR for hostname:'FS', options:'hello'
D: Opt hello
D: Resolve 'FS' with 1ff
D: getaddrinfo = 0
D: RR: 0,2,1,6,10,(null)
D: append '192.168.56.104'
I: The key instantiation data is '192.168.56.104'
/etc/request-key.conf 的内容为:
create dns_resolver * * /sbin/key.dns_resolver %k
create user debug:* negate /bin/keyctl negate %k 30 %S
create user debug:* rejected /bin/keyctl reject %k 30 %c %S
create user debug:* expired /bin/keyctl reject %k 30 %c %S
create user debug:* revoked /bin/keyctl reject %k 30 %c %S
create user debug:loop:* * |/bin/cat
create user debug:* * /usr/share/keyutils/request-key-debug.sh %k %d %c %S
negate * * * /bin/keyctl negate %k 30 %S
我之所以摆弄这个,是因为我试图成功挂载 Windows DFS 共享。我能够挂载和访问托管在根服务器上的文件夹,但是当我尝试访问指向外部服务器的子文件夹时,我得到:
ls: cannot access /mnt/dfstest/FS_SERV/: Invalid argument
我使用的是 3.7.10 内核:
Linux gentoo 3.7.10-gentoo-r1 #3 SMP Fri Apr 19 17:32:20 PDT 2013 x86_64 Intel(R) Xeon(R) CPU E5620 @ 2.40GHz GenuineIntel GNU/Linux
在网络捕获中,我没有看到任何针对“FS”的 DNS 请求,但我看到了针对“ESOTEST”的请求。这表明该请求从未发出过。
您建议采取哪些后续步骤来解决此问题?
答案1
这似乎是由 Linux 内核引起的。具体来说,是由 dns_resolver 引起的。“FS”甚至没有尝试解析。
dns_resolver(net/dns_resolver/dns_query.c)中的以下几行似乎导致了这种情况:
if (namelen < 3)
return -EINVAL;
我不知道为什么要进行此项检查。我将尝试将另一台服务器的名称从“FS”重命名为更长的名称。我将尝试重新编译内核并删除此项检查。
更新:是的,这就是原因,将主机名重命名为更长的名称后即可正常工作
答案2
还,显然内核 dns_resolver 不遵守 TTL。 清除内核的 DNS 缓存:
sudo keyctl clear $((16#$(sudo cat /proc/keys | grep .dns_resolver | awk '{print $1;}')))