# 审核 Mac 在 10 分钟内从终端发送的内容

> 十分钟的 macOS 附带审核工具：lsof、nettop、日志流、scutil --dns、dig 和 tcpdump — 每一项实际显示的内容、确切的命令以及它们都无法告诉您的内容。

HisnLabs Security & Research Team · Published 2026-09-14
Canonical: https://hisnlabs.com/zh/blog/audit-mac-network-terminal

您无需安装任何东西即可获得 Mac 正在通话的真实当前图片。本实验室中的每个工具均随 macOS 一起提供。它们都不需要您信任第三方来处理您的流量，一旦您知道命令，这六个工具加在一起大约需要十分钟才能完成。他们不会做的，这一点很重要，就是告诉你哪些连接是好的，哪些是不好的——为此你仍然需要上下文，最后我们将诚实地告诉你这些工具的止点。

## 1. lsof — 现在每个打开的连接

在 Unix 上，网络套接字是一个文件，`lsof`（列出打开的文件）列出它们。 macOS 手册页将 `-i` 描述为选择互联网地址与给定规范匹配的文件 - 没有给定，每个互联网套接字。添加`-n`以跳过将地址解析为主机名，添加`-P`以跳过将端口解析为服务名称；两者都使命令更快并且输出精确而不是近似。

*终端 — 每个打开的网络套接字*

```console
$ sudo lsof -i -n -P
# example output, trimmed to a few representative lines
COMMAND   PID   USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
Mail      612   alice   9u  IPv4  0x...      0t0  TCP 192.168.1.10:54321->17.57.145.13:993 (ESTABLISHED)
Slack     980   alice  22u  IPv4  0x...      0t0  TCP 192.168.1.10:54400->35.186.224.25:443 (ESTABLISHED)
mDNSResp   88   root    4u  IPv4  0x...      0t0  UDP *:5353
```

从左到右读取：进程名称和PID、本地地址和端口、`->` 和远程地址和端口以及连接状态。 `ESTABLISHED` 表示当前处于活动状态的双向连接。在没有`sudo`的情况下运行，您仍然会看到自己的进程； root 拥有的需要它。这不能告诉您什么：`lsof` 是您按下 Enter 的那一刻的快照。在运行命令之前打开、发送几千字节并关闭半秒的连接根本不存在 - 您需要重复运行它，或者移至下一个工具，以捕获该连接。

## 2. nettop — 相同的视图，但实时

nettop 是同一想法的实时版本。它的手册页将其描述为显示“套接字或路由列表”以及定期更新的统计信息。 `-m route` 将其从列出套接字切换到列出路由表视图； `-m tcp` 或 `-m udp` 将其限制为一种协议。

*终端——实时连接，每秒刷新*

```console
$ nettop -m route
# interactive; press q to quit, or use -l N to print N samples and exit
# example output, trimmed
  time                     interface  state       bytes_in  bytes_out
23:41:02.123 Mail.612      en0        Established     4.2K      1.1K
23:41:02.123 Slack.980     en0        Established    18.6K      6.4K
```

添加 `-l 5` 以获取五个样本并退出，而不是保持交互式会话，如果您想将输出通过管道传输到某个地方，这很有用。 nettop 修复了 lsof 的快照问题——你可以观察连接的出现、传输数据并关闭——但它继承了相同的上限：进程名称和 PID，不知道谁签署了二进制文件，并且一旦关闭终端就没有内存。

## 3. 日志流——系统本身对网络的描述

macOS 保留每个进程正在执行的操作的统一、结构化日志，`log stream` 可让您实时观看并经过过滤。手册页将 `--predicate` 描述为使用 NSPredicate 样式子句针对子系统、类别、进程和消息内容进行过滤条目。

*终端 — 流式传输网络相关的日志条目*

```console
$ log stream --predicate 'eventMessage contains "network" or subsystem == "com.apple.network"' --info
# live stream; Ctrl-C to stop. Example line, trimmed:
2026-09-14 23:41:05.001 process=nesessionmanager subsystem=com.apple.network "TCP Connection ... state changed to Ready"
```

