307 lines
12 KiB
Markdown
307 lines
12 KiB
Markdown
# RPKI RTR Server
|
||
|
||
这是一个用 Rust 实现的 RPKI-to-Router (RTR) cache server。服务端从 CCR 文件中读取 RPKI 数据,生成 RTR cache snapshot 和 delta,并通过 RTR 协议提供给路由器或调试客户端。
|
||
|
||
当前代码重点覆盖:
|
||
|
||
- RTR server:TCP 默认启用,可选启用 TLS/mTLS 和进程内 SSH transport。
|
||
- 数据输入:从 CCR 目录选择最新 `.ccr` 文件,解析 VRP 和 VAP/ASPA。
|
||
- 本地策略:可选加载 SLURM 文件,对 CCR 解析出的 payload 做过滤和本地断言。
|
||
- 持久化:使用 RocksDB 保存 RTR cache 状态。
|
||
- 运行报告:输出 source、client、runtime 三类 JSON report。
|
||
- 运行期管理:可选启用 HTTP Admin API,修改部分 runtime config、触发 source reload、管理 SLURM 文件。
|
||
- 调试工具:`rtr_debug_client` 支持 TCP、TLS 和 SSH 连接 RTR server。
|
||
|
||
## 协议参考
|
||
|
||
- RTR: [RFC 6810](https://www.rfc-editor.org/rfc/rfc6810.html), [RFC 8210](https://www.rfc-editor.org/rfc/rfc8210.html)
|
||
- SLURM: [RFC 8416](https://www.rfc-editor.org/rfc/rfc8416.html)
|
||
- CCR: [draft-ietf-sidrops-rpki-ccr](https://www.ietf.org/archive/id/draft-ietf-sidrops-rpki-ccr-02.html)
|
||
|
||
## 项目结构
|
||
|
||
| 路径 | 说明 |
|
||
| --- | --- |
|
||
| `src/main_rtr.rs` | RTR server 入口 |
|
||
| `src/rtr/` | RTR 协议、cache、store、server transport、admin、report |
|
||
| `src/source/` | CCR/SLURM source 加载流程 |
|
||
| `src/slurm/` | SLURM 文件解析、合并和策略应用 |
|
||
| `src/data_model/` | RPKI 相关数据结构 |
|
||
| `src/bin/rtr_debug_client/` | RTR 调试客户端 |
|
||
| `deploy/server/` | server Docker 镜像和 compose |
|
||
| `deploy/client/` | debug client Docker 镜像和 compose |
|
||
| `deploy/frr/`, `deploy/bird/` | FRR/BIRD 作为 RTR client 的测试部署 |
|
||
| `tests/` | 单元和集成测试 |
|
||
|
||
## 构建与测试
|
||
|
||
```bash
|
||
cargo build --bin rpki_rtr
|
||
cargo build --bin rtr_debug_client
|
||
cargo test
|
||
```
|
||
|
||
服务端 binary 名称是 `rpki_rtr`:
|
||
|
||
```bash
|
||
cargo run --bin rpki_rtr
|
||
```
|
||
|
||
默认配置会监听 `0.0.0.0:323`,从 `./data` 查找 CCR 文件,并使用 `./rtr-db` 保存 RocksDB 数据。启动前需要确保 CCR 目录里存在可解析的 `.ccr` 文件。
|
||
|
||
## 数据输入
|
||
|
||
服务端启动和刷新时会读取 `RPKI_RTR_CCR_DIR` 指向的目录:
|
||
|
||
1. 如果该目录下存在包含 `.ccr` 文件的子目录,先按子目录名排序选择最新子目录。
|
||
2. 在选中的目录中按文件名排序选择最新 `.ccr` 文件。
|
||
3. 从 CCR 中解析 VRP 和 VAP/ASPA。
|
||
4. 如果配置了 `RPKI_RTR_SLURM_DIR`,加载其中启用的 `*.slurm` 文件并应用本地策略。
|
||
|
||
## 快速启动
|
||
|
||
### Docker 运行
|
||
|
||
推荐使用 `deploy/server/build-run.sh` 和 `deploy/client/build-run.sh` 分别管理 server 与 debug client:
|
||
以下命令默认从仓库根目录执行。
|
||
|
||
```bash
|
||
chmod +x deploy/server/build-run.sh deploy/client/build-run.sh
|
||
./deploy/server/build-run.sh up --mode tcp
|
||
./deploy/client/build-run.sh up --mode tcp
|
||
./deploy/client/build-run.sh down
|
||
./deploy/server/build-run.sh down
|
||
```
|
||
|
||
更多 action、mode 和环境变量说明见 `deploy/README.md`。
|
||
|
||
### 跨架构构建
|
||
示例:x86 开发机本地构建 ARM 镜像,打包后传到 ARM 部署机。
|
||
|
||
```bash
|
||
./deploy/server/build-run.sh buildx \
|
||
--platform linux/arm64 \
|
||
--server-image rpki-rtr:arm64
|
||
|
||
./deploy/client/build-run.sh buildx \
|
||
--platform linux/arm64 \
|
||
--client-image rpki-rtr-debug-client:arm64
|
||
|
||
mkdir -p dist/images
|
||
docker save rpki-rtr:arm64 -o dist/images/rpki-rtr-arm64.tar
|
||
docker save rpki-rtr-debug-client:arm64 -o dist/images/rpki-rtr-debug-client-arm64.tar
|
||
|
||
scp dist/images/*.tar user@arm-host:/tmp/
|
||
```
|
||
|
||
ARM 部署机加载镜像并运行:
|
||
|
||
```bash
|
||
docker load -i /tmp/rpki-rtr-arm64.tar
|
||
docker load -i /tmp/rpki-rtr-debug-client-arm64.tar
|
||
|
||
SERVER_IMAGE=rpki-rtr:arm64 \
|
||
BUILD=0 ./deploy/server/build-run.sh up --mode tcp
|
||
|
||
CLIENT_IMAGE=rpki-rtr-debug-client:arm64 \
|
||
BUILD=0 ./deploy/client/build-run.sh up --mode tcp
|
||
```
|
||
|
||
```bash
|
||
docker compose -f deploy/server/docker-compose.yml up -d --build
|
||
docker compose -f deploy/server/docker-compose.yml down
|
||
```
|
||
|
||
TLS/mTLS 示例:
|
||
|
||
```bash
|
||
docker compose -f deploy/server/docker-compose.tls.yml up -d --build
|
||
docker compose -f deploy/server/docker-compose.tls.yml down
|
||
```
|
||
|
||
## 传输模式
|
||
|
||
TCP 默认启用。TLS 和 SSH 是附加监听,不会替代 TCP。
|
||
|
||
| 模式 | 默认地址 | 启用方式 |
|
||
| --- | --- | --- |
|
||
| TCP | `0.0.0.0:323` | 默认启用 |
|
||
| TLS/mTLS | `0.0.0.0:324` | `RPKI_RTR_ENABLE_TLS=true` |
|
||
| SSH | `0.0.0.0:22` | `RPKI_RTR_ENABLE_SSH=true` |
|
||
|
||
TLS server 会加载服务端证书、私钥和 client CA。SSH server 使用 OpenSSH host key 和 authorized_keys 文件;`RPKI_RTR_SSH_AUTH_MODE` 支持 `key`、`password`、`both`。
|
||
|
||
## 主要环境变量
|
||
|
||
布尔值支持 `true/false`、`1/0`、`yes/no`、`on/off`。
|
||
|
||
| 变量 | 默认值 | 说明 |
|
||
| --- | --- | --- |
|
||
| `RPKI_RTR_ENABLE_TLS` | `false` | 是否启用 TLS/mTLS 监听 |
|
||
| `RPKI_RTR_ENABLE_SSH` | `false` | 是否启用 SSH 监听 |
|
||
| `RPKI_RTR_TCP_ADDR` | `0.0.0.0:323` | TCP 监听地址 |
|
||
| `RPKI_RTR_TLS_ADDR` | `0.0.0.0:324` | TLS 监听地址 |
|
||
| `RPKI_RTR_SSH_ADDR` | `0.0.0.0:22` | SSH 监听地址 |
|
||
| `RPKI_RTR_SSH_PORT` | 未设置 | 仅覆盖 `RPKI_RTR_SSH_ADDR` 中的端口 |
|
||
| `RPKI_RTR_DB_PATH` | `./rtr-db` | RocksDB 路径 |
|
||
| `RPKI_RTR_CCR_DIR` | `./data` | CCR 输入目录 |
|
||
| `RPKI_RTR_SLURM_DIR` | 未设置 | SLURM 目录;空值表示禁用 |
|
||
| `RPKI_RTR_REPORT_DIR` | `./report` | JSON report 输出目录 |
|
||
| `RPKI_RTR_MAX_DELTA` | `100` | 每个 RTR 版本保留的最大 delta 数,必须大于 0 |
|
||
| `RPKI_RTR_PRUNE_DELTA_BY_SNAPSHOT_SIZE` | `false` | 是否按 snapshot wire size 继续裁剪 delta window |
|
||
| `RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS` | `300` | source 刷新间隔,单位秒 |
|
||
| `RPKI_RTR_REFRESH_INTERVAL_SECS` | 未设置 | 旧变量名,仍兼容;建议使用 `RPKI_RTR_SOURCE_REFRESH_INTERVAL_SECS` |
|
||
| `RPKI_RTR_TIMING_REFRESH_SECS` | `3600` | RTR EndOfData `refresh` 字段 |
|
||
| `RPKI_RTR_TIMING_RETRY_SECS` | `600` | RTR EndOfData `retry` 字段 |
|
||
| `RPKI_RTR_TIMING_EXPIRE_SECS` | `7200` | RTR EndOfData `expire` 字段,必须大于 refresh 和 retry |
|
||
| `RPKI_RTR_MAX_CONNECTIONS` | `512` | 最大并发 RTR 连接数 |
|
||
| `RPKI_RTR_MAX_CONCURRENT_HANDSHAKES` | `128` | 最大并发握手数,不能大于最大连接数 |
|
||
| `RPKI_RTR_NOTIFY_QUEUE_SIZE` | `1024` | Serial Notify 广播队列大小 |
|
||
| `RPKI_RTR_TCP_KEEPALIVE_SECS` | `60` | TCP keepalive;设为 `0` 表示禁用 |
|
||
| `RPKI_RTR_WARN_INSECURE_TCP` | `true` | TCP 模式是否输出安全提示 |
|
||
| `RPKI_RTR_REQUIRE_TLS_SERVER_DNS_NAME_SAN` | `false` | 是否要求 TLS 服务端证书包含 dNSName SAN |
|
||
| `RPKI_RTR_ENFORCE_TLS_CLIENT_SAN_IP_MATCH` | `true` | 是否校验 TLS client 证书 SAN IP 与 peer IP 匹配 |
|
||
| `RPKI_RTR_RUNTIME_REPORT_INTERVAL_SECS` | `300` | runtime report 周期 |
|
||
| `RPKI_RTR_REPORT_HISTORY_LIMIT` | `10` | 每类 report 滚动保留数量 |
|
||
| `RPKI_RTR_TIMEZONE` | `Asia/Shanghai` | 日志和 report 使用的时区 |
|
||
| `RPKI_RTR_ADMIN_ADDR` | 未设置 | Admin API 监听地址;未设置时关闭 |
|
||
| `RPKI_RTR_ADMIN_TOKEN` | 未设置 | Admin API Bearer token;非 loopback 监听时必须设置 |
|
||
|
||
TLS 相关路径:
|
||
|
||
| 变量 | 默认值 |
|
||
| --- | --- |
|
||
| `RPKI_RTR_TLS_CERT_PATH` | `./certs/server.crt` |
|
||
| `RPKI_RTR_TLS_KEY_PATH` | `./certs/server.key` |
|
||
| `RPKI_RTR_TLS_CLIENT_CA_PATH` | `./certs/client-ca.crt` |
|
||
|
||
SSH 相关配置:
|
||
|
||
| 变量 | 默认值 |
|
||
| --- | --- |
|
||
| `RPKI_RTR_SSH_HOST_KEY_PATH` | `./certs/ssh_host_ed25519_key` |
|
||
| `RPKI_RTR_SSH_AUTHORIZED_KEYS_PATH` | `./certs/rtr-authorized_keys` |
|
||
| `RPKI_RTR_SSH_USERNAME` | `rpki-rtr` |
|
||
| `RPKI_RTR_SSH_SUBSYSTEM_NAME` | `rpki-rtr` |
|
||
| `RPKI_RTR_SSH_AUTH_MODE` | `key` |
|
||
| `RPKI_RTR_SSH_PASSWORD` | 未设置 |
|
||
|
||
## 运行报告
|
||
|
||
服务会在 `RPKI_RTR_REPORT_DIR` 下写入 JSON report,并按 `RPKI_RTR_REPORT_HISTORY_LIMIT` 滚动保留:
|
||
|
||
- `rtr-source-*.json`:CCR/SLURM source、fingerprint、刷新状态、数据质量、cache 统计。
|
||
- `rtr-clients-*.json`:client 连接数和连接方式统计。
|
||
- `rtr-runtime-*.json`:进程状态、服务状态和当前生效的 runtime config。
|
||
|
||
## Admin API
|
||
|
||
Admin API 默认关闭。设置 `RPKI_RTR_ADMIN_ADDR` 后启用:
|
||
|
||
```bash
|
||
export RPKI_RTR_ADMIN_ADDR=127.0.0.1:8323
|
||
export RPKI_RTR_ADMIN_TOKEN=change-me
|
||
```
|
||
|
||
如果监听非 loopback 地址,例如 `0.0.0.0:8323`,必须设置 `RPKI_RTR_ADMIN_TOKEN`。设置 token 后,请求需要携带:
|
||
|
||
```http
|
||
Authorization: Bearer change-me
|
||
```
|
||
|
||
当前实现的主要接口:
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
| --- | --- | --- |
|
||
| `GET` | `/admin/rtr/health` | 健康检查和能力开关 |
|
||
| `GET` | `/admin/rtr/config` | 查看 runtime config |
|
||
| `POST` | `/admin/rtr/config` | 修改部分 runtime config |
|
||
| `GET` | `/admin/rtr/logs/tail` | 读取 stdout/stderr 日志 tail |
|
||
| `POST` | `/admin/rtr/slurm/reload` | 触发 source reload |
|
||
| `GET` | `/admin/rtr/slurm/files` | 列出 SLURM 文件 |
|
||
| `POST` | `/admin/rtr/slurm/files` | 新增或覆盖 SLURM 文件 |
|
||
| `GET` | `/admin/rtr/slurm/files/{name}` | 读取 SLURM 文件 |
|
||
| `PUT` | `/admin/rtr/slurm/files/{name}` | 新增或覆盖指定 SLURM 文件 |
|
||
| `DELETE` | `/admin/rtr/slurm/files/{name}` | 删除 SLURM 文件 |
|
||
| `POST` | `/admin/rtr/slurm/files/{name}/enable` | 启用 `.slurm.disabled` 文件 |
|
||
| `POST` | `/admin/rtr/slurm/files/{name}/disable` | 禁用 `.slurm` 文件 |
|
||
|
||
示例:
|
||
|
||
```bash
|
||
curl http://127.0.0.1:8323/admin/rtr/config \
|
||
-H "Authorization: Bearer change-me"
|
||
|
||
curl -X POST http://127.0.0.1:8323/admin/rtr/config \
|
||
-H "Content-Type: application/json" \
|
||
-H "Authorization: Bearer change-me" \
|
||
-d '{"max_delta": 6, "source_refresh_interval_seconds": 60}'
|
||
```
|
||
|
||
## 调试客户端
|
||
|
||
`rtr_debug_client` 用于手动发起 Reset Query 或 Serial Query,并观察服务端返回的 PDU。
|
||
|
||
TCP:
|
||
|
||
```bash
|
||
cargo run --bin rtr_debug_client -- 127.0.0.1:323 1 reset
|
||
cargo run --bin rtr_debug_client -- 127.0.0.1:323 1 serial 42 100
|
||
```
|
||
|
||
TLS:
|
||
|
||
```bash
|
||
cargo run --bin rtr_debug_client -- \
|
||
127.0.0.1:324 1 reset \
|
||
--tls \
|
||
--ca-cert tests/fixtures/tls/client-ca.crt \
|
||
--server-name localhost \
|
||
--client-cert tests/fixtures/tls/client-good.crt \
|
||
--client-key tests/fixtures/tls/client-good.key
|
||
```
|
||
|
||
SSH:
|
||
|
||
```bash
|
||
cargo run --bin rtr_debug_client -- \
|
||
127.0.0.1:22 1 reset \
|
||
--ssh \
|
||
--ssh-user rpki-rtr \
|
||
--ssh-key certs/rtr-client.key \
|
||
--ssh-server-key certs/ssh_host_rsa_key.pub
|
||
```
|
||
|
||
SSH password auth 也已实现;SSH 模式下 `--ssh-key` 和 `--ssh-password` 二选一,同时必须通过 `--ssh-known-hosts` 或 `--ssh-server-key` 做 host key 校验。
|
||
|
||
更多参数见 `src/bin/rtr_debug_client/README.md`。
|
||
|
||
## 部署入口
|
||
|
||
| 用途 | Compose 文件 |
|
||
| --- | --- |
|
||
| Server | `deploy/server/docker-compose.yml` |
|
||
| Server TCP 示例 | `deploy/server/docker-compose.tcp.yml` |
|
||
| Server TLS 示例 | `deploy/server/docker-compose.tls.yml` |
|
||
| Server SSH 示例 | `deploy/server/docker-compose.ssh.yml` |
|
||
| Debug client | `deploy/client/docker-compose.yml` |
|
||
| Debug client 多实例 | `deploy/client/docker-compose.clients.yml` |
|
||
| FRR client | `deploy/frr/docker-compose.yml` |
|
||
| BIRD client | `deploy/bird/docker-compose.yml` |
|
||
|
||
通用操作:
|
||
|
||
```bash
|
||
COMPOSE_FILE=deploy/server/docker-compose.yml
|
||
docker compose -f "${COMPOSE_FILE}" up -d --build
|
||
docker compose -f "${COMPOSE_FILE}" ps
|
||
docker compose -f "${COMPOSE_FILE}" down
|
||
```
|
||
|
||
## 开发说明
|
||
|
||
- 代码中的 RTR cache 按协议版本维护状态;v0 只包含 Route Origin,v1 包含 Route Origin 和 Router Key,v2 包含 Route Origin、Router Key 和 ASPA。
|
||
- 当前 source pipeline 从 CCR 生成 Route Origin 和 ASPA,再可选应用 SLURM。
|
||
- `RtrStore::save_cache_state_versioned(...)` 是 cache 状态写入 RocksDB 的核心入口,相关边界测试在 `tests/test_store_boundary.rs`。
|
||
- Admin API 的日志 tail 依赖部署入口写出的 stdout/stderr 日志文件;容器入口脚本会把日志写到 `/app/logs`。
|