
网络安全网络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 内置 Supervisor 框架核心 API 的权威技术指南内容以 api.zeek 的官方 API 文档api.zeek.rst为主体骨架并深入其脚本层实现与 C 底层源码。读完本文你将掌握如何使用Supervisor::create拉起持久的 Zeek 子进程、如何通过NodeConfig/ClusterEndpoint编排一个完整集群、如何用事件与钩子接管子进程的标准输出以及如何借助 Broker 远程控制 Supervisor 进程树。Supervisor 框架为 Zeek 引入了一种全新的运行模式由一个监督者进程Supervisor管理一组应当长期存活的 Zeek 子进程任何进程意外退出都会被自动复活整个进程树在 Supervisor 退出时有序关闭。该 API 自 Zeek 3.1.0 引入并在 4.0.0 起趋于稳定在此之前它可能在不经通知的情况下发生不兼容变更。本文所有代码示例均来自当前仓库的真实脚本可直接复制运行。Supervisor API 概览命名空间与组成Supervisor API 全部位于Supervisor命名空间下共分为四类构件类别成员说明类型TypesSupervisor::ClusterEndpoint、Supervisor::ClusterRole、Supervisor::NodeConfig、Supervisor::NodeStatus、Supervisor::Status描述被监督节点及其集群角色、当前状态事件EventsSupervisor::node_status节点重新启动成功时的通知钩子HooksSupervisor::stdout_hook、Supervisor::stderr_hook接管所有子进程的标准输出/错误流函数FunctionsSupervisor::create、Supervisor::destroy、Supervisor::is_supervised、Supervisor::is_supervisor、Supervisor::node、Supervisor::restart、Supervisor::status节点生命周期管理与运行环境查询脚本层的类型与函数声明定义在 scripts/base/frameworks/supervisor/api.zeek实现则位于 scripts/base/frameworks/supervisor/main.zeek底层与 C 引擎交互的 BIF 桥接层见 src/supervisor/supervisor.bif。核心类型详解ClusterRole节点在集群框架中的角色Supervisor::ClusterRole是一个枚举定义了被监督节点在 Zeek Cluster Framework 中将要扮演的角色取值如下枚举值含义Supervisor::NONE不参与集群作为独立节点运行Supervisor::LOGGER集群日志记录节点Supervisor::MANAGER集群管理节点Supervisor::PROXY集群代理节点Supervisor::WORKER集群工作节点通常负责抓包与分析从源码看该枚举定义于 api.zeek并同步映射到 BIF 层supervisor.bif供 C 侧识别角色。ClusterEndpoint集群中某个节点的端点描述Supervisor::ClusterEndpoint是一个 record描述集群布局中一个被监督节点的端点信息注意它描述的是节点配置而非单条连接字段类型必填/可选说明roleClusterRole必填该集群节点扮演的角色hostaddr必填集群节点运行的主机/IPpport必填集群节点监听的 TCP 端口interfacestringoptional节点读取/分析数据包的网络接口名通常由 worker 节点使用pcap_filestringoptional节点读取/分析数据包的 PCAP 文件名通常由 worker 节点使用metrics_portportoptional节点向 Prometheus 暴露指标的 TCP 端口NodeConfig被监督节点的完整配置Supervisor::NodeConfig是create 调用最核心的参数完整控制被监督节点的行为字段类型默认值/可选说明namestring必填节点名称在给定监督进程树内唯一通常人类可读interfacestringoptional节点读取/分析数据包的网络接口名pcap_filestringoptional节点读取/分析数据包的 PCAP 文件名directorystringoptional节点使用的工作目录stdout_filestringoptional节点 stdout 重定向到的文件路径stderr_filestringoptional节点 stderr 重定向到的文件路径bare_modebooloptional是否以 bare 模式启动节点省略时继承 Supervisor 自身的 bare-mode 状态addl_base_scriptsvector of stringdefault []在 base 脚本之后、任何用户指定脚本之前加载的附加脚本addl_user_scriptsvector of stringdefault []在用户指定脚本之后加载的附加脚本envtable[string] of stringdefault {}在节点中定义的环境变量cpu_affinityintoptional节点尝试将自己绑定到的 CPU/核编号clustertable[string] of ClusterEndpointdefault {}集群布局定义键为节点名其中cluster字段值得特别说明集群框架中的每个节点都知晓自己所归属的完整、静态的集群拓扑。当 Supervisor 孵化被监督节点时会自动把这个表翻译成正确的 Cluster Framework 配置——例如同时填充CLUSTER_NODE环境变量和Cluster::nodes表参见 api.zeek 的注释。在 C 侧该字段被序列化为 JSON 字符串保存见 Supervisor.h。NodeStatus 与 Status状态查询结果Supervisor::NodeStatus单个被监督节点的当前状态含两个字段——node: NodeConfig期望的节点配置与pid: int optional节点当前或最后已知的进程 ID进程尚未启动时可能未初始化。Supervisor::Status一组被监督节点的状态仅含一个字段nodes: table[string] of NodeStatus以节点名为键。两者定义于 api.zeek是Supervisor::status函数的返回类型。生命周期管理函数Supervisor命名空间下共 7 个函数其中create、destroy、restart、status四个只能由 Supervisor 进程调用从其他进程调用是错误用法。create孵化新的被监督节点function Supervisor::create(node: NodeConfig): string传入期望的节点配置返回空字符串表示成功否则返回错误/失败描述。官方示例中典型的调用方式local sn Supervisor::NodeConfig($namefoo, $interfaceen0); local res Supervisor::create(sn); if ( res ) print supervisor created a new node; else print supervisor failed to create node, res;destroy / restart / status节点销毁、重启与状态查询function Supervisor::destroy(node: string default): bool function Supervisor::restart(node: string default): bool function Supervisor::status(node: string default): Status三个函数都接受节点名作为参数且都支持**空字符串表示全部节点**这一特殊语义destroy销毁并移除被监督节点成功返回true。restart通过先销毁kill再重新创建的方式重启节点成功返回true。status返回当前状态——空串时返回所有节点的Status指定名字时返回该节点的状态。is_supervisor / is_supervised / node进程角色判定这三个函数用于让同一份脚本在 Supervisor 进程与子进程中都正确运行is_supervisor(): bool—— 当前进程是否为 Supervisor 进程。is_supervised(): bool—— 当前进程是否为被监督节点进程。node(): NodeConfig—— 若当前进程是被监督节点返回其节点配置从非被监督进程调用是错误。值得注意由Supervisor::create孵化的子进程会继承 Supervisor 进程加载的脚本命令行参数也基本全部继承唯一不继承的是-r读 PCAP与-i实时接口这两个参数。因此脚本作者常用is_supervisor()与is_supervised()区分角色分支用node()$name进一步区分多个子进程。事件与钩子感知节点状态、接管输出流node_status 事件event Supervisor::node_status(node: string, pid: count)Supervisor 在收到来自 stem 进程的状态消息更新、确认某个节点已重新启动时触发。node是通过Supervisor::create创建过的节点名pid是 stem 上报的进程 ID。该事件在 main.zeek 中实现收到后立即通过 Broker 发布到SupervisorControl::topic_prefix /node_status实现远程通知。stdout_hook 与 stderr_hookhook Supervisor::stdout_hook(node: string, msg: string): bool hook Supervisor::stderr_hook(node: string, msg: string): bool这两个钩子接管所有子进程包括内部 stem 进程的 stdout/stderr 行缓冲输出。关键语义node消息来源的节点名此前通过create创建空值表示消息来自内部 supervisor stem 进程这种情况通常不应发生。msg子进程 stdout/stderr 的行缓冲内容。若钩子以break结束将抑制该行输出到关联流stdout/stderr。例如希望过滤某个节点的调试噪音可以这样注册hook Supervisor::stdout_hook(node: string, msg: string) { if ( node noisy-node /DEBUG/ in msg ) break; # 抑制该行 }钩子声明见 api.zeek。实战一监督一个抓包节点官方框架文档doc/frameworks/supervisor.rst给出了最简用法simple-supervisor.zeekevent zeek_init() { if ( Supervisor::is_supervisor() ) { local sn Supervisor::NodeConfig($namefoo, $interfaceen0); local res Supervisor::create(sn); if ( res ) print supervisor created a new node; else print supervisor failed to create node, res; } else print fmt(supervised node %s zeek_init(), Supervisor::node()$name); } event zeek_done() { if ( Supervisor::is_supervised() ) print fmt(supervised node %s zeek_done(), Supervisor::node()$name); else print supervisor zeek_done(); }运行方式$ zeek -j simple-supervisor.zeek其中-j是开启 Supervisor 模式的关键命令行参数详见 supervisor.rst。本地测试时请把en0换成真实可嗅探的接口名若接口启用了校验和卸载checksum offloading可加-C忽略校验和$ zeek -j -C simple-supervisor.zeek可以看到这份脚本在 Supervisor 进程和子进程中都被加载执行靠is_supervisor()/is_supervised()分支子进程侧再用Supervisor::node()$name打印自己的节点名。Supervisor 退出时整个进程树会有序关闭子进程的zeek_done()同样会被触发。实战二用 Supervisor 编排完整集群cluster-supervisor.zeek 展示了如何一键拉起 manager、logger、proxy、worker 四类节点event zeek_init() { if ( ! Supervisor::is_supervisor() ) return; Broker::listen(127.0.0.1, 9999/tcp); local cluster: table[string] of Supervisor::ClusterEndpoint; cluster[manager] [$roleSupervisor::MANAGER, $host127.0.0.1, $p10000/tcp]; cluster[logger] [$roleSupervisor::LOGGER, $host127.0.0.1, $p10001/tcp]; cluster[proxy] [$roleSupervisor::PROXY, $host127.0.0.1, $p10002/tcp]; cluster[worker] [$roleSupervisor::WORKER, $host127.0.0.1, $p10003/tcp, $interfaceen0]; for ( n, ep in cluster ) { local sn Supervisor::NodeConfig($namen); sn$cluster cluster; sn$directory n; if ( ep?$interface ) sn$interface ep$interface; local res Supervisor::create(sn); if ( res ! ) print fmt(supervisor failed to create node %s: %s, n, res); } }要点拆解用Supervisor::ClusterEndpoint记录构造cluster表键为节点名值为端点信息角色、地址、端口、接口。每个节点创建独立的NodeConfigname取自节点名cluster填入完整拓扑集群框架要求每个节点都知道完整静态拓扑directory设为节点名对应的子目录使各节点工作目录隔离。worker 节点的接口名从ClusterEndpoint的interface字段传递到NodeConfig。Broker::listen(127.0.0.1, 9999/tcp)让 Supervisor 监听自己的端口供外部远程控制见下文。子进程的 stdout/stderr 输出会自动经由 Supervisor 转发并加上节点名前缀便于区分来源见 supervisor.rst。运行$ zeek -j cluster-supervisor.zeek实战三通过 Broker 远程控制 SupervisorSupervisor 进程除了提供本地 API还能作为 Broker 端点接收远程指令。远程控制 API 定义在SupervisorControl命名空间control.zeek包含两个可重定义选项选项类型默认值说明SupervisorControl::topic_prefixstringredefzeek/supervisor订阅 Supervisor API 请求、发布响应所用的 Broker topic 前缀SupervisorControl::enable_listenboolredefF启用后Supervisor 将监听配置的Broker::default_listen_address以及一组成对事件create_request/create_response、status_request/status_response、restart_request/restart_response、destroy_request/destroy_response、stop_request无响应Supervisor 收到即终止自身进程树、node_statusSupervisor::node_status的远程等价物。官方控制端示例 supervisor-control.zeekevent zeek_init() { Broker::peer(127.0.0.1, 9999/tcp, 1sec); } event Broker::peer_added(endpoint: Broker::EndpointInfo, msg: string) { Broker::publish(SupervisorControl::topic_prefix, SupervisorControl::restart_request, , ); } event SupervisorControl::restart_response(reqid: string, result: bool) { print fmt(got result of supervisor restart request: %s, result); terminate(); }运行$ zeek supervisor-control.zeek它会连接到 9999 端口上的 Supervisor建立 Broker 对等关系后发布restart_requestreqid与node均为空串含义是重启全部节点——适合改完脚本后热重载整个集群。请求中的reqid是任意字符串会被原样回显到响应中用于关联请求与响应。在 main.zeek 中可以看到请求分发的机制zeek_init时若is_supervisor()且enable_listen则Broker::listen()随后Cluster::subscribe(SupervisorControl::topic_prefix)订阅控制 topic。每个*_request事件处理函数都会调用对应的本地 API并把结果发布回topic_prefix/操作/reqid主题。stop_request处理最简单——直接terminate()关闭整个进程树main.zeek。内部架构Supervisor → Stem → 被监督节点理解 API 背后的进程模型有助于合理预估资源占用与故障行为。官方文档supervisor.rst明确说明顶层 Supervisor 进程并不直接管理被监督节点而是先孵化一个中间进程Stem由 Stem 负责被监督节点的生命周期。这样设计有两个原因避免对子进程执行exec()——否则每次孵化都依赖文件系统上当时的zeek二进制版本系统升级期间可能引发兼容性/竞态问题。唯一仍需要exec()的情形是 Stem 进程本身意外死亡属于罕见场景此时 Supervisor 依据Supervisor::Config::zeek_exe_path记录在 Supervisor.h重新 forkexec 出 Stem。Zeek 运行时普遍污染全局状态尽早fork()出 Stem 相当于保留一份纯净的基线镜像供所有被监督进程复用。因此实际存在两级监督Supervisor 复活 StemStem 复活自己的子节点。此外Stem 和任何被监督子进程都会自动检测是否与父进程失联并自我终止Stem 每秒钟从其poll()循环醒来检查父 PID 是否变化被监督节点则通过一个周期性TimerParentProcessCheckTimer见 Supervisor.cc完成同样检查。除失联检查与配置获取方式外被监督节点运行期与普通 Zeek 进程并无差异。节点复活策略指数退避supervisor.rst 与 Supervisor.cc 共同确认了节点复活Node Revival的确切算法三个硬编码常量如下constexpr auto attempts_before_delay_increase 3; // 每个延迟档位最多尝试 3 次 constexpr auto delay_increase_factor 2; // 每档结束后延迟翻倍 constexpr auto reset_revival_state_after 30; // 节点存活满 30 秒后重置复活状态行为归纳从1 秒延迟开始Stem 尝试复活节点最多 3 次此后复活延迟翻倍2 秒、4 秒、8 秒……每档再试最多 3 次如此无限继续——Stem永不放弃任何节点但延迟持续增长一旦节点存活超过 30 秒复活状态清零下次意外退出时重新从 1 秒延迟开始。也就是说频繁崩溃的节点不会被高频轰炸式重启而是逐渐降低重启频率稳定的节点则始终获得快速恢复。BIF 层与 C 桥接脚本 API 最终由 src/supervisor/supervisor.bif 桥接到 C 引擎zeek::supervisor_mgr。几个值得注意的实现事实__status/__create/__destroy/__restart在zeek::supervisor_mgr为空时即未以-j启动 Supervisor 模式会报错supervisor mode not enabledcreate 此时返回该错误字符串——这与从非 Supervisor 进程调用是错误的文档语义一致。__is_supervisor直接判断zeek::supervisor_mgr ! nullptr__is_supervised判断Supervisor::ThisNode().has_value()__node从ThisNode()-config.ToRecord()还原脚本层的NodeConfigrecord。脚本层的NodeConfig在 C 侧对应Supervisor::NodeConfig结构体Supervisor.h并通过FromRecord/ToRecord/ToJSON/FromJSON在脚本层 record 与 JSON 之间转换——这为未来进程间传递配置提供了序列化基础。BIF 中还有一个未出现在脚本 API 文档的Supervisor::__stem_pid()Supervisor 进程返回 stem PID被监督节点返回父 PID可用于调试进程树关系supervisor.bif。使用限制与注意事项调用主体限制create、destroy、restart、status只能由 Supervisor 进程调用node只能由被监督节点调用。混用会导致运行期错误。API 稳定性该 API 自 3.1.0 引入在 4.0.0 之前视为不稳定可能不经弃用警告直接不兼容变更。参数继承子进程继承 Supervisor 的大多数命令行参数但-rPCAP与-i实时接口不继承必须在NodeConfig中显式指定interface/pcap_file。命名唯一性节点名在给定监督进程树内必须唯一destroy/restart/status的空串参数会作用于全部节点操作前请确认意图。远程控制若要使用SupervisorControl的远程事件需在 Supervisor 侧显式Broker::listen(...)如集群示例中的 9999 端口否则外部无法连接enable_listen选项默认关闭。输出重定向stdout_file/stderr_file与stdout_hook/stderr_hook都可用于处理子进程输出——前者重定向到文件后者在脚本内接管钩子以break结束可抑制对应行。延伸阅读API 完整文档api.zeek.rst 远程控制文档control.zeek.rst框架概念与架构说明doc/frameworks/supervisor.rst脚本层实现main.zeek control.zeek api.zeek引擎层实现Supervisor.cc Supervisor.h supervisor.bif官方示例simple-supervisor.zeek cluster-supervisor.zeek supervisor-control.zeek赞分享网络安全网络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 Supervisor 框架实战指南进程监督、节点复活与集群部署Zeek Supervisor 框架实战指南进程监督、节点复活与集群部署 导读 Supervisor 是 Zeek 内置的一套进程监督框架位于 src/su网络安全网络IDSSupervisor XML-RPC API 完全指南supervisord 远程控制、进程管理与日志读取接口详解Supervisor XML RPC API 完全指南supervisord 远程控制、进程管理与日志读取接口详解 导读 本文是 Supervisorsup运维Zeek 控制框架Control Framework详解基于 Broker 的远程运行时控制与信息采集Zeek 控制框架Control Framework详解基于 Broker 的远程运行时控制与信息采集 Control framework 是 Zeek网络安全网络IDS上一篇Android MenuDrawer 开源项目教程下一篇Stylebot代码编辑器详解轻松编写专业级自定义CSS创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考