这是六个工具中最难接近的一个——体积很大，谓词语法有一个学习曲线——但它也是唯一一个以简单的英语显示系统级网络状态变化和连接生命周期事件，并由负责的子系统标记的工具。将其视为 grep 的内容，而不是逐行读取：通过 `grep` 传递您关心的进程名称，或者像 `"Wi-Fi"` 或 `"VPN"` 这样的关键字。

## 4. scutil --dns 和 dig — 您的 Mac 实际解析的内容

在建立连接之前，通常会进行 DNS 查找。 `scutil --dns`，根据其手册页，“报告当前的 DNS 配置”：配置了哪些解析器、默认解析器以及仅适用于特定域（分割 DNS，在 VPN 上常见）。

*终端 — 当前 DNS 解析器配置*

```console
$ scutil --dns
# example output, trimmed
DNS configuration
resolver #1
  nameserver[0] : 192.168.1.1
  if_index : 12 (en0)
  flags    : Request A records, Request AAAA records
  reach    : 0x00020002 (Reachable,Directly Reachable Address)
```

`dig` 直接回答一个问题：这个名称现在解析为什么。它的手册页称其为“用于询问 DNS 名称服务器的灵活工具”，其价值在于“灵活性、易用性和输出的清晰度”。

*终端 — 解析单个主机名*

```console
$ dig example.com +short
# example output
93.184.216.34
```

这两种工具都不会告诉您哪个应用程序触发了查找或之后发生了什么 - DNS 只能为您提供应用程序即将（或已经连接）连接的地址；连接本身是 lsof、nettop 或防火墙日志向您显示的内容。

## 5. tcpdump — 基本事实，以及需要 sudo 的事实

上面的所有内容都读取操作系统已经保存的状态。 `tcpdump` 是不同的：它直接从接口捕获数据包，这就是为什么它自己的文档直接说明了要求 - “从网络接口读取数据包可能需要您拥有特殊权限” - 实际上，在 macOS 上为 `sudo`。使用`-i`来选择接口，使用`-n`来保持地址数字，并使用`port 53`这样的过滤器表达式来隔离DNS流量：

*终端 — 观察 DNS 查询离开机器*

```console
$ sudo tcpdump -i en0 -n port 53
# example output, trimmed
23:41:10.221331 IP 192.168.1.10.54812 > 192.168.1.1.53: 41213+ A? example.com. (30)
23:41:10.244109 IP 192.168.1.1.53 > 192.168.1.10.54812: 41213 1/0/0 A 93.184.216.34 (46)
```

> **Warning:** 这需要提升权限，因为它直接从网络接口读取数据包——原则上，如果您扩大过滤器或完全丢弃它，相同的访问级别可以捕获比 DNS 多得多的数据包。保持过滤器狭窄，运行一小段时间，完成后关闭终端。不要让广泛的、未经过滤的捕获在无人看管的情况下运行。

需要注意的模式：在端口 53 上发出查询后立即返回答案。如果您在一个终端中运行 `dig`，而 `tcpdump` 在另一个终端中运行，您可以观看您自己的命令生成的确切查询和响应 - 这是真正相信手册页内容而不是相信它们的好方法。

## 第七个免费工具：活动监视器

值得在此列表中命名一个图形选项，因为并非所有东西都需要终端。活动监视器的“网络”选项卡为您提供总计 - 每个进程发送和接收的数据，以及实时吞吐量图 - 这是“某些东西正在占用带宽但我不知道是什么”的正确第一站。这也是本文中每个工具所共有的上限的最清晰说明：它可以告诉您辅助进程一夜之间移动了 2 GB，并且它没有列说明这 2 GB 的去向。音量和目的地是两个不同的问题，macOS 使用两种不同的工具来回答它们。

## 把这十分钟放在一起

