> For the complete documentation index, see [llms.txt](https://freebsd-journal-cn.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://freebsd-journal-cn.bsdcn.org/20190304-tiao-shi-yu-ce-shi/excess-ldap-connection-using-dtrace.md).

# 用 DTrace 排查 LDAP 连接过剩

我管理着我们计算机科学系的大数据集群，最近遇到了一个有趣的问题，并用 DTrace 完成了诊断。以下是事情经过。

我为实验练习搭建了几台学生可访问的 FreeBSD 机器。学生通常通过 SSH 与 PAM 组合登录分配给他们的集群机器，并向系里的 LDAP 服务器进行身份认证。LDAP 服务器提供学生所需的全部信息，比如校验密码是否正确、家目录在哪里、用什么 shell。对于某些系统，不允许学生访问。这些节点在 **/etc/ssh/sshd\_config** 中有一行 `AllowedUsers`，列出允许登录的账户。这套设置已正常运行多个学期，并集成到安装脚本中，让用户从系统安装之初就能登录。

学期中间的某一天，我办公室的电话响了。IT 部门的同事告诉我，他们从大数据集群子网收到了大量打到两台 LDAP 服务器的请求。他给了我几个在日志中出现最频繁的 IP 地址。有些机器每秒发起多次请求——而正常情况下这个数字应该小得多。这显然不正常，不该有这么高的频率。挂断电话后，我把排查范围集中到他提到的几台机器上。一份简短的“问题机器”清单是个不错的起点，给了我聚焦调查的素材，也便于和表现正常的系统做对比。

我先做了几项基础检查：是否有不该运行的进程在运行？是否同时有太多学生在使用机器，从而产生大量网络请求？两个答案都是否定的，因为我是当时唯一登录系统的人。**top(1)** 和 **ps(1)** 的输出中只显示了预期的实验软件。接着运行 **netstat(1)** 也没有显示异常连接或开放端口，除了本该开放的那些。其他几台问题机器情况相同，于是我需要更深入地排查。

我知道问题多少与 LDAP 服务器和连接到它们的主机上运行的某种软件有关。但究竟是什么应用（第三方软件还是操作系统自带）？我又该如何统计每个应用连到 LDAP 服务器的连接数？我当然可以运行 **tcpdump(1)** 一会儿，观察流向 LDAP 服务器的流量，但要弄清楚发起方的应用就要费更多功夫。我查阅了 FreeBSD wiki 上的 DTrace 单行命令（<https://wiki.freebsd.org/DTrace/One-Liners>），找到一个能列出本机连到远程 IP 地址连接数的脚本。

运行几秒钟后停止跟踪，输出是两列。第一列显示外部 IP 地址，第二列按升序列出跟踪期间建立的连接数。这很有用，我看到两台 LDAP 服务器的 IP 地址位列其中，而且在短短的跟踪时间内连接数确实很高。随着时间推移，这些计数不断增长，DTrace 单行脚本运行越久，触发的探针就越多。并非每个程序每秒都在建立连接。让脚本运行几分钟，能更好地了解情况。唯一缺少的信息是发起请求的实际应用。我把脚本扩展了一下，让它同时给出可执行文件名（在 DTrace 术语中称为 execname）：

```sh
sudo dtrace -n 'tcp:::send { @[args[2]->ip_daddr] = count(); }'
sudo dtrace -n 'tcp:::send { @[execname, args[2]->ip_daddr] = count(); }'
```

输出现在有三列：第一列是发起连接的程序或进程名（比如 sshd 或 sudo）。第二、三列与之前的跟踪相同。由于我知道要找的目标 IP 地址（两台 LDAP 服务器之一），还可以更精细地过滤：

```sh
sudo dtrace -n 'tcp:::send {@[execname, args[2]->ip_daddr == "IP.address.LDAP.server"] = count(); }'
```

看输出时，一个问题浮现：为什么 ssh 守护进程会向我们的 LDAP 服务器发送这么多 TCP 流量？当然，我们是在 SSH 会话中运行这个脚本，这意味着相当一部分流量可能由我们运行脚本本身产生。我停止跟踪，从 SSH 会话退出。从服务器控制台登录后，我用 **w(1)** 确认自己仍是当前唯一登录的用户。然后我重新运行跟踪。出乎意料，sshd 仍建立了大量连接，即便当时没有人在使用 SSH 会话。

与系统上其他进程相比，sshd 的连接数位居第二，而连接数最多的是到本地服务器 IP 地址的连接。这没什么问题，也没造成任何麻烦，但为什么在没有人主动使用 SSH 会话时，会持续不断地向两台 LDAP 服务器 IP 发起请求？再往下看，引起我注意的另一个进程是 sudo。当然，我用 sudo 运行脚本，于是我再次停止跟踪，改用 root 用户身份重复一遍。和之前一样，sudo 的连接数并未减少。

ssh 和 sudo 都在使用 LDAP 服务器——前者用于让特定用户登录系统，后者用于授予权限执行某些本地特权操作。记得我使用这套配置已有多年，但直到最近才收到 IT 部门关于这些连接的投诉。这次跟踪只显示了一台机器的情况，可以想象这个子网（至少 40 台配置相同的 FreeBSD 和 Linux 节点）总共向 LDAP 服务器发起多少请求。显然，这必须解决，否则这些机器面临被永久封禁网络的风险——在学期中间学生和研究人员正使用这些机器做实验时，这可不是什么好消息。

与 IT 部门商议后，他们建议我启用 **nscd(8)**，即名称服务缓存守护进程。思路是用缓存服务从本地缓存返回结果，而不是每次请求都直接联系 LDAP 服务器。由于 LDAP 服务器返回的信息不会经常变化，本地缓存应该能减轻服务器负载，也会提升本地请求查询的性能。阅读 FreeBSD 上 nscd、nscd.conf 和 nsswitch.conf 的相关 man 页后，我用以下命令启用了 nscd：

```sh
# sysrc nscd_enable=yes
```

启动 nscd 服务前，我在 **/etc/nsswitch.conf** 中加入“cache”语句，使其变成这样：

```ini
group: cache files ldap
hosts: cache files dns
networks: cache files
passwd: cache files ldap
passwd_compat: nis
shells: files
services: compat
services_compat: nis
protocols: files
rpc: files
```

默认的 **/etc/nscd.conf** 已经启用了几乎全部缓存，无需修改这个文件。然后用以下命令启动 nscd 服务：

```sh
# service nscd start
```

我在被报告为 LDAP 服务器最主要“滥用者”的服务器上启用它。然后，因为还有其他工作要忙，我没有运行第二次跟踪来确认启用 nscd 后请求数量是否减少。一周半时间过去了，我没再多想。这里有个教训：在转向其他事情之前，先确认问题已解决。过一段时间再把思路切回某个问题是困难的。

在我的情况里，问题在我没上班时再次爆发。周三上午，我们的 IT 部门切断了整个大数据集群的网络，因为对 LDAP 服务器的请求数量严重到被怀疑是内部拒绝服务攻击。这导致那天早上使用集群节点的一个实验小组失去访问权限。直到带队的教授——他对网络封锁毫不知情——向 IT 部门提交工单求助，他们才恢复了网络。实验小组又能工作了，但问题仍未解决（当然，投诉也堆进了我的收件箱）。高峰时段，单个 IP 就占了到 LDAP 服务器总流量的 12.5%。情况不妙，必须尽快找到解决方案。

显然，nscd 并未如预期那样解决问题，我不得不重新分析。在网上搜索其他人可能遇到的类似问题时，我没有找到与我的问题直接相关的内容。不过，我找到了一些关于 pam\_ldap 的讨论，这正是我在集群节点上用来连接 LDAP 服务器的客户端。原来，FreeBSD 的这个 Port 自 2016 年 4 月 1 日起就没有收到过任何更新，而且据一些用户反映，这个软件从一开始就设计得很糟糕。有人推荐了由 Arthur de Jong 编写并维护的替代客户端：nss-pam-ldapd（<https://arthurdejong.org/nss-pam-ldapd/>）。

在 **/usr/ports/net/nss-pam-ldapd** 下的 Port 描述（`cat pkg-descr`）中，除其他事项外还列出了”less connections to the LDAP server”。这听起来正是我要找的，于是我在产生大量请求的某台集群节点上做了测试安装。

nss-pam-ldapd 软件不仅完全从头设计，并与名为 nslcd 的本地缓存服务集成，而且文档完善。此外，该软件持续维护，FreeBSD Port 的最近一次更新是在 2018 年 11 月——也就是本文撰写之时。这些改动无需重启系统即可实施。一句警告：**/etc/pam.d** 或 **/etc/nsswitch.conf** 中的文件出错可能让你被系统锁在外面，连 root 用户也不例外。发生这种情况时，需要在单用户模式或使用 live CD 修复。

改动落实、nslcd 服务启动后，我再次运行 DTrace 脚本。在第一列中我看到 nslcd 连接 LDAP 服务器的条目（之前我已停用 nscd，因为它没起作用）。现在由这个缓存守护进程发起调用，向本地服务（sudo 和 ssh）提供所需信息。DTrace 输出中到 LDAP 服务器的连接数大幅下降。在服务器一侧，IT 部门也确认流量已恢复正常水平。不必说，我在其他所有机器上都部署了 nss-pam-ldapd 服务和 nslcd。我还更新了安装脚本，在系统安装时使用 nss-pam-ldapd 替代 pam-ldap。注意，还有一个支持 SASL 的版本，名为 nss-pam-ldapd-sasl。

这次排查令人愉快的一点是，我几乎不用自己费神去写 DTrace 探针。我可以直接从 FreeBSD wiki 上的 DTrace 单行命令库（<https://wiki.freebsd.org/DTrace/One-Liners>）中取用。那里已经有一些现成的、开箱即用的单行命令，覆盖存储、网络、系统调用等多个领域。稍加修改，就能构造出提供所需信息的探针，帮助诊断更棘手的问题。 •

***

**BENEDICT REUSCHLING** 于 2009 年加入 FreeBSD 项目。2010 年获得完整文档提交权限后，他积极指导他人成为 FreeBSD 提交者。他于 2015 年加入 FreeBSD 基金会，现任副总裁。Benedict 拥有计算机科学理学硕士学位，在德国达姆施塔特应用技术大学教授面向软件开发者的 UNIX 课程。他与 Allan Jude 共同主持每周的 BSDNow\.tv（<http://BSDNow.tv）播客。>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://freebsd-journal-cn.bsdcn.org/20190304-tiao-shi-yu-ce-shi/excess-ldap-connection-using-dtrace.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
