扫描与上传恢复¶
扫描器将未完成扫描和待上传结果分别保存到 SQLite。日志中的“扫描完成”表示扫描流水线返回结果;ResultUploadCompleted 才表示全部结果已获得服务端确认。
租约和上传¶
上传期间使用最新的租约截止时间。心跳续租会唤醒租约监控并延长可上传时间。租约丢失、网络异常和正常退出都保留原 task_id、upload_id、结果及上传游标。下次连接成功后先恢复服务端执行,再继续上传。
确认响应丢失时重传完全相同的批次。每次只构造一个批次,批次大小仍为最多 500 条、序列化后最多 8 MiB;上传期间不追加或修改观察记录。服务端无运行执行时,仅尝试由服务端验证的幂等结果提交。
服务端明确拒绝旧执行或取消任务后,缓存归档到 upload_archive。归档保留最多 10 份、7 天、总量 64 MiB;超过单份容量时保留活动缓存并停止处理,避免静默删除。归档不是自动重传队列。
服务识别边界¶
远程运行配置和本地配置支持以下字段;旧配置缺少字段时使用默认值。
| service_detection 字段 | 默认值 | 范围 |
|---|---|---|
batch_endpoints |
512 | 1–4096 |
idle_timeout_seconds |
120 | 1–3600 |
max_runtime_seconds |
1800 | 1–86400 |
每个分块执行原有的初始和自适应回退探测,成功后才保存分块。每 30 秒输出 ServiceDetectionProgress;日志包含探测数量、输出数、进程 PID、耗时和无输出时间。子进程无输出、超过总运行预算、输出行过大或超过证据/聚合结果容量时停止。原始分块输出和整阶段聚合服务结果各有 64 MiB 上限;单行最大 8 MiB。
可选识别阶段中止时保留端口和已识别服务,输出 ServiceDetectionIncomplete。必需阶段中止时报失败,不能作为完整成功。无输出后的进程等待同样受到超时与取消约束。
检查点与失败上限¶
检查点包含目标、端口、地址族、速率、扫描计划、实际引擎配置和 DNS 解析器的签名。只有签名一致、服务端重新确认任务所有权后才复用。端口发现、DNS 和漏洞阶段完成后保存结果;服务识别保存已完成分块。参数变化会重新扫描。
服务识别消耗的预算跨恢复累计。异常进程退出留下的运行标记,在下次恢复时按墙钟时间保守计入预算(包括停机时间),同时计一次失败;重复读取不重复计数。正常取消和关闭会保存已耗时。
扫描失败、丢租约和服务分块异常重启最多累计三次,计数跨重启保存;普通 HTTP 重试不计入扫描失败。恢复退避从 5 秒开始,最大 300 秒。新服务端同步累计次数并幂等更新;旧服务端仍由扫描器本地上限保护。成功上传后清除该任务的失败记录。
恢复能力引入的 SQLite schema 3 保存检查点及失败次数;当前 schema 为 4,继续增量迁移并增加注册凭据摘要,保留旧身份、配置和待上传数据。旧程序可能拒绝打开升级后的库,回滚前需核对兼容性并准备升级前的完整数据库目录备份,操作步骤见部署指南。显式执行 cache clear 也会清除当前扫描检查点和失败次数,但不会删除身份或归档。
验证与现场排查¶
回归测试使用假扫描进程、本地 HTTP 服务和临时 SQLite,不扫描真实网络。执行 cargo fmt --check、cargo clippy --all-targets --locked -- -D warnings、cargo test --locked 和 cargo build --locked --release。
现场排查时同时检查 ServiceDetectionStarted 的策略/并发/限速、进度事件、租约丢失来源及服务端请求日志。代码边界能够终止停滞,但不能单凭旧 INFO 日志确认历史 zgrab2 性能问题的内部原因。