1. `sudo lsof -i -n -P` — 获取当前打开的套接字列表，一次通过，三十秒。
2. `nettop -m route -l 5` — 获取一些实时样本以捕捉 lsof 快照遗漏的任何内容。
3. `scutil --dns` — 确认您实际使用的解析器，尤其是当您使用 VPN 或公共 Wi-Fi 时。
4. `dig <name> +short`，对步骤 1 中任何不熟悉的内容，查看它当前解析的内容。
5. `sudo tcpdump -i en0 -n port 53`，六十秒，在应用程序运行其业务时观察原始的 DNS 流量。
6. `log stream --predicate` 带有关键字 grep，如果上面的内容提出了前五个没有回答的问题。

## 一个有效的例子

假设步骤 1 出现了一个名为 `helperd` 的进程，该进程持有与您不认识的地址的开放连接。不要停在那里。运行 `dig -x <the address>` 进行反向查找 — 它并不总是解析为可读的内容，但当它解析时，像 `ads.example-cdn.net` 这样的主机名会在五秒内告诉您比原始 IP 更多的信息。运行 `nettop -m tcp -l 3` 并观察同一连接在几秒钟后是否仍然打开，以及字节是否实际在其中移动或处于空闲状态。如果它空闲并以固定的时间间隔重新打开，那就是定期签入而不是一次性传输的形式 - 值得记住，而不是自动值得担心，因为普通更新检查器的行为方式相同。然后检查 `scutil --dns` 以确认生成连接到 `helperd` 的任何地址的解析器是您期望的地址，尤其是当您使用其他人的 Wi-Fi 时。五个命令，一个过程，你就从“我不认识这个”变成了“这是我所知道和不知道的具体内容”——这是这样的审计的实际目标，而不仅仅是好或坏的判断。

## 这些工具都不会告诉你什么

跑完所有六个，你仍然有三个真正的差距。首先，除了进程名称之外的身份：这里没有任何内容检查名为“Mail”的二进制文件是Apple的Mail还是重命名的东西，或者它是否完全签名 - 这是使用`codesign`和`spctl`进行单独的查找。其次，记忆：一旦终端窗口关闭，你学到的一切也会消失；除非您自己构建一个，否则不会有“上周二我的 Mac 连接到什么”的日志。第三，判断：这些工具都没有关于是否预期连接的意见。连接到以前从未使用过的地址的笔记应用程序在 `lsof` 中看起来与连接到其常用同步服务器的笔记应用程序完全相同 - 区分这两者的方法是您必须自带模式识别功能，或者必须为您提供工具。

## FireAI 和 HisnLabs 在其中扮演的角色

Everything in this lab is free and built into macOS, and none of it names the process behind a connection or remembers it after the terminal closes — which is the specific, narrow gap FireAI’s per-app rules and connection history are built to close.

FireAI 是 HisnLabs 自己的产品：一款直接在 Mac 上运行的 AI 防火墙。它用通俗易懂的语言显示你的应用建立的每一个连接，并让你决定哪些数据可以离开你的 Mac——它的 AI 在本地运行，因此你的流量永远不会发送给我们或任何其他人。HisnLabs 的安全研究团队负责让这些判断保持准确：归类哪些域名只是普通的遥测、哪些属于真正的服务，追踪连接背后的国家和网络，并用真实的流量模式训练设备端模型（FireAI Pilot 功能）——这一切都不会离开你的 Mac。

你可以阅读它背后的技术决策，或试用 FireAI 17 天：[HisnLabs 出品的 FireAI](https://hisnlabs.com/fireai/zh/download)。

## Sources

- [SS64: lsof man page for macOS](https://ss64.com/mac/lsof.html)
- [nettop(1) man page (Xcode man pages mirror)](https://keith.github.io/xcode-man-pages/nettop.1.html)
- [log(1) man page (Xcode man pages mirror)](https://keith.github.io/xcode-man-pages/log.1.html)
- [scutil(8) man page (Xcode man pages mirror)](https://keith.github.io/xcode-man-pages/scutil.8.html)
- [dig(1) man page (Xcode man pages mirror)](https://keith.github.io/xcode-man-pages/dig.1.html)
- [SS64: tcpdump man page for macOS](https://ss64.com/mac/tcpdump.html)
