如果DNS超时,使用getaddrinfo()只会首次检查nscdcaching

如果我得到一个初始的“名称或服务未知”(EAI_NONAME),下一次调用getaddrinfo()似乎直接进入dns,而不是首先检查caching(nscd日志显示没有查找尝试,tcpdump显示stream量到DNS服务器)。 如果第一次调用成功获取地址,那么所有getaddrinfo()调用都会按照预期先进入nscd。

我正在编译针对arm linux的glibc-2.13。 在我的rc.d中,nscd是在守护进程之前启动的。 nscd设置为禁止共享caching,并维护主机caching。 我正在使用busybox(0.47)的nscd。 设置nsswitch.conf以便主机检查caching/文件/ dns。 hosts.conf被设置为检查文件/绑定。

我的守护进程调用getaddrinfo()。

我有nscd运行的debugging日志,他们显示客户端开始读取DNS响应closures与“Broken Pipe”错误。

之后,它会显示尝试使用caching的其他守护进程的GAI尝试(所以我知道它不是nscdlocking或任何东西),但获得EAI_NONAME的守护进程永远不会再联系nscd做caching查找。

如果我重新启动守护进程, 如果第一个DNS查询再次超时,我会得到相同的行为。

glibc中是否存在使守护进程的链接无效的内容? 有没有办法重新连接我的守护进程到caching而不重新启动它(类似于通过res_init()强制resolv.conf重新加载?

正如alk在他的评论中提到的 ,重试getaddrinfo()超过100次应该强制nscd查询。


为了理解为什么,让我们快速浏览一下getaddrinfo()中的执行流程。

  1. getaddrinfo()调用gaih_inet 。

  2. gaih_inet()__nss_not_use_nscd_hosts执行以下操作:

    • 检查它是否是一个正整数?
    • 增加它。
    • 检查是否超过重试计数NSS_NSCD_RETRY

      – 只有在满足上述条件的情况下才尝试查询nscd。

    在尝试查询nscd时,计数立即重置为零,从而忽略nscd,以调用下一个NSS_NSCD_RETRYgetaddrinfo()

  3. 另外__nss_not_use_nscd_hosts在以下地方由nscd内部修改

    • nscd / nscd_gethst_r.c行178,189
      – 重置为1

    • nscd / nscd_getai.c第89,164行
      – 重置为1

    • nss / nsswitch.c,第709行
      – 设置为-1即禁用nscd。

基于上述,可以得出结论getaddrinfo()不会每次查询nscd。 另外,nscd的内部状态(由__nss_not_use_nscd_hosts决定)决定getaddrinfo()最终调用nscd。

为了在100次重试限制的范围内强制执行,可以修改NSS_NSCD_RETRY并重建libc以偏离标准行为。 但我不确定这是否会导致任何其他意想不到的回归。

参考:在getaddrinfo()中引入__nss_not_use_nscd_hosts逻辑的修补程序。