rekurt/prt
GitHub: rekurt/prt
prt 是一款用 Rust 编写的实时终端网络端口监控工具,通过交互式 TUI 替代 lsof、ss 等传统命令,提供连接追踪、容器感知、告警和 SSH 隧道管理等功能。
Stars: 2 | Forks: 0
# prt
**为你的终端设计的实时网络端口监控工具**
[](https://crates.io/crates/prt)
[](https://crates.io/crates/prt)
[](https://github.com/rekurt/prt/actions/workflows/ci.yml)
[](LICENSE)
[](https://www.rust-lang.org)
[](https://docs.rs/prt-core)
[English](README.md) | [Русский](README.ru.md) | [中文](README.zh.md)
## 什么是 prt?
`prt` 可以实时在你的终端中显示哪些进程正在占用你机器上的网络端口。你可以把它看作是一个实时的、交互式的 `lsof -i` / `ss -tlnp`,并且带有颜色、过滤功能和进程树。
## 为什么选择 prt?
像 `lsof`、`ss` 和 `netstat` 这样的传统工具提供的是静态快照,当你读到它时就已经过时了。`prt` 为你提供了一个**实时、自动刷新的终端 UI**,并带有变更追踪功能,让你可以:
- **实时查看连接的出现和消失**(绿色 = 新建,红色 = 正在关闭)
- **瞬间发现端口冲突** —— 不再需要通过 `lsof -i :8080` 瞎猜
- **检测可疑活动** —— 异常连接会自动被标记为 `[!]`
- **直接在 TUI 中一键封禁恶意 IP**
- **调试容器化应用** —— 查看每个端口属于哪个 Docker/Podman 容器
- **即时追踪 syscall** —— 无需离开 TUI 即可附加 strace/dtruss
- **监控带宽** —— header 栏会显示全系统的网络吞吐量
- **设置告警** —— 当特定端口开放或进程超出连接限制时收到通知
## prt vs lsof vs ss vs netstat
| 功能 | `prt` | `lsof -i` | `ss -tlnp` | `netstat -tlnp` |
|---------|:-----:|:---------:|:----------:|:---------------:|
| 实时自动刷新 | **是** | 否 | 否 | 否 |
| 变更追踪 (新建/消失) | **是** | 否 | 否 | 否 |
| 彩色输出 | **是** | 否 | 否 | 否 |
| 交互式过滤 | **是** | 否 | 否 | 否 |
| 进程树 | **是** | 否 | 否 | 否 |
| 已知端口名称 (170+) | **是** | 部分 | 部分 | 部分 |
| 可疑连接检测 | **是** | 否 | 否 | 否 |
| 容器感知 (Docker) | **是** | 否 | 否 | 否 |
| 带宽监控 | **是** | 否 | 否 | 否 |
| 防火墙快速封禁 | **是** | 否 | 否 | 否 |
| 附加 Strace/dtruss | **是** | 否 | 否 | 否 |
| 创建 SSH 隧道 | **是** | 否 | 否 | 否 |
| 告警规则 (TOML 配置) | **是** | 否 | 否 | 否 |
| 导出为 JSON/CSV | **是** | 否 | 否 | 否 |
| 用于脚本的 NDJSON 流 | **是** | 否 | 否 | 否 |
| 多语言 (EN/RU/ZH) | **是** | 否 | 否 | 否 |
| macOS + Linux | **是** | macOS/Linux | Linux | Linux |
| 无依赖 (单一二进制文件) | **是** | 系统 | 系统 | 系统 |
## 功能
### 带有变更追踪的实时表格
主视图在一个可排序、可过滤的表格中显示所有活动的网络连接。列包括端口、服务名称、协议、状态、PID、进程名称和用户。新连接会闪烁**绿色**;已关闭的连接会褪色为**红色** 5 秒钟后再消失。表格每 2 秒自动刷新一次。
### 已知端口数据库
`Service` 列将众所周知的端口号映射为人类可读的名称 —— http (80)、ssh (22)、postgres (5432) 等约 170 种。你可以在 `~/.config/prt/config.toml` 中覆盖或扩展自定义名称:
```
[known_ports]
3000 = "my-app"
9090 = "prometheus"
```
### 连接老化
每个连接都会追踪其 `first_seen` 时间戳。超过 1 小时的 ESTABLISHED 连接会高亮显示为黄色;超过 24 小时的会显示为红色。CLOSE_WAIT 连接始终显示为红色,因为它们表明可能存在资源泄漏。
### 可疑连接检测器
连接将被扫描异常情况,并标记为 `[!]`:
- **非 root 用户使用特权端口** —— 非 root 进程监听在小于 1024 的端口上
- **脚本占用敏感端口** —— Python、Perl、Ruby 或 Node.js 监听在 22、80 或 443 端口
- **root 用户向高端口发起外连** —— root 进程与大于 1024 的远程端口建立了连接
按 `/` 然后输入 `!` 仅显示可疑条目。
### 容器感知
如果 Docker 或 Podman 正在运行,`Container` 列将显示每个进程所属的容器。当没有检测到容器时,该列会自动隐藏以节省空间。解析使用批处理的 `docker ps` + `docker inspect` 调用,具有 2 秒的超时时间,以避免阻塞 TUI。
### 带宽估算
header 栏显示全系统网络吞吐量:`▼ 1.2 MB/s ▲ 340 KB/s`。在 Linux 上读取 `/proc/net/dev`,或在 macOS 上读取 `netstat -ib`。速率是根据刷新周期之间的增量计算的。
### 进程树
按 `Enter` 或 `d` 打开详情面板,然后按 `1` 查看所选进程的完整父级链(例如 `launchd → nginx → worker`)。通过遍历 PPID 关系构建。
### 区块
`Tab` / `Shift+Tab` 在三个顶层区块之间循环切换。活动区块会在 header 中高亮显示。
| 区块 | 默认内容 | 子标签页 (`[` / `]`) |
|---------|-----------------|----------------------|
| **Connections** | 端口表 + 底部详情面板(使用 `Enter` / `d` 切换) | — |
| **Processes** | 所选条目的进程详情 (CWD、CPU %、RSS、打开的文件、环境变量、所有连接、进程树) | 详情 ⇄ 拓扑 |
| **SSH** | 保存的主机和活动的隧道集中在一处 | 主机 ⇄ 隧道 |
Connections 表格下方的 **Details** 面板是一个统一的视图,
结合了绑定类型、网络接口、远程地址、状态、cmdline、相关
端口以及进程树 —— 无需切换标签页。
Processes 中的 **Topology** 子标签页会为整个工作集绘制 ASCII 树状图
`process → :local_port → remote`。
所有可滚动的视图都支持 `j`/`k` 和 `g`/`G`。
### 操作菜单 (`Space`)
对所选条目的几乎所有操作都可以通过按 `Space`
打开的一个上下文弹出菜单来执行:
- **杀死进程**(也直接绑定到 `K`)
- **复制行**(也直接绑定到 `c`) / **复制 PID**
- **封禁远程 IP** —— `iptables -A INPUT -s
-j DROP` (Linux) /
`pfctl -t prt_blocked -T add ` (macOS)。状态栏会显示撤销
命令。需要 sudo。
- **追踪 syscall** —— `strace -p -e trace=network -f` (Linux) 或
`dtruss -p ` (macOS,需要禁用 SIP 或拥有 root 权限)。重新运行即可分离。
- **SSH 转发** —— 打开隧道表单,让你可以选择本地端口、
远程目标和主机别名。
该菜单仅显示对当前条目有效的操作 —— 当没有
远程地址时,封禁和转发将被隐藏。
### SSH 区块
`SSH` 聚合了两个子标签页:
- **Hosts** —— 从 `~/.ssh/config` 以及 `~/.config/prt/config.toml` 中的
`[[ssh_hosts]]` 条目解析的只读列表。按 `Enter`
打开预填了主机别名的隧道表单。
- **Tunnels** —— 具有实时状态的运行中隧道:🟢 存活,🟡 启动中,
🔴 失败(失败状态将保持可见,直到你进行处理)。
按键:`n` 新建 · `e` 编辑 · `K` 杀死 · `r` 重启 · `s` 保存到配置。
隧道表单会进行**行内验证**(输入时错误的字段会变红),支持
**编辑模式**(按 Enter 会替换现有隧道),并且
**保护 Esc 键** —— 丢弃一个非空表单需要在 1.5 秒
内按第二次 Esc。
### 告警规则
在 `~/.config/prt/config.toml` 中定义规则,以便在满足特定条件时收到通知:
```
[[alerts]]
port = 22
action = "bell" # terminal bell on new SSH connections
[[alerts]]
process = "python"
state = "LISTEN"
action = "highlight" # highlight row in yellow
[[alerts]]
connections_gt = 100
action = "bell" # alert when a process exceeds 100 connections
```
告警仅在出现 NEW 条目时触发(而不是在每个刷新周期)。可用的条件:`port`、`process`、`state`、`connections_gt`。操作:`bell`、`highlight`。
### NDJSON 流
```
prt --json | jq '.process.name'
```
每个刷新周期向 stdout 输出每个连接的一个 JSON 对象。优雅地处理 SIGPIPE(当通过管道传递给 `head` 时不会发生 panic)。无 TUI 初始化 —— 对脚本和 pipeline 安全。
### 监控模式
```
prt watch 3000 8080 5432
```
显示特定端口 UP/DOWN 状态的紧凑型非 TUI 显示器。在状态改变时发出 BEL (`\x07`)。当连接到 TTY 时支持 ANSI 颜色,通过管道传递时为纯文本。
```
:3000 ● UP nginx (1234) since 42s
:8080 ○ DOWN since 7m
:5432 ● UP postgres (567) since 42s
```
### 导出
```
prt --export json # JSON snapshot of all connections
prt --export csv # CSV snapshot
```
### 多语言界面
支持英语、俄语和中文。语言解析顺序:
1. `--lang en|ru|zh` CLI flag(最高优先级)
2. `PRT_LANG` 环境变量
3. 系统区域设置自动检测
4. 英语(后备)
在 TUI 中按 `L` 即可在运行时切换语言 —— 无需重启。
## 安装
```
cargo install prt
```
从源码构建
```
git clone https://github.com/rekurt/prt.git
cd prt
make install # or: cargo install --path crates/prt
```
**环境要求:** Rust 1.75+ · macOS 10.15+ 或带有 `/proc` 的 Linux · `lsof` (macOS —— 预装)
## 用法
```
prt # launch TUI
prt --lang ru # Russian interface
prt --export json # export snapshot to JSON
prt --export csv # export snapshot to CSV
prt --json # NDJSON streaming to stdout
prt watch 80 443 5432 # compact port watch mode
sudo prt # run as root (see all processes)
```
## 键盘快捷键
**导航:**
**全局:**
| 按键 | 操作 |
|-----|--------|
| `?` | 帮助 (速查表) |
| `q` | 退出 |
| `Tab` / `Shift+Tab` | 下一个 / 上一个区块 (Connections \| Processes \| SSH) |
| `Space` | 操作菜单 (杀死 / 复制 / 封禁 / 追踪 / 转发) |
| `/` | 搜索与过滤 (`!` = 仅显示可疑) |
| `Esc` | 关闭模态框 · 按两次可清除激活的过滤器 |
| `r` | 刷新 |
| `s` | Sudo 提示 |
| `L` | 循环切换语言 |
| `j`/`k` `↑`/`↓` `g`/`G` | 移动 / 滚动 · 跳转到顶部 / 底部 |
**直接快捷键 (任何区块):**
| 按键 | 操作 |
|-----|--------|
| `K` / `Del` | 杀死所选进程 |
| `c` | 复制行到剪贴板 |
**Connections 区块:**
| 按键 | 操作 |
|-----|--------|
| `Enter` / `d` | 切换底部详情面板 |
| `o` / `O` | 下一个排序列 / 反向排序 |
**Processes 区块:**
| 按键 | 操作 |
|-----|--------|
| `[` / `]` | 切换子标签页 (Detail \| Topology) |
**SSH 区块:**
| 按键 | 操作 |
|-----|--------|
| `[` / `]` | 切换子标签页 (Hosts \| Tunnels) |
| Hosts: `Enter` | 从所选主机新建隧道 |
| Hosts: `r` | 重新加载 `~/.ssh/config` 和 prt 配置 |
| Tunnels: `n` | 打开新建隧道表单 |
| Tunnels: `e` 编辑所选隧道 (提交时杀死 + 重生) |
| Tunnels: `K` | 杀死所选隧道 |
| Tunnels: `r` | 重启所选隧道 |
| Tunnels: `s` | 将活动隧道保存到配置 |
## 配置
创建 `~/.config/prt/config.toml`:
```
# 覆盖已知端口名称
[known_ports]
3000 = "my-app"
9090 = "prometheus"
# Alert rules
[[alerts]]
port = 22
action = "bell"
[[alerts]]
process = "python"
state = "LISTEN"
action = "highlight"
[[alerts]]
connections_gt = 100
action = "bell"
```
## 架构
```
crates/
├── prt-core/ # Core library (platform-independent)
│ ├── model.rs # PortEntry, TrackedEntry, ViewMode, ProcessesTab, SshTab, ActionItem
│ ├── config.rs # TOML config loading (~/.config/prt/)
│ ├── known_ports.rs # Well-known port → service name database
│ ├── core/
│ │ ├── scanner.rs # scan → diff → sort → filter → export
│ │ ├── session.rs # Refresh cycle state machine
│ │ ├── killer.rs # SIGTERM / SIGKILL
│ │ ├── alerts.rs # Alert rule evaluation
│ │ ├── suspicious.rs # Suspicious connection heuristics
│ │ ├── bandwidth.rs # System-wide RX/TX rate tracking
│ │ ├── container.rs # Docker/Podman container resolution
│ │ ├── namespace.rs # Network namespace grouping (Linux)
│ │ ├── process_detail.rs # CWD, env, files, CPU, RSS
│ │ └── firewall.rs # iptables/pfctl block/unblock
│ ├── i18n/ # EN / RU / ZH, AtomicU8-backed runtime switching
│ └── platform/
│ ├── macos.rs # lsof + batch ps (2 calls/cycle)
│ └── linux.rs # /proc via procfs
└── prt/ # TUI binary (ratatui + crossterm + clap)
├── app.rs # App state, main loop, caching
├── ui.rs # ViewMode-based rendering, fullscreen views
├── input.rs # Key dispatch by view mode
├── stream.rs # NDJSON streaming mode
├── watch.rs # Port watch mode
├── tracer.rs # Strace/dtruss session management
└── forward.rs # SSH tunnel manager
```
**数据流:**
```
platform::scan_ports() → Session::refresh()
→ diff_entries() New / Unchanged / Gone (with first_seen carry-forward)
→ enrich() service names, suspicious flags, containers
→ retain() remove Gone after 5s
→ bandwidth.sample() RX/TX delta since previous cycle
→ sort_entries() by current SortState
App::refresh()
→ alerts::evaluate() fire bell/highlight alerts
→ filter_indices() user's search query
→ UI renders ViewMode-based routing
```
| 平台 | 方法 | 性能 |
|----------|--------|-------------|
| **macOS** | `lsof -F` 结构化输出 | 每个扫描周期 2 次 `ps` 调用(批量) |
| **Linux** | 通过 `procfs` 访问 `/proc/net/` | 零子进程开销 |
## 高投资回报率用例 (超越基础监控)
### 1) 部署前网络回归防护
在部署前后运行 `prt --json` 并对比连接配置文件差异。
这能捕获意外的新出口路径、错误的绑定地址以及隐藏的副作用。
```
prt --json | jq -c '{pid: .process.pid, name: .process.name, local: .local_addr, remote: .remote_addr, state: .state}'
```
### 2) 终端内的实时事件响应循环
无需离开 TUI 即可使用可疑过滤 + 封禁 + 追踪:
1. `/` 然后按 `!` 仅显示可疑项
2. 按 `b` 封禁远程 IP
3. 按 `t` 附加 strace/dtruss 并检查行为
这提供了一个快速的“观察 → 隔离 -> 检查”工作流。
### 3) 容器端口暴露审计
在容器密集的主机上,切换到 **Processes → Topology**(按 `Tab` 到 Processes,再按 `]` 到 Topology)以发现
意外的暴露(例如,调试端口、管理 API、意外的公开绑定)。
### 4) 运行时功能开关验证
在功能推出期间,追踪启用某个开关是否会引入新的出站
连接或状态变动(`SYN_SENT`、`CLOSE_WAIT` 激增等)。
### 5) 针对脚本密集型服务的轻量级主机金丝雀
对于重度使用 Python/Node/Ruby 的技术栈,可疑启发式算法 + 告警可以作为一种
廉价的金丝雀,用于监测敏感端口上的异常监听行为。
## 开发
```
cargo build --workspace # build everything
cargo test --workspace # run all tests
cargo clippy --workspace # lint
cargo fmt --all -- --check # format check
cargo bench -p prt-core # criterion benchmarks
```
请参阅 [CONTRIBUTING.md](CONTRIBUTING.md) 了解指南。
## 常见问题
### 如何查看所有进程?某些端口显示为“unknown”。
使用 `sudo prt` 运行以查看其他用户拥有的进程。在没有 root 权限的情况下,操作系统会隐藏不属于你的 PID。
### prt 可以在 Windows 上运行吗?
暂时不行。`prt` 目前支持 **macOS** (10.15+) 和 **Linux** (带有 `/proc`)。Windows 支持已在 issue 追踪器中记录。
### prt 与 `htop` 或 `btop` 有什么区别?
`htop`/`btop` 是通用的进程监控器。`prt` 则专门针对**网络连接和端口** —— 显示哪个进程正在使用哪个端口,追踪连接生命周期,检测异常,并提供网络特定的操作(防火墙封禁、strace、SSH 隧道)。
### 我可以在脚本和 pipeline 中使用 prt 吗?
可以!使用 `prt --json` 输出 NDJSON 流,`prt --export json|csv` 获取快照,或者使用 `prt watch ` 进行简单的 UP/DOWN 监控。所有非 TUI 模式在通过管道传递时都能完美运行。
### 如何添加自定义端口名称?
编辑 `~/.config/prt/config.toml`:
```
[known_ports]
3000 = "my-frontend"
8080 = "my-api"
9090 = "prometheus"
```
### 在生产环境中使用 prt 安全吗?
默认情况下,`prt` 是一个**只读的诊断工具**。破坏性操作(杀死进程、封禁 IP、附加 strace)始终需要明确的确认。TUI 绝不会在未经你批准的情况下修改系统状态。
## Star History
[](https://star-history.com/#rekurt/prt&Date)
## 许可证
[MIT](LICENSE)
**如果 `prt` 对你有用,可以考虑在 GitHub 上给它点个 star!**
[](https://github.com/rekurt/prt)
标签:Python安全, Rust, 内存分配, 可视化界面, 系统工具, 终端UI, 网络流量审计, 请求拦截, 跨平台, 运维监控, 通知系统