跳转到内容
GitHub

网络

Alt-N 或 命令 → 网络 会显示这台机器在网络上的活动:哪些端口开放、谁能访问它们,哪些进程在通信、速度多快,每一个连接,以及各个网络接口。它来自内置的系统插件,与进程监视器一样。列表占据当前窗格,另一个窗格详细显示所选行,并附有最近 60 秒的图表。屏幕打开期间,Borg 每秒采样一次,关闭后即停止。速率从第二次采样开始显示,每个速率都是最近 3 秒的平均值,因此按流量排序的列表能保持稳定,让你有足够的时间阅读。

按 1 到 4 或点击标签页即可切换页面:

  • 1 端口 列出进程监听的每个端口,按端口号排序。可访问范围 说明谁可以连接:在所有地址上开放的端口显示 所有网络,绑定到指定地址的端口显示该地址,只有本机程序能访问的端口显示 仅本机。对所有网络开放的端口会突出显示,因为其他机器可以发现它们。连接 统计通过该端口进入的连接,详细信息会列出这些连接及其流量。
  • 2 进程 列出使用网络的进程,最繁忙的排在最前,并显示下载和上传速率以及连接数。详细信息还会显示自屏幕打开以来该进程传输的数据量,以及它持有的每个连接。
  • 3 连接 列出每个连接及其进程、对端和速率。窗格较宽时还会显示协议和 TCP 状态。详细信息显示两端地址、主机名、服务,以及收发的字节数。
  • 4 接口 列出网络接口及其类型(Wi-Fi、以太网、回环、隧道、网桥 或 虚拟)、第一个地址和速率。● 表示接口已启用。详细信息还会显示所有地址、MTU、接口迄今收发的字节数和数据包数,以及错误数。

底部显示本机除回环接口外所有接口的下载和上传总速率。Borg 会在后台查询远程地址的名称,一旦得知,就用名称代替地址显示。

按键 操作
1 / 2 / 3 / 4 显示端口 / 进程 / 连接 / 接口
/ 筛选行;↑↓ 仍可移动,Enter 保留筛选条件,Esc 清除筛选条件
T / N / P / C 按流量 / 名称 / 端口 / 连接数排序;再按一次则反向排序
Enter 在进程监视器中显示所选行的进程
K 显示该进程并打开 信号或优先级
R 抓取所选行的流量,或停止正在进行的抓包
Ctrl-C 复制端口的地址、PID、对端地址或接口的地址
Tab 在列表和详细信息之间切换
Space 暂停或恢复采样
Alt-W 最大化当前焦点所在的窗格
Esc 返回列表,然后关闭屏幕或回到进程监视器

P 用于有端口的页面,C 用于统计连接数的页面。点击列标题可按该列排序,双击某一行可显示其进程。在没有进程的行上按 Enter 会进入详细信息。这里的行只指明进程,没有程序文件,因此按 Alt-O 会提示你先按 Enter,再在进程监视器中按 Alt-O。Enter 和 K 打开的进程监视器中已选中该进程,因此只需一个按键就能查看它的内存、发送信号或调整优先级(参见信号和优先级)。在那里按 Esc 会回到网络屏幕,停在你离开时的那一行,图表也都还在。

反过来也可以。在进程监视器中按 Alt-N,会在 2 进程 页上打开所选进程所在的行,详细信息中显示它的流量和连接,按 Esc 则回到监视器。如果该进程没有连接,也没有打开的端口,会出现提示说明这一点。

筛选会保留与你输入的所有词语都匹配的行。普通词语会匹配进程、PID、端口、服务、地址、主机名、状态、协议或该行显示的标签,因此 postgres、5432、https 和 example.com 都可以使用。带字段名的词语只在该字段中查找:

词语 保留
port:443、port:ssh 使用该端口号或服务的行
proc:node、process:node 进程名包含该文本的行
pid:4100 该 PID 的行
host:example 地址或主机名包含该文本的行;完整的地址只保留该地址
state:listen、state:time 状态名包含该文本的 TCP 行
proto:udp、proto:tcp 该协议的行
if:en0、interface:en0 名称包含该文本的接口

