ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Zeek 配置框架(Config Framework)深度实战:option 运行时热更新、集群分发与 config.log 审计

Zeek 配置框架(Config Framework)深度实战:option 运行时热更新、集群分发与 config.log 审计 网络安全网络IDS【免费下载链接】zeekZeek is a powerful network analysis framework that is much different from the typical IDS you may know.项目地址https://gitcode.com/gh_mirrors/ze/zeek点击查看免费下载Zeek 的配置框架Configuration Framework提供了一种在运行时修改 Zeek 脚本option值的能力既能通过外部配置文件持续推送新值也能在脚本中调用Config::set_value主动更新并将每一次变更记录到config.log。本文以 base/frameworks/config/main.zeek 为核心结合底层源码与测试用例系统讲解该框架的公开接口、集群同步机制、配置文件格式与变更日志审计读完即可在你的 Zeek 环境中实现不改脚本、不重启进程的配置热更新。框架概览为什么需要运行时配置Zeek 传统上用脚本常量const保存各种设置。常量在 Zeek 启动后便不可修改虽然redef允许在加载阶段重新定义常量但同样只能在启动时生效。重启 Zeek 代价高昂——它会丢失全部连接状态与已积累的分析知识。配置框架正是为解决运行中修改配置这一需求而生语言层面提供option关键字声明可运行时变更的配置项配置文件可持续把新值推入运行中的 Zeek基于输入框架热替换脚本层面提供Config::set_value主动更新配置并能在集群中自动分发每一次变更都会写入config.log形成完整审计轨迹。框架主体由 scripts/base/frameworks/config/main.zeek 实现命名空间为Config并在加载时load base/frameworks/cluster依赖集群框架实现跨节点同步。模块通过load.zeek 聚合加载main、input、weird三个部分。核心公开接口对应官方 API 文档类型Config::InfoConfig::Info是一个record描述config.log中每一条记录的字段定义见 main.zeek字段类型属性含义tstimelog配置变更发生的时间戳idstringlog被修改的 option 的完整 ID含模块名old_valuestringlog变更前的值字符串化new_valuestringlog变更后的值字符串化locationstringoptional log触发变更的位置如配置文件路径、set_value的 location 参数可选Redefinition日志流Config::LOGmain.zeek通过redef enum Log::ID { LOG };为配置框架申请了一个独立的日志流标识Config::LOG在zeek_init中创建流Log::create_stream(LOG, Log::Stream($columnsInfo, $evlog_config, $pathconfig, $policylog_policy));即日志写入config.log列结构即Config::Info。事件Config::log_configglobal log_config: event(rec: Info);当一条Config::Info记录被送往日志框架时触发可通过事件处理函数访问该记录用于二次加工例如补充字段后再写日志。钩子Config::log_policyConfig::log_policy是类型为Log::PolicyHook的默认日志策略钩子可用于在记录写盘前过滤、改写或附加字段与 Zeek 其他日志流的 policy hook 用法一致。函数Config::set_valueglobal set_value: function(ID: string, val: any, location: string default ): bool;这是配置框架对底层Option::set的封装层。官方文档明确指出Config::set_value会将配置值设置到集群中所有节点无论它在哪里被调用而底层Option::set不会把配置变更分发到其他节点单节点生效参见 option.bif 中的说明。参数说明参数类型说明IDstring要更新的 option 的完整 ID如Test::enable_featurevalanyoption 的新值locationstring default optional可选描述本次变更的来源会写入config.log的location字段返回值成功返回T出错返回F。运行时热更新实战配置文件驱动声明 option使用option关键字声明配置项。option兼具全局变量与常量的特性不能在函数、hook 或事件处理函数内部声明声明时必须初始化类型通常可从初始值推断运行时可被修改但不能用普通赋值语句赋值。示例源自 doc/frameworks/configuration.rstmodule Test; export { option my_networks: set[subnet] {}; option enable_feature F; option hostname testsystem; option timeout_after 1min; option my_ports: vector of port {}; }option 的初始值可像常量一样用redef重新定义无需redef属性redef Test::enable_feature T; redef Test::my_networks { 10.1.0.0/16, 10.2.0.0/16 };注册配置文件Config::config_files配置框架通过输入框架持续监控磁盘上的配置文件见 input.zeek。注册方式是在启动脚本如local.zeek中redef Config::config_files { /path/to/config.dat };配置文件的每一行对应一条赋值格式为[option name][tab/空格][new value]以#开头的行是注释会被忽略。运行时直接编辑文件中的一行例如把Test::enable_feature T写进正在运行的 Zeek 所监控的文件脚本层对应 option 会自动更新之后代码访问该 option 便读到新值。关键注意点input.zeek 源码注释明确说明文件每次更新都会被重新读取因此更新应当采用原子替换mv而不是原地写入——否则可能在写入过程中读到半行数据。另外如果同一个 option 在多个文件中被赋予不同值行为是未定义的several-files.zeek测试即验证了多文件场景见 several-files.zeek。底层实现Input::add_table以Input::READER_CONFIG读取器、Input::REREAD模式注册每个文件读取器在 src/input/readers/config/Config.cc 中通过比对文件的mtime与inode检测变化并触发重读。只有当值与上次不同时才下发避免无效事件见 Config.cc。一次性读取Config::read_config如果只想在启动时或某个时刻读取一次配置文件、之后不跟踪更新可调用Config::read_config(/path/to/configfile);它在内部以Input::MANUAL模式注册一次事件读取后立即移除。测试用例 read_config.zeek 演示了完整的读取、打印与config.log比对流程。配置文件的值格式配置文件里的值格式与 Zeek 脚本语法并不完全一致格式错误的行会被读取器忽略并在reporter.log中给出警告。支持的类型及表示法汇总如下源自 doc/frameworks/configuration.rst 的完整类型表数据类型配置文件示例说明addr1.2.3.4普通 IPv4/IPv6 地址不带/32等掩码boolTT或1表示真F或0表示假count42非负整数double-42.5普通浮点数enumEnum::FOO_A枚举字符串int-1普通整数interval3600.0恒为 epoch 秒数可带小数绝不包含时间单位pattern/(foo|bar)/以正斜杠包裹的正则port42/tcp端口号加协议缺省协议时按/unknown解释set80/tcp,53/udp集合成员按自身格式以逗号分隔空集合用空字符串option 名后直接跟空白多索引类型集合如set[addr,string]暂不支持stringDont bite, Zeek普通字符串不加引号加了引号会成为字符串的一部分option 名后分隔空白之后的所有内容都是字符串反斜杠无特殊含义subnet1.2.3.4/16普通子网time1608164505.5恒为 epoch 秒数可带小数绝不包含时间单位vector1,2,3,4元素按自身格式以逗号分隔空 vector 用空字符串不支持的类型table与record。若确需使用可自行构造相应类型的实例比如从另一个输入框架文件读取再调用Config::set_value更新module Test; export { option host_port: table[addr] of port {}; } event zeek_init() { local t: table[addr] of port { [10.0.0.2] 123/tcp }; Config::set_value(Test::host_port, t); }解析细节set_separator、empty_field等分隔符常量定义于 config.bif读取器在 Config.cc 中装配 ASCII 格式化器值的实际类型转换发生在Ascii::ParseValue()src/threading/formatters/Ascii.cc与Value::ValueToValsrc/threading/SerialTypes.cc。未知 option 与错误处理配置文件中出现脚本层不存在的 option 是安全的但会在reporter.log中告警Config.ccwarning: config.txt/Input::READER_CONFIG: Option an_unknown does not exist. Ignoring line.若 option 类型不受配置文件输入支持如record见 Config.cc 对TYPE_ERROR的标记同样会告警并忽略该行。值转换失败的行也会被忽略并告警。集群环境下的配置分发配置框架是集群化的集群模式下只有 manager 节点监控配置文件并把更新中继给所有 workerdoc/frameworks/configuration.rst 明确说明。分发机制源码级看 main.zeek 的集群实现定义Config::cluster_set_option事件与option_cache: table[string] of OptionCacheValue缓存最近一次设置的 option 值及来源set_value先调用底层Option::set在本地生效失败则返回F在 manager 上更新option_cache并向所有Cluster::broadcast_topics广播cluster_set_option在 worker 上向Cluster::manager_topic发布cluster_set_option由 manager 统一广播任何节点收到cluster_set_option事件后执行Option::set(ID, val, location)manager 额外缓存并转发。因此在集群中worker 也可以调用Config::set_value变更会经 manager 转发到所有节点。测试 basic_cluster.zeek 展示了 worker-1 调用Config::set_value(testport, 44/tcp)后manager 与两个 worker 的 option 同步更新。新节点加入的补偿同步框架还处理了manager 已运行、新 worker 才接入的场景manager 监听Cluster::node_up优先级-10当新节点连接时把option_cache中所有当前 option 值一次性发送给它main.zeekevent Cluster::node_up(name: string, id: string) priority-10 { if ( name in Cluster::nodes ) for ( ID in option_cache ) Cluster::publish(Cluster::node_topic(name), Config::cluster_set_option, ID, option_cache[ID]$val, option_cache[ID]$location); }cluster_resend.zeek测试正是围绕该重发行为设计的。独立standalone模式非集群模式下set_value直接退化为底层Option::setmain.zeekfunction set_value(ID: string, val: any, location: string default ): bool { return Option::set(ID, val, location); }引用语义保护set_value在实现中先执行val copy(val)即拷贝一份值再设置从而切断调用者后续对该值的引用——即使调用者之后修改原变量option 也不会被意外改变main.zeek。若确需联动修改应显式调用Option::set_value或Option::set并在调用时刻传入目标值。底层机制Option::set与变更处理器链Config::set_value最终落到 src/option.bif 中的内置函数Option::set其内部校验包括ID 必须存在且已初始化目标必须是option否则报ID %s is not an option类型必须匹配特别地Broker 传输来的DataVal会先反序列化为目标类型集群分发依赖此路径未指定类型的空表会被强制转换赋值前依次调用该 option 已注册的变更处理器change handler处理器链的最终返回值被克隆后赋给 optioni-SetVal(val-Clone())。注册变更处理器Option::set_change_handler除配置文件与Config::set_value外也可为 option 挂接自定义变更回调Option::set_change_handler(Test::testaddr, change_addr);处理器函数接收 2 或 3 个参数IDstring、新值类型须与 option 一致、可选locationstring并返回期望的新值——因此可以拒绝或改写正在设置的变更。多个处理器按优先级链式执行优先级高的先调用同优先级按注册顺序后一个处理器看到的是前一个处理器返回的值option.bif 的完整校验逻辑。注意处理器调用时全局值尚未更新且处理器名必须是含模块名的完整 ID。weird.zeekscripts/base/frameworks/config/weird.zeek正是这一机制的真实用例它为Weird::sampling_whitelist、Weird::sampling_threshold、Weird::sampling_rate、Weird::sampling_duration注册处理器把新值实时同步到Reporter的采样配置中对应测试 weird.zeek 验证了通过Config::set_value修改这些 option 后采样行为的即时变化。处理器触发时机根据 doc/frameworks/configuration.rst 的权威说明未注册任何配置文件时处理器不运行已注册但文件在磁盘上不存在时处理器不运行处理器与配置文件绑定不会因默认值自动触发启动时文件存在则处理器会按文件中的配置值运行即使文件中值与默认值相同处理器仍会被调用zeek_init处理器先于变更处理器运行即在默认值下运行由于依赖输入框架的异步性无法假设变更生效的精确时刻若需默认值 每次变更都执行初始化逻辑可在zeek_init注册时手动调用一次处理器。config.log配置变更审计日志框架在zeek_init优先级 10中为每个全局 option 注册一个低优先级-100的变更处理器config_option_changedmain.zeek负责把每次变更写入日志。样本记录源自 doc/frameworks/configuration.rst#fields ts id old_value new_value location #types time string string string string 1608167352.498872 Test::a_count 42 3 config.txt要点日志分级集群模式下仅 manager 写config.logworker 只是消费变更main.zeek 的if ( !Cluster::is_enabled() || Cluster::local_node_type() Cluster::MANAGER )分支值序列化format_value对set/vector用逗号连接元素字符串原样输出其余类型cat化main.zeek内部变更豁免若location等于特殊值skip-config-log本次变更不记录——用于屏蔽 Zeek 内部活动引起的 option 更新location 语义配置文件触发的变更location为配置文件路径Config::set_value触发的变更location为传入的第三个参数set_value的 location 也会透传给处理器链的第三参数。例如basic.zeek测试testing/btest/scripts/base/frameworks/config/basic.zeek会在启动时读取配置文件并对config.log做btest-diff比对作为回归基线。完整实战示例不重启的热更新把上述要素组合成一个可运行的示例参照 updates.zeek 的多轮热更新模式load base/frameworks/config module Test; export { option enable_feature F; option timeout_after 1min; } redef Config::config_files { /etc/zeek/live-config.dat }; event Input::end_of_data(name: string, source: string) { if ( sub_bytes(name, 1, 7) ! config- ) return; print config file reloaded; }之后运维只需原子替换/etc/zeek/live-config.dat先写新文件再mv覆盖# live-config.dat Test::enable_feature T Test::timeout_after 300.0Zeek 检测到文件变化后自动重读enable_feature变为Ttimeout_after变为 300 秒两条变更均以location /etc/zeek/live-config.dat写入config.log——全程无需重启、不丢失连接状态。若希望在脚本运行中主动推送配置例如基于业务逻辑则直接if ( Config::set_value(Test::enable_feature, T, policy-driven update) ) print config applied cluster-wide; else print config update failed;小结Zeek 配置框架以option关键字 配置文件 变更处理器 config.log四条主线把运行时配置管理做成了开箱即用的完整能力声明option声明可运行时可变的配置项注入Config::config_files持续监控外部文件原子替换生效Config::read_config一次性读取编程式更新Config::set_value全集群生效底层Option::set仅本节点生效感知Option::set_change_handler链式回调可校验、改写、拒绝变更审计所有变更写入config.log字段结构由Config::Info定义可通过Config::log_config事件与Config::log_policy钩子二次加工。想深入阅读实现细节的读者可继续查看框架脚本 scripts/base/frameworks/config/ 下三个文件、底层内置函数 src/option.bif、专用读取器 src/input/readers/config/Config.cc以及testing/btest/scripts/base/frameworks/config/目录下的全套回归测试含集群、多文件、热更新、weird 联动等场景。赞分享网络安全网络IDS【免费下载链接】zeekZeek is a powerful network analysis framework that is much different from the typical IDS you may know.项目地址https://gitcode.com/gh_mirrors/ze/zeek点击查看免费下载相关推荐RIOT ztimer 按需时钟基准测试测量并校准 ztimer_acquire()/ztimer_release() 的开销RIOT ztimer 按需时钟基准测试测量并校准 ztimer_acquire /ztimer_release 的开销 导读 本指南围绕 RIOT 操作系统网络安全网络IDSZeek 配置框架Configuration Framework实战指南运行时动态更新脚本选项Zeek 配置框架Configuration Framework实战指南运行时动态更新脚本选项 本指南系统讲解 Zeek 网络分析框架内置的配置框架Co网络安全网络IDSZeek 配置框架与 Config 输入读取器基于 Zeek_ConfigReader 插件的运行时选项更新机制Zeek 配置框架与 Config 输入读取器基于 Zeek_ConfigReader 插件的运行时选项更新机制 导读 本文围绕 Zeek 的配置框架及其底层网络安全网络IDS上一篇nunif iw3深度解析将任意2D视频转换为VR 3D SBS格式的10个技巧下一篇HCB装饰器模式应用提升视图层代码复用性创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表