- 网络安全
- 网络
- IDS
【免费下载链接】zeek
Zeek is a powerful network analysis framework that is much different from the typical IDS you may know.
导读
本文聚焦 Zeek 的 storage framework 中异步操作模块Storage::Async。storage framework 为 Zeek 提供基于插件的短/长期数据存储能力,以键值对形式在脚本层读写数据;而Storage::Async是其中以when条件配合使用的异步 API 模块,适用于不能阻塞 Zeek 主事件循环的场景。读完本文,你将掌握open_backend/close_backend/put/get/erase五个异步函数的完整签名、参数语义、返回值结构,理解异步与同步模式的分派机制,并能基于仓库中的真实测试用例写出可运行的 Zeek 存储脚本。
1. Storage::Async 模块概览
Storage::Async定义在 scripts/base/frameworks/storage/async.zeek,模块注释明确其职责为 "Asynchronous operation methods for the storage framework"(storage framework 的异步操作方法)。其 API 文档即 doc/scripts/base/frameworks/storage/async.zeek.rst,对应的接口摘要如下:
| 函数 | 说明 |
|---|---|
Storage::Async::open_backend | 基于配置对象异步打开一个新的后端连接 |
Storage::Async::close_backend | 异步关闭一个已有的后端连接 |
Storage::Async::put | 异步向后端插入一条新记录 |
Storage::Async::get | 异步从后端取回一条记录 |
Storage::Async::erase | 异步从后端删除一条记录 |
该模块通过@load ./main依赖基础模块 scripts/base/frameworks/storage/main.zeek(命名空间Storage),因此在使用Storage::Async之前无需手动加载main,直接@load base/frameworks/storage/async即可,同时会获得Storage::BackendOptions、Storage::PutArgs、Storage::OperationResult等类型定义。模块的自动装载入口见 scripts/base/frameworks/storage/load.zeek。
1.1 异步模式与同步模式的分工
storage framework 将脚本层 API 拆分为两个平级模块:Storage::Async(异步)与Storage::Sync(同步,见 scripts/base/frameworks/storage/sync.zeek)。二者参数与返回值完全一致,唯一区别在于:
- 异步函数必须写在
when条件内调用,否则会返回错误; - 同步函数可直接调用,也可以放进
when,但会阻塞直到后端返回数据。
两者均通过各函数体内的__前缀内建函数(如Storage::Async::__open_backend)最终接入 src/storage/storage.bif 所声明的 C++ 实现,因此异步 API 的底层由原生代码支撑,脚本层只是分派层。
2. 五个异步 API 的完整签名与语义
以下签名与参数说明均严格对齐 doc/scripts/base/frameworks/storage/async.zeek.rst 及源码 scripts/base/frameworks/storage/async.zeek。
2.1 open_backend:异步建立后端连接
function open_backend(btype: Storage::Backend, options: Storage::BackendOptions, key_type: any, val_type: any): Storage::OperationResult| 参数 | 类型 | 说明 |
|---|---|---|
btype | Storage::Backend(enum) | 指示要打开哪种后端,取值由已加载的后端插件定义,内置Storage::STORAGE_BACKEND_REDIS与Storage::STORAGE_BACKEND_SQLITE |
options | Storage::BackendOptions(record) | 连接配置记录;后端插件可通过 redef 该记录追加自身字段 |
key_type | any | 后端中键的脚本层类型,用于校验传入其他方法(get、erase等)的键 |
val_type | any | 后端中值的脚本层类型,既用于校验传给put的值,也用于get返回值的类型转换 |
返回值:一个Storage::OperationResult记录;成功时其value字段为opaque of Storage::BackendHandle(后端句柄),失败时在error_str中给出错误信息。
后端句柄是opaque类型,与普通 Zeek 值一样可以存放在全局变量中,可在zeek_init事件里打开一次、在整个 Zeek 运行期间复用。打开成功后框架会抛出Storage::backend_opened事件。
2.2 close_backend:异步关闭后端连接
function close_backend(backend: opaque of Storage::BackendHandle) : Storage::OperationResultbackend:要关闭的后端连接句柄。- 返回值:包含操作状态与可选错误字符串的
OperationResult。
关闭成功后抛出Storage::backend_lost事件;该事件同样会在连接意外中断时触发(如 Redis 服务端掉线),供脚本感知连接故障并执行重连等恢复逻辑。
2.3 put:异步写入键值对
function put(backend: opaque of Storage::BackendHandle, args: Storage::PutArgs): Storage::OperationResultbackend:后端连接句柄。args:Storage::PutArgs记录,封装写入参数(见下文 §3.2)。- 返回值:操作状态与可选错误字符串。
2.4 get:异步读取键值对
function get(backend: opaque of Storage::BackendHandle, key: any) : Storage::OperationResultbackend:后端连接句柄。key:要查找的键。- 返回值:成功时
value字段携带所取回的值,其类型与open_backend时传入的val_type一致;若键不存在,后端应返回Storage::KEY_NOT_FOUND。
2.5 erase:异步删除键值对
function erase(backend: opaque of Storage::BackendHandle, key: any) : Storage::OperationResultbackend:后端连接句柄。key:要删除的键。- 返回值:操作状态与可选错误字符串;键不存在时返回
Storage::KEY_NOT_FOUND。
3. 支撑类型:BackendOptions、PutArgs 与 OperationResult
3.1 Storage::BackendOptions:后端连接配置
定义于 scripts/base/frameworks/storage/main.zeek(第 13–21 行),是传给open_backend的基础配置记录,后端插件可 redef 追加字段:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
serializer | Storage::Serializer(enum) | Storage::STORAGE_SERIALIZER_JSON | 用于转换 Zeek 数据的序列化器 |
forced_sync | bool | Storage::default_forced_sync(默认F) | 是否强制进入同步模式;设为T后即便调用异步函数也会走同步路径,通常只在测试时使用 |
其中default_forced_sync是可 redef 的全局选项,默认F。加载具体后端策略后该记录会扩展字段,例如加载policy/frameworks/storage/backend/sqlite后新增sqlite: Storage::Backend::SQLite::Options(含database_path、table_name等),加载 Redis 策略后新增redis: Storage::Backend::Redis::Options,详见 doc/scripts/base/frameworks/storage/main.zeek.rst。
框架同时提供可 redef 的Storage::latency_metric_bounds(vector of double,默认[0.001, 0.01, 0.1, 1.0]),用于定义操作时延指标的直方图分桶(单位秒)。
3.2 Storage::PutArgs:put 的参数载体
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
key | any | — | 存储所用的键 |
value | any | — | 与该键关联的值 |
overwrite | bool | T | 键已存在时是否覆盖旧值 |
expire_time | interval | 0sec | 条目自动过期并被后端移除的时间;0sec表示永不过期 |
3.3 Storage::OperationResult:统一返回结构
定义于 scripts/base/init-bare.zeek(第 6814–6826 行):
type OperationResult: record { code: ReturnCode; # 后端可 redef 的返回码 error_str: string &optional; # 失败时设置,非 SUCCESS 时应存在 value: any &optional; # get 返回命中值;open_backend 返回后端句柄 };code字段取自Storage::ReturnCode枚举,仓库内置以下取值:
| 返回码 | 含义 |
|---|---|
SUCCESS | 操作成功 |
VAL_TYPE_MISMATCH | 传入值的类型与打开后端时声明的值类型不符 |
KEY_TYPE_MISMATCH | 传入键的类型与打开后端时声明的键类型不符 |
NOT_CONNECTED | 后端未连接 |
TIMEOUT | 操作超时 |
CONNECTION_LOST | 后端连接意外丢失 |
OPERATION_FAILED | 通用操作失败 |
KEY_NOT_FOUND | 键在后端中不存在 |
KEY_EXISTS | 待覆盖的键已存在 |
CONNECTION_FAILED | 连接建立失败(区别于已建立后丢失) |
DISCONNECTION_FAILED | 断开失败 |
INITIALIZATION_FAILED | 初始化失败 |
IN_PROGRESS | 异步操作正在等待结果(由异步操作返回) |
ReturnCode带&redef,后端可追加自定义状态码。注意并非所有返回码对所有操作都合法。
4. 源码级剖析:异步函数如何分派
阅读 scripts/base/frameworks/storage/async.zeek 第 81–126 行可以看到,Storage::Async的每个公开函数并非直接发起异步请求,而是先检查forced_sync状态再分派:
function open_backend(btype: Storage::Backend, options: Storage::BackendOptions, key_type: any, val_type: any): Storage::OperationResult { if ( options$forced_sync ) return Storage::Sync::__open_backend(btype, options, key_type, val_type); else return Storage::Async::__open_backend(btype, options, key_type, val_type); }close_backend、put、get、erase四个函数则统一以Storage::is_forced_sync(backend)判断分派方向,例如:
function get(backend: opaque of Storage::BackendHandle, key: any) : Storage::OperationResult { if ( Storage::is_forced_sync(backend) ) return Storage::Sync::__get(backend, key); else return Storage::Async::__get(backend, key); }Storage::is_forced_sync与Storage::is_open是 C++ 内建函数,声明在 src/storage/storage.bif:is_forced_sync在句柄无效时返回F,否则返回句柄所指向后端对象的IsForcedSync()结果。由此可以推断:
forced_sync是逐连接生效的:open_backend依据BackendOptions$forced_sync决定该连接进入同步模式;同一 Zeek 进程内可同时存在同步与异步后端句柄;- 异步与同步共享同一套参数/返回结构,模式切换对上层脚本透明,代价仅是阻塞行为不同。
另一个重要行为来自框架文档 doc/frameworks/storage.rst:当用-r参数离线读取 pcap 时,所有后端内部都以同步方式工作,以保证 Zeek 的定时器机制正确运转。此时异步函数仍必须写在when中,但底层会被转换为同步调用。
5. 实战示例:基于仓库测试用例的异步读写
仓库的 btest 测试 testing/btest/scripts/base/frameworks/storage/sqlite/basic.zeek 完整演示了Storage::Async的open_backend→put→get→close_backend全链路,且每个异步调用都嵌套在when中并带timeout兜底。下面是提取并整理的可运行示例:
@load base/frameworks/storage/async @load policy/frameworks/storage/backend/sqlite @load base/frameworks/telemetry redef exit_only_after_terminate = T; global b : opaque of Storage::BackendHandle; event Storage::backend_opened(tag: Storage::Backend, config: any) { print "Storage::backend_opened", tag, config; } event zeek_init() { # 配置 SQLite 后端:数据库文件与表名 local opts: Storage::BackendOptions; opts$serializer = Storage::STORAGE_SERIALIZER_JSON; opts$sqlite = [ $database_path="test.sqlite", $table_name="testing" ]; local key = "key1234"; local value = "value5678"; # 异步打开后端,注意必须放在 when 条件中 when [opts, key, value] ( local open_res = Storage::Async::open_backend( Storage::STORAGE_BACKEND_SQLITE, opts, string, string) ) { print "open result", open_res; b = open_res$value; when [key, value] ( local put_res = Storage::Async::put(b, [ $key=key, $value=value ]) ) { print "put result", put_res; when [key, value] ( local get_res = Storage::Async::get(b, key) ) { print "get result", get_res; if ( get_res$code == Storage::SUCCESS && get_res?$value ) print "get result same as inserted", value == ( get_res$value as string ); } timeout 5sec { print "get request timed out"; terminate(); } } timeout 5sec { print "put request timed out"; terminate(); } } timeout 5sec { print "open request timed out"; terminate(); } }要点归纳:
when是异步 API 的强制要求:文档与源码均明确,"must be called via awhencondition or an error will be returned"(必须通过when条件调用,否则返回错误)。when右侧的局部声明(如open_res)在条件满足后自动可用;key_type/val_type严格校验:示例中声明键、值均为string,后续put/get/erase传入其他类型会触发Storage::KEY_TYPE_MISMATCH或Storage::VAL_TYPE_MISMATCH;get返回值需按声明类型转换:OperationResult$value是any,示例中通过get_res$value as string转回原类型并比较;- 每个异步调用都应配
timeout:一旦后端无响应(如连接丢失),when的timeout 5sec分支会被触发,避免脚本悬挂。exit_only_after_terminate = T确保脚本直到显式terminate()才退出; close_backend同样异步:示例事件print_metrics_and_close()中再次用when包裹Storage::Async::close_backend(b),成功后再terminate()。
另一个测试 testing/btest/scripts/base/frameworks/storage/sqlite/basic-reading-pcap.zeek 展示了混合用法:用Storage::Sync::open_backend打开连接,随后对同一句柄调用Storage::Async::put/Storage::Async::get,最后用Storage::Sync::close_backend关闭——说明同步句柄与异步操作可以混用,只要后端连接本身有效,异步函数可作用在任何句柄上(其is_forced_sync决定实际执行路径)。
6. 使用异步存储框架的注意事项
综合框架文档 doc/frameworks/storage.rst 与源码,实践中有以下几点约束:
- 后端与序列化器插件:Zeek 默认提供 Redis(需系统安装
hiredis≥ 1.1.0,Redis 服务端 ≥ 6.2.0)与 SQLite 两个后端,以及 JSON 序列化器(Storage::STORAGE_SERIALIZER_JSON,默认启用)。切换后端只需更换btype标签与对应 options 记录,脚本层 API 保持一致; - SQLite 的 WAL 限制:SQLite 后端默认 pragma 将
journal_mode设为WAL,该模式不适用于网络文件系统——数据库文件必须位于所有打开它的 Zeek 进程同一台机器上;若使用:memory:内存库,数据不会在节点间同步,每个进程持有独立数据库; backend_lost的双重语义:该事件在主动close_backend成功与连接意外丢失时都会被抛出,脚本应据此实现重连逻辑;forced_sync仅建议测试使用:BackendOptions$forced_sync = T会让所有操作(包括异步 API)走同步路径,main.zeek注释明确 "This should generally only be set toTduring testing"(通常仅在测试时设为T);仓库中的redis/forced-sync.zeek、redis/async-reading-pcap.zeek等测试即覆盖此类场景;- 同步/异步 API 二选一装载:若脚本只使用同步 API,可
@load base/frameworks/storage/sync;两者同时装载亦无冲突,因为Storage::Async在forced_sync时会调用Storage::Sync::__*,反之亦然,二者互为补充。
7. 总结
Storage::Async是 Zeek storage framework 的异步操作入口,五个函数open_backend、close_backend、put、get、erase覆盖了后端生命周期管理与键值数据读写的全部场景。其核心设计包括:
- 统一返回结构
Storage::OperationResult与后端可扩展的Storage::ReturnCode枚举; when条件驱动的非阻塞调用模型,配合timeout分支保证健壮性;forced_sync双层分派机制:脚本层先按连接状态决定走同步还是异步内建实现,且-r读 pcap 时后端内部一律同步化;- 类型即契约:打开后端时声明的
key_type/val_type会在所有后续操作中被严格校验。
如需继续深入,可查阅仓库中的 storage framework 框架文档、Storage 命名空间 API 文档、Storage::Sync 模块文档,以及 storage 的 C++ 接口声明 与 SQLite 后端测试用例,将异步存储能力接入自己的 Zeek 策略脚本。
- 网络安全
- 网络
- IDS
【免费下载链接】zeek
Zeek is a powerful network analysis framework that is much different from the typical IDS you may know.
相关推荐
Notion Avatar性能优化终极指南:图片压缩、懒加载与PWA应用
Notion Avatar性能优化终极指南:图片压缩、懒加载与PWA应用 Notion Avatar Maker是一款强大的在线Notion风格头像生成工具,它
StatsD 对接 Graphite 配置完全指南:Storage Schemas 与 Storage Aggregation 实战详解
StatsD 对接 Graphite 配置完全指南:Storage Schemas 与 Storage Aggregation 实战详解 本指南以 statsd
可观测性指标监控Zeek Storage 框架同步存储接口详解:Storage::Sync 的 open/close/put/get/erase 全解析
Zeek Storage 框架同步存储接口详解:Storage::Sync 的 open/close/put/get/erase 全解析 本篇技术指南围绕 Ze
网络安全网络IDS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考