在词语前加 ! 可排除与之匹配的行:!state:time_wait 会隐藏正在关闭的连接,!proc:browser 会隐藏某个程序。筛选对所有页面生效,输入时会显示当前页面保留了多少行。

按 R 用 tcpdump 录制所选行背后的数据包。macOS 自带它,Linux 可以从 tcpdump 软件包安装。抓取流量 对话框从这一行开始:

  • 流量 决定 tcpdump 保留什么。在 1 端口 上是该端口以及从它进来的连接,在 3 连接 上是这一条连接的双向流量。在 2 进程 上则是“全部流量,按该进程显示”:tcpdump 无法按进程挑选数据包,所以 Borg 录制整个接口,再在该进程上打开结果。第二个选项始终是 接口上的全部流量。
  • 接口 默认是该行地址所在的接口,没有时则是最繁忙的接口。
  • 时长 可选 5、10、30 或 60 秒,或 直到停止。
  • 保留 默认为 每个连接的前 1 MiB:每个会话的数据包在携带满 1 MiB 数据之前保持完整,之后 Borg 只保存它们的头部。短请求保持完整,长时间的下载或视频通话也不会让文件变大。完整数据包 保存全部内容,仅头部,每个数据包的前 128 字节 只保存每个数据包的开头,文件最小。Borg 在写入文件时裁剪数据包,文件仍是普通的 pcap 或 pcapng,每个被裁剪的数据包仍记录它在线路上的长度。
  • TLS 密钥 可选 关闭、在 Borg 的 Shell 中设置 SSLKEYLOGFILE 或 通过 Borg 代理 HTTPS,使用临时 CA。第二项会记录抓包期间你启动的程序的 TLS 密钥,第三项用于不写密钥的程序(参见解密 TLS)。
  • 运行身份 在 Borg 能请系统索要管理员密码时出现。当前用户 以你的身份运行 tcpdump,管理员 则在你于系统对话框中输入密码后以 root 身份运行它。在 macOS 上,这个选项显示为 管理员,并记录每个数据包的进程:tcpdump 会通过 macOS 的 pktap 监听,它会为每个数据包标记发送或接收它的进程。

↑↓ 选择字段,←→ 或 Space 更改字段,Enter 开始抓包,Esc 取消。使用鼠标时,单击字段选中它,再单击一次更改它。抓包进行时,底部一行显示已抓到的数据包数、字节数和剩余秒数,按 R 可以提前停止。抓包在达到 200,000 个数据包或 256 MiB 时也会停止;磁盘写满时也会停止,并保留已经保存的内容。如果要给系统的其他部分留出空间,请设置 keep-free-mib,它位于配置文件的 [network] 部分:这样一来,如果文件夹所在磁盘的可用空间少于这么多 MiB,抓包不会开始;可用空间降到这个值以下时,抓包会停止。开始 3 秒后,底部一行会按目前的速率显示最先到达的限制还有多久,例如 约 30 秒后达到 256 MiB 或 约 2 分钟后达到磁盘空间上限,前提是它早于抓包本身的结束时间,并且在一小时之内。如果抓包因限制而停止,会有通知说明是哪一个限制。如果先关闭了屏幕,抓包会停止,并有通知告诉你 Borg 把它保存在哪里。

Borg 把每次抓包保存为 capture-<date>-<time>.pcap,放在网络屏幕所覆盖面板的文件夹中,只有你可以读取,之后 Wireshark 等工具也能打开它。为每个数据包标记进程的抓包会保存为 capture-<date>-<time>.pcapng,因为这种格式可以携带这些标记。记录了 TLS 密钥的抓包在 Borg 把密钥放进去后也会保存为这种格式。抓包文件包含数据包携带的一切内容,请像保管这些数据本身一样妥善保管它。每次抓包也会记入 Borg 的文件 中的列表。

通过 borg mcp 连接的智能体也可以请求抓包,抓包同样会等待你批准(参见智能体能做什么)。

