antirubber/netmon

GitHub: antirubber/netmon

被动网络流量审计工具,通过分类记录设备的 DNS、TLS SNI、HTTP 请求和网络连接等明文泄露信息,帮助用户了解运营商可见的设备网络活动。

Stars: 1 | Forks: 0

# netmon 被动网络监控工具,用于审计你的设备向 ISP 泄露了什么信息以及联系了哪些网站。在所有接口上进行捕获,并记录带有时间戳、分类的 JSONL。 ## 记录内容 | 文件 | 内容 | |------|----------| | `dns.jsonl` | 每个 DNS 查询(名称、类型、解析器),每个回答(A/AAAA/CNAME/… 及 TTL),以及带有其 SvcParams 的每条 HTTPS/SVCB(类型 65/64)记录:`alpn`、`port`、`ipv4hint`、`ipv6hint` 和 `ech` 标志 | | `tls.jsonl` | 来自每个 HTTPS 连接的 ClientHello 中的 SNI — TCP TLS 和解密后的 QUIC Initials(`transport`),明文 `alpn` 列表,其中 `ech: true` 标记了一个掩护名称(参见限制) | | `http.jsonl` | 明文 HTTP 请求:方法、路径、Host、User-Agent;已知的强制门户探测带有 `tag: "captive-portal"` | | `flows.jsonl` | 每个新连接:协议、方向、本地/远程 IP+端口、服务猜测、主机名(通过观察到的 DNS 回答反向映射)、范围(`internet`、`lan` 或 `multicast`),以及对披露性服务(NTP、STARTTLS 邮件)的 `note` | | `summary.json` | 在退出时写入:热门 DNS 名称、热门 SNI 主机名、热门互联网主机、事件计数 | 所有事件均带有精度为毫秒的 ISO 8601 UTC 时间戳。每次运行都会写入 `logs/run-/`。 ## 运行 捕获需要 raw socket 权限: ``` sudo $(command -v uv) run netmon.py # all interfaces sudo $(command -v uv) run netmon.py -i wlan0 # one interface sudo $(command -v uv) run netmon.py --bpf 'not port 22' -q ``` 或者授予一次该 capability 然后免去 sudo: ``` sudo setcap cap_net_raw+eip "$(readlink -f .venv/bin/python3)" uv run netmon.py ``` `-q/--quiet` 会抑制每个事件的标准输出(文件始终会被写入)。每 30 秒记录一次统计行。使用 Ctrl-C 停止 — 摘要会在退出时写入。 ## 读取结果 即使在使用 HTTPS 的情况下,你的 ISP 也能看到什么:`dns.jsonl` 中的所有内容(除非你使用加密 DNS)、`tls.jsonl` 中的每个 `sni` 值,以及 `flows.jsonl` 中的每个远程 IP。快速查看: ``` jq -r '.sni' logs/run-*/tls.jsonl | sort | uniq -c | sort -rn # sites visited via SNI jq -r 'select(.kind=="dns_query") | .qname' logs/run-*/dns.jsonl | sort -u jq -r 'select(.scope=="internet") | .hostname // .remote_ip' logs/run-*/flows.jsonl | sort | uniq -c | sort -rn ``` 缓解 ISP 所见内容:[docs/MITIGATIONS.md](docs/MITIGATIONS.md)。操作说明:[docs/RUNBOOK.md](docs/RUNBOOK.md)。 ## 限制 - QUIC (HTTP/3, `udp/443`):QUIC Initial 数据包中的 SNI **并未**对你的 ISP 隐藏。Initial 数据包使用从连接的明文 Destination Connection ID 加上特定于版本的公开盐值(RFC 9001 §5.2)派生的密钥进行保护,因此路径上的任何被动观察者都可以解密 ClientHello — 而且主流的 DPI 已经做到了这一点。netmon 会解密这些 Initials(QUIC v1 和 v2,在合并和分片的数据包之间重新组装 CRYPTO 流),并将 SNI 记录在 `tls.jsonl` 中,带有 `"transport": "quic"`。它仅解析 `udp/443` 且仅解析客户端的 Initial 飞行。 - 加密 DNS (DoH/DoT/DoQ) *确实* 对你的 ISP 隐藏了查询名称;它在此处仅显示为与解析器的流。 - Encrypted Client Hello (ECH) 在设计上隐藏了 SNI:明文 ClientHello 随后会带有一个公开的*掩护*名称,而不是你访问的网站。netmon 在 `tls.jsonl` 中用 `"ech": true` 标记这些 — 这样的行意味着真实的主机名已对你的 ISP 隐藏(*防止*了泄露),而 `sni` 值只是掩护名称。如果 ECH 握手失败,浏览器会在不使用它的情况下重试,真实的 SNI 将以明文形式发出,netmon 依然会记录它。 - 分段解析:SNI 和 HTTP 请求会跨越多个 TCP 分段进行重组(后量子时代的 ClientHello 通常会跨越多个分段),因此在中途拆分了 header 的请求依然会被作为一个整体解析一次。唯一的盲区是其*开始*分段从未被捕获的连接 — 如果 netmon 在流传输中途启动,该流将不会被重组,其 SNI/HTTP 将被跳过(该流本身仍会被记录)。 ## 此工具无法向你展示的内容 即使在 qname/SNI/remote-IP 全部为零(ECH + 加密 DNS + VPN)的情况下,路径上的 ISP 仍然拥有 netmon 无法捕获的信号 — 这是对“ISP 能看到什么”的客观界限: - **流量分析** — 数据包大小、时间、方向和每个流的字节量。仅凭这些就能对 TLS、ECH 和 VPN 背后的各个网站(通常是单个页面)进行指纹识别,因为页面加载的形状是独特的。netmon 仅记录*发生了*某个流,而不是其大小/时间概况。 - **TLS 客户端指纹 (JA3/JA4)** — ClientHello 中密码套件、扩展和支持的组的顺序标识了客户端软件和版本。netmon 从该 hello 中读取 SNI 和 ALPN,但不计算指纹。 - **TLS 1.2 服务器证书** — 在仍然普遍存在的 TLS 1.2 路径上,服务器的证书(及其 SAN)在握手期间以明文形式通过网络传输;TLS 1.3 对其进行了加密。netmon 不解析服务器证书。 - **IPv6 地址泄露** — SLAAC EUI-64 地址嵌入了 NIC MAC,而稳定的 IPv6 即使在 SNI 被隐藏的情况下,也能跨网络识别设备。netmon 记录了这些地址,但没有标记此推导关系。 只有 Tor 级别的工具(onion 路由加流量填充)才能有效应对流量分析/相关性通道;VPN 或 ECH 只是改变了观察者的位置,它并不能消除你的流量形状。
标签:Python, 数据包解析, 无后门, 时序数据库, 目录遍历, 逆向工具, 隐私审计