一个用 ratatui 实现的 macOS 静态路由 TUI 管理器。
通过 macOS 自带的 networksetup 命令查看与修改网卡的「附加路由(additional routes)」,
写操作经 osascript 弹出系统级图形授权对话框提权,TUI 进程本身不需要 root。
- 扫描所有网络服务(网卡),聚合三类来源的路由:
manual手动附加路由(networksetup -getadditionalroutes)—— 可在 TUI 内增删default默认路由(netstat -rn的 default,决定「其他流量走哪」)—— 只读展示direct直连网段(每张网卡 IP/掩码对应的本地网段)—— 只读展示
- 左侧:IP 段列表,按优先级低→高排序,每条标注来源标记
[m]/[d]/[.]。 - 右侧:选中 IP 段的全部命中(来源 + 网卡 + 网关 + 优先级/禁用标记)。
- 添加路由:输入 CIDR(如
10.0.0.0/8)→ 选择目标网卡 → 提权写入(成为 manual)。 - 删除路由:仅在 manual 命中上可用 → 确认 → 提权移除。
- 自动过滤路由噪声:loopback / link-local / multicast / broadcast /
/32主机条目、 以及 utun/lo0 等非服务网卡上的条目均不展示。
cargo run需要:macOS + 已安装 networksetup(系统自带)+ Rust 工具链。
| 按键 | 作用 |
|---|---|
↑/k |
上一个 IP 段 |
↓/j |
下一个 IP 段 |
←/h |
上一个绑定网卡(右侧) |
→/l |
下一个绑定网卡(右侧) |
r |
刷新(重新读取 networksetup) |
a |
添加路由 |
d |
删除当前选中的绑定 |
? |
帮助 |
q/Esc |
退出 |
添加路由弹窗内:Tab 在「CIDR 输入框」和「网卡列表」之间切换焦点,Enter 确认。
networksetup -setadditionalroutes 写路由需要 root。本程序在写操作时通过:
osascript -e 'do shell script "networksetup ..." with administrator privileges'
弹出 macOS 系统级用户名/密码授权对话框(独立于终端,不干扰 TUI 屏幕)。 取消授权或密码错误会以错误弹窗展示,并附上原始命令文本供手动重试。
读操作(-listnetworkserviceorder / -getadditionalroutes)不需要提权。
networksetup -setadditionalroutes是全量覆盖语义:传入一个服务的全部路由。 因此增/删内部都是「读现有全部路由 → 加/减一条 → 整体回写」,封装在net::networksetup::set_routes,对上层只暴露「增/删一条」的语义。- 内部统一用
{dest, prefix_len}(CIDR)表示路由,调用命令前再做 netmask↔prefix 转换。
src/
├── main.rs # 入口:terminal setup/restore (Drop guard)、事件循环
├── app.rs # App 状态、Mode 枚举、update reducer
├── event.rs # crossterm 键盘事件循环
├── ui/
│ ├── mod.rs # draw:整体双面板布局 + 底栏
│ ├── sidebar.rs # 左侧 IP 段列表
│ ├── detail.rs # 右侧:选中 IP 段绑定的网卡列表
│ └── popup.rs # 添加路由 / 删除确认 / 帮助 / 错误 弹窗
├── net/
│ ├── mod.rs # 重新导出
│ ├── service.rs # NetworkService + listnetworkserviceorder 解析
│ ├── route.rs # Route + RouteSource + CIDR/netmask 转换
│ ├── getinfo.rs # networksetup -getinfo 解析(IP/掩码/网关)
│ ├── netstat.rs # netstat -rn 解析(默认路由 + 直连网段,去噪)
│ └── networksetup.rs # list_services / get_routes / set_routes / netstat_routes / run_elevated
├── macros.rs # key! / cmd! / log! 宏
└── error.rs # AppError (thiserror)
key!:压缩 crosstermKeyEvent的匹配,如key!(ev, 'j')、key!(ev, Esc)、key!(ev, ctrl => 'c')。cmd!:构造Command并压入参数,如cmd!(networksetup -getadditionalroutes service),自动把-flag拼成字符串。log!:向应用内部日志缓冲写入(TUI 里不能用println!)。
cargo test覆盖:CIDR 解析与 netmask 互转、listnetworkserviceorder / getadditionalroutes 输出解析(含真实样例 fixture)、AppleScript/shell 转义、宏行为。