抓包结束后,流量查看器取代实时页面,每种查看方式各有一页:

  • 1 进程 显示每个进程及其通信过的主机、数据包和字节数。数据包带有进程信息时,每个数据包都属于发送或接收它的进程。这样,即使一个进程只运行了不到一秒,也能显示它的名称,而按进程筛选时只保留它自己的数据包。否则,一个会话属于抓包期间持有其套接字的进程,其余归入 未知进程。
  • 2 主机 显示其他机器以及看到的协议。名称来自抓包中的 DNS 应答和 TLS 连接请求的服务器名称,所以大多数主机都有名称。
  • 3 连接 显示每个会话及其进程、另一端、协议、数据包和字节数。详情显示两端、服务器名称、服务、发送和接收的字节,以及会话的数据流:双方发送的内容按顺序还原,重传的字节只算一次,以十六进制转储显示,旁边是可打印为文本的字节。数据流按轮次分段,每一轮带有表示方向的箭头、所含字节数和到达时间。如果某一轮之前有抓包缺失的字节,这一轮会注明缺了多少。如果抓包只保留了连接的开头,数据流的标题会按数据包头部的记录注明之后未保存的字节数。] 和 [ 跳到下一轮和上一轮。F3 在查看器中以十六进制行打开整个数据流,各轮依次相接,便于在那里翻页和查找。Enter 逐个显示该会话的数据包。当 Borg 拥有该连接的 TLS 密钥时,数据流会显示其加密记录所携带的内容(参见解密 TLS)。
  • 4 数据包 按顺序显示所有数据包,包括从开始算起的时间、协议、长度和摘要,例如 ClientHello example.com 或 A example.com → 203.0.113.10。详情显示它的各层(Ethernet、IP、TCP 或 UDP,以及 Borg 能读取的 DNS、TLS 或 HTTP)和十六进制转储形式的字节。转储的字节排列方式与查看器的十六进制行相同,每行显示窗格能容纳的最多字节数。F3 在查看器中以十六进制行打开该数据包的字节。
按键 操作
1 / 2 / 3 / 4 显示进程 / 主机 / 连接 / 数据包
Enter 向下一层:从进程或主机到它的连接,从连接到它的数据包,从数据包到它的详情
] / [ 在连接的详情中跳到数据流的下一轮或上一轮
/ 筛选行,与实时页面相同
Ctrl-C 复制 PID、地址、另一端,或以十六进制复制数据包的字节
F3 在查看器中以十六进制行打开连接的数据流或数据包的字节
Tab 在列表和详情之间切换,详情中用 ↑↓ 滚动
Esc 回到列表,然后返回上一层,然后清除筛选,然后回到实时屏幕

筛选支持与实时页面相同的词,proto: 还能匹配 Borg 在数据包中识别出的协议:proto:dns、proto:tls、proto:http 和 proto:quic。筛选作用于所有页面,Enter 向下一层时会设置筛选,所以 Esc 可以一步步退回。

在面板中对 .pcap、.pcapng 或 .cap 文件按 F3,会在同一个查看器中打开它,并从 2 主机 开始。在别处录制的文件没有可匹配的套接字,所以其中的会话显示为 未知进程。如果 .pcapng 文件中的数据包带有进程信息(Borg 和 tcpdump -i pktap 在 macOS 上保存的文件就是这样),每个进程仍会显示名称。查看器最多读取 256 MiB 的文件及其前 200,000 个数据包。

如果 Borg 找不到 tcpdump,抓包会提议安装它。安装 tcpdump 对话框显示 Borg 找到的包管理器所用的确切命令:Linux 上是 apt-get、dnf、pacman、zypper 或 apk,macOS 上以及没有这些包管理器的 Linux 上是 Homebrew 的 brew。系统的包管理器通过 sudo 运行,或者改用 doas(在没有 sudo 的系统上);Borg 以 root 身份运行时则直接运行。Enter 把命令输入 Borg 的 Shell,你会在那里看到它的执行过程,并亲自输入密码;Esc 取消。命令结束时,通知会说明是否成功,Ctrl-O 显示它的输出。每次开始抓包时,Borg 都会在 PATH 以及 /usr/sbin、/usr/bin、/sbin、/bin 和 Homebrew 的 sbin 文件夹中重新查找 tcpdump,所以安装一结束,R 就能抓包。如果没有 Borg 认识的包管理器,抓包会结束并显示 抓包需要 tcpdump,但 Borg 找不到它。

tcpdump 需要访问抓包设备。Borg 以你的身份运行它,所以请为自己授权一次:

  • 在 macOS 上,起初只有 root 能打开 /dev/bpf 设备。安装一次带 ChmodBPF 组件的 Wireshark:它会把这些设备交给 access_bpf 组并把你加入该组,此后你就可以在所有接口上抓包。
  • 在 Linux 上,用 sudo setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump 给 tcpdump 一次性授予抓包能力。有些发行版也允许 pcap 或 wireshark 组的成员抓包。

没有权限时,如果系统能够索要你的密码,Borg 会询问 以管理员身份抓包:在 macOS 上使用系统自己的密码对话框,在 Linux 上通过 pkexec,其对话框由你的桌面环境提供。选择“是”,然后在系统对话框中输入密码,Borg 始终看不到它。对话框打开期间,底部一行显示 正在等待输入密码 以及接口名称。随后 Borg 以 root 身份运行自身的一个副本,它会检查要抓取的内容,并从系统自己的文件夹中启动 tcpdump。数据包流回 Borg,由 Borg 以你的身份保存文件。R 和时长仍像以前一样停止抓包;如果 Borg 退出,抓包也会随之停止。如果取消系统对话框,抓包会结束,不显示任何通知。若想跳过这个询问,请在开始前把 运行身份 设为 管理员。

在没有 pkexec 的 Linux 上,如果 sudo 无需密码就能运行 tcpdump,Borg 会使用它。通过 SSH 连接时没有桌面来显示对话框,所以抓包会结束,并显示 Borg 无法以管理员身份抓包 和系统给出的原因。Borg 本身以 root 身份运行时从不询问,并且在 macOS 上它的抓包总会记录每个数据包的进程。在 Borg 无法询问的地方,抓包会结束,通知会说明没有在该接口上抓包的权限,并写出接口名称。

当 Borg 拥有某个 TLS 连接的密钥时,该连接在 3 连接 中的数据流会显示加密记录所携带的内容,例如一个 HTTP 请求及其响应,数据流标题的末尾会显示 已解密。

密钥来自 TLS 密钥日志:当环境变量 SSLKEYLOGFILE 指定一个文件时,浏览器、curl、Python 以及许多其他程序会把密钥写入该文件。这时程序和服务器之间没有任何中间环节,因此对固定证书的程序同样有效。对于从不写密钥日志的程序,Borg 可以自己站到中间(参见通过 Borg 的代理)。

要在抓包时记录密钥,请在 抓取流量 对话框中把 TLS 密钥 设为 在 Borg 的 Shell 中设置 SSLKEYLOGFILE。抓包开始时,Borg 会在抓包文件旁边创建只有你能读取的 capture-<date>-<time>.keylog,并在其 Shell 的提示符处输入类似下面的一行。你能看到它运行,之后也能在 Shell 的历史记录中找到它:

终端窗口
export SSLKEYLOGFILE='/home/me/projects/capture-20260101-120000.keylog'

在 fish 中,这一行以 set -gx 开头。随后 Borg 回到网络屏幕,抓包期间底部一行会显示 TLS 密钥。

现在从 Borg 的命令行启动程序,或者按 Ctrl-O 在 Shell 中启动它。程序会继承这个变量,并把密钥写入该文件。对于在其他终端中运行的程序,在网络屏幕上按 L 复制带有密钥日志路径的 SSLKEYLOGFILE='…',粘贴到那个终端,再在后面输入程序。已经在运行的程序会保留启动时的设置,所以请退出后重新启动。浏览器尤其如此,因为再次启动时它们会把请求交给已经打开的窗口。在 macOS 上,open 启动应用时不会带上 Shell 的变量,因此请直接启动应用自己的程序,例如 /Applications/Firefox.app/Contents/MacOS/firefox。

如果 Borg 的 Shell 正忙,或者命令行属于某个容器或另一台机器,Borg 不会输入任何内容,并会有通知说明。L 仍然可以复制这一行。

抓包结束时,Borg 会在提示符处输入 unset SSLKEYLOGFILE(fish 中为 set -e SSLKEYLOGFILE),或者恢复 Borg 自身启动时的值,并有通知写出这一行。如果你启动的程序仍在 Shell 中运行,这一行会等到它结束。然后 Borg 把抓包中各连接的密钥作为解密密钥块放进抓包文件,因此 .pcap 会变成同名的 .pcapng,Wireshark 打开它时即可解密。密钥日志会留在旁边,因为抓包期间启动的程序会一直写入它,直到退出。智能体请求的抓包不会记录密钥。

会读取 SSLKEYLOGFILE 的程序包括 Firefox、Chrome 和其他基于 Chromium 的浏览器、大多数 curl 构建,以及使用 ssl 模块默认上下文的 Python 程序。其他程序需要各自的开关:

  • Node.js 通过 --tls-keylog 写入密钥,因此请这样启动它:node --tls-keylog="$SSLKEYLOGFILE" app.js。
  • Go 程序只有在程序自己于 TLS 配置中设置了 KeyLogWriter 时才会写入密钥。
  • 使用 rustls 的 Rust 程序只有在使用其 KeyLogFile 时才会写入密钥。
  • Java 需要一个能挂接其 TLS 代码的 Java agent。

Safari 以及其他基于 Apple 自家 TLS 库的应用从不写密钥日志,它们的流量仍保持加密。

把 TLS 密钥 设为 通过 Borg 代理 HTTPS,使用临时 CA,就能读取从不写密钥日志的程序的 HTTPS,例如 Go 和 Rust 程序,或者你无法修改的客户端。抓包开始时,Borg 会在 127.0.0.1 上运行一个代理,并为这次抓包单独生成一个证书颁发机构(CA)。CA 的私钥只保存在 Borg 的内存中,抓包结束后就不复存在。Borg 会在其 Shell 的提示符处输入一行命令,让 HTTPS 经过代理,并让程序信任这个 CA:

终端窗口
export HTTPS_PROXY='http://127.0.0.1:54321' https_proxy='http://127.0.0.1:54321' SSL_CERT_FILE='…' CURL_CA_BUNDLE='…' REQUESTS_CA_BUNDLE='…' NODE_EXTRA_CA_CERTS='…'

这四个证书变量指向 Borg 运行时文件夹中的同一个文件,只有你可以读取。文件里先是 CA 的证书,后面是系统自己的证书,所以程序仍然信任其他所有主机。抓包进行时,底部一行显示 代理位于 和代理的地址,L 复制代理设置 会复制同样的变量,供另一个终端中的程序使用。抓包结束时,Borg 会像处理 SSLKEYLOGFILE 一样恢复其 Shell 原有的设置,并删除这个文件。Borg 从不把它的 CA 加入系统的信任存储。

经过代理的程序会请求代理建立一条通往主机的隧道。代理连接主机,像系统一样检查主机的证书,然后向程序出示一张由 CA 签发、针对同一主机的证书。程序和主机之间仍然使用主机选定的 HTTP/2 或 HTTP/1.1。代理把两段 TLS 会话的密钥都写入抓包的密钥日志,因此抓包中与主机之间的那条连接可以解密打开,查看器也会把它归到请求隧道的进程名下。隧道中不是 TLS 的内容会原样通过。

程序同时读取这两类变量时才会经过代理:

  • curl、git 以及使用 requests 或 urllib 的 Python 会遵循 HTTPS_PROXY 或 https_proxy,并通过 CURL_CA_BUNDLE、REQUESTS_CA_BUNDLE 或(使用 OpenSSL 时)SSL_CERT_FILE 信任这个证书文件。
  • Go 遵循 HTTPS_PROXY,但发往 localhost 的请求除外;在 Linux 上它读取 SSL_CERT_FILE。在 macOS 上它只信任系统的证书,所以在那里它的连接会失败。
  • Node.js 通过 NODE_EXTRA_CA_CERTS 信任这个 CA。较新的版本会让 fetch 和 https 经过代理,前提是你同时设置了 NODE_USE_ENV_PROXY=1。
  • 自带证书列表的程序、固定证书的程序,以及从系统设置读取代理的应用(例如 Safari)会拒绝或绕过代理。被拒绝时,会有通知说明有程序不信任代理为该主机出示的证书。

如果主机的证书没有通过检查,代理会关闭连接,并有通知显示 Borg 无法验证 和主机名。当你自己的服务使用系统不信任的开发 CA 签发的证书时就会这样,例如 mkcert 生成的 CA。把 proxy-ca 指向那个 CA 的文件夹,这一项属于 [network] 部分,写在 config.toml 中:

[network]
proxy-ca = "~/Library/Application Support/mkcert" # mkcert -CAROOT prints the folder

文件夹中必须有证书及其私钥,名称为 rootCA.pem 和 rootCA-key.pem(mkcert 的命名),或 ca.pem 和 ca-key.pem。这样对话框中的选项会写明这个文件夹,形如 通过 Borg 代理 HTTPS,使用 /home/me/dev-ca 中的 CA。代理用你的 CA 签发证书,你的程序本来就信任它;代理检查你的服务时也信任它。请只使用专门用于开发的 CA,因为拿到它私钥的人可以读取所有信任它的程序的流量。

F3 会在两个地方查找密钥:

  • .pcapng 文件中的解密密钥块,Wireshark 也把密钥保存在这里。
  • 抓包文件旁边同名、扩展名为 .keylog 的密钥日志,例如 capture-20260101-120000.keylog,它和 capture-20260101-120000.pcap 放在一起。

要解密以其他方式得到的抓包,请在抓包期间设置该变量并运行程序,抓包保存后,把密钥日志重命名为与抓包文件相同的名字:

终端窗口
SSLKEYLOGFILE=~/tls.keylog curl https://example.com

Borg 能打开以 AES-128-GCM、AES-256-GCM 或 ChaCha20-Poly1305 加密的 TLS 1.3 和 TLS 1.2 记录,浏览器和当前的服务器协商使用的正是这些加密算法。没有任何密钥能打开的记录会保留加密字节,所在的轮次会标注 仍是密文。当密钥日志缺少该连接的部分密钥时会出现这种情况;在抓包缺失的字节之后也会如此,因为 Borg 无法判断下一条记录从哪里开始。QUIC 流量仍保持加密。

密钥日志能解密其中有密钥的每个连接,包括密码、cookie 和令牌,内含密钥的抓包文件也是如此。Borg 会让这两种文件都只有你能读取。你自己写的密钥日志也请用 chmod 600 这样设置,像保管抓包文件一样妥善保管密钥日志,用完后把两者都删除。

在 macOS 上,Borg 通过 netstat 读取每个套接字及其字节计数和所属进程,因此 TCP 和 UDP 都能显示流量。其他用户进程的套接字也会列出。

在 Linux 上,Borg 从 /proc/net 读取套接字,并通过各进程打开的文件找到每个套接字所属的进程。没有管理员权限时,它只能查看你自己的进程,因此其他用户的套接字会显示 未知进程。安装了 ss 时,TCP 的字节计数来自它;UDP 套接字以及没有 ss 的机器在速率处显示 —,详细信息中会显示 系统未提供这里的字节数。接口的总量和速率始终可用。

本指南跟随 main 分支更新 · Borg 0.11.0 · 1f6bce6
最新发布版本可能尚未包含此处介绍的全部功能。 发布说明

译自英文指南,欢迎指正。命令和键盘快捷键不作翻译。