ARTICLE DETAIL

资讯详情

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

Zeek Pcap 模块内置函数详解:动态管理 PCAP/BPF 抓包过滤器

Zeek Pcap 模块内置函数详解:动态管理 PCAP/BPF 抓包过滤器 网络安全网络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 仓库中 doc/scripts/base/bif/pcap.bif.zeek.rst 为骨架系统讲解Pcap命名空间下五个与抓包过滤相关的内置函数Pcap::precompile_pcap_filter、Pcap::install_pcap_filter、Pcap::error、Pcap::get_filter_state、Pcap::get_filter_state_string以及枚举设备接口的Pcap::findalldevs。读完本文你将掌握如何在 Zeek 脚本中动态编译、安装、查询 BPF 过滤器如何读懂过滤器的编译状态与错误信息并理解这些函数在 Zeek 底层iosource与packet-filter框架中的真实调用链。所有结论均以仓库内 src/iosource/pcap/pcap.bif、scripts/base/frameworks/packet-filter/main.zeek 与测试用例为准。一、Pcap 模块概览从 BIF 到抓包内核在 Zeek 中Pcap命名空间封装了与 libpcap 交互的内置函数它们通过.bifBuilt-In Function机制生成 Zeek 脚本可直接调用的函数。对应的 BIF 源文件位于 src/iosource/pcap/pcap.bif文档中给出的函数签名与行为均由该文件中的%%{ ... }%%C 代码实现。该模块同时声明了抓包相关的常量位于 scripts/base/init-bare.zeek常量类型默认值含义snaplencount—抓包快照长度bufsizecount—在线抓包缓冲区大小bufsize_offline_bytescount—离线读 pcap 文件缓冲区字节数non_fd_timeoutinterval20usec非文件描述符型包源的轮询超时这些常量说明Pcap模块不仅提供过滤函数也承载着 libpcap 底层抓包参数的配置入口。Pcap模块涉及的两个核心数据类型同样定义在 scripts/base/init-bare.zeek 中PcapFilterIDinit-bare.zeek#L1533-L1535枚举类型初始只有None用于标识不同的 BPF 过滤器Pcap::filter_stateinit-bare.zeek#L5975-L5980枚举{ ok, fatal, warning }描述过滤器编译/初始化的状态Pcap::Interface/Pcap::Interfacesinit-bare.zeek#L5955-L5973描述抓包接口的记录类型与接口集合。二、五个核心函数一览原文档 pcap.bif.zeek.rst 以 Summary 表格的形式列出全部函数整理如下函数签名作用Pcap::precompile_pcap_filter(id: PcapFilterID, s: string): bool预编译 PCAP 过滤器并绑定到给定标识符Pcap::install_pcap_filter(id: PcapFilterID): bool安装已预编译的过滤器Pcap::error(): string返回最后一次 PCAP 错误的字符串表示Pcap::get_filter_state(id: PcapFilterID): Pcap::filter_state返回过滤器初始化状态Pcap::get_filter_state_string(id: PcapFilterID): string返回过滤器初始化产生的错误信息字符串Pcap::findalldevs(): Pcap::Interfaces枚举本机所有可用的抓包设备其中前五个构成编译 → 安装 → 查询 → 排错的完整动态过滤工作流findalldevs则用于设备发现。三、预编译过滤器Pcap::precompile_pcap_filter3.1 文档定义的接口function Pcap::precompile_pcap_filter(id: PcapFilterID, s: string): bool参数id用于后续引用过滤器s的 PCAP 标识符参数sPCAP 过滤表达式合法语法参见man tcpdump返回值s合法且预编译成功时返回T否则返回F。3.2 源码实现与限制src/iosource/pcap/pcap.bif#L36-L60 中的实现揭示了两个关键细节ID 空间上限为 100id-AsEnum() 100时直接报错并返回false。原因是底层用 vector 存储过滤器以支持快速查找限制 ID 空间防止其无限增长。错误信息为PCAP filter ids must remain below 100 (is N)。编译状态联动实现通过zeek::iosource_mgr-GetPktSrc()获取当前活动的包源PktSrc调用其PrecompileFilter(id, s)虚方法默认实现见 src/iosource/PktSrc.h#L188随后取得对应的BPF_Program并检查其状态只有编译成功且过滤器状态为FilterState::OK时函数才返回T。BPF_Program是对 libpcapstruct bpf_program的封装定义于 src/iosource/BPF_Program.h其Compile()方法内部对应pcap_compile()。对 libpcap 源而言编译发生在 src/iosource/pcap/Source.cc#L266-L279 的PcapSource::CompileFilter()中失败时错误信息形如cannot compile BPF filter ... : 详情。3.3 何时使用预编译的目的是把语法检查与真正的安装分离脚本可以先在任何时刻例如zeek_init验证过滤器表达式是否合法再在合适的时机如某个事件触发时将其安装生效避免在流量处理的关键路径上执行昂贵的编译。四、安装过滤器Pcap::install_pcap_filter4.1 文档定义的接口function Pcap::install_pcap_filter(id: PcapFilterID): bool参数id已通过Pcap::precompile_pcap_filter预编译过的过滤器标识符返回值与id关联的过滤器安装成功时返回T。4.2 源码实现src/iosource/pcap/pcap.bif#L80-L89 中安装动作最终落到包源的SetFilter(id)纯虚方法见 src/iosource/PktSrc.h#L202zeek::iosource::PktSrc* ps zeek::iosource_mgr-GetPktSrc(); if ( ps ! ps-SetFilter(id-AsInt()) ) success false;不同的包源实现各不相同libpcap 源PcapSource在 src/iosource/pcap/Source.cc#L282 实现将预编译的 BPF 程序绑定到 pcap 句柄AF_Packet 源AF_PacketSource在 src/iosource/af_packet/AF_Packet.cc#L318-L322 实现PrecompileFilter与SetFilterpcapng 源SetFilter直接返回truesrc/iosource/pcapng/Source.h#L36即对 pcapng 输入不做过滤。这说明Pcap模块的过滤器机制是包源无关的抽象同一套脚本接口可驱动不同底层抓包引擎。4.3 典型用法先预编译再安装仓库测试 testing/btest/core/pcap/dynamic-filter.zeek 展示了标准的两阶段用法redef enum PcapFilterID { A, B }; event zeek_init() { if ( ! Pcap::precompile_pcap_filter(A, port 80) ) print error 1; if ( ! Pcap::precompile_pcap_filter(B, port 53) ) print error 2; } event new_packet(c: connection, p: pkt_hdr) { cnt; if ( cnt 1 ) if ( ! Pcap::install_pcap_filter(A) ) print error 3; if ( cnt 2 ) if ( ! Pcap::install_pcap_filter(B) ) print error 4; }该测试使用wikipedia.pcap离线流量zeek_init阶段预编译port 80与port 53两个过滤器然后在new_packet事件中先后安装验证先编译后安装的完整链路。五、读取过滤状态get_filter_state与get_filter_state_string5.1Pcap::get_filter_statefunction Pcap::get_filter_state(id: PcapFilterID): Pcap::filter_state返回过滤器初始化状态若当前没有活动包源或过滤器 ID 不存在则返回ok。实现见 src/iosource/pcap/pcap.bif#L128-L139通过ps-GetBPFFilter(id)获取BPF_Program后将其GetState()映射为Pcap::filter_state枚举值返回。FilterState的 C 定义在 src/iosource/BPF_Program.h#L16-L20enum class FilterState : uint8_t { OK, FATAL, // results in Reporter::Error WARNING // results in Reporter::Warning };与 Zeek 侧的枚举{ ok, fatal, warning }init-bare.zeek#L5976-L5980一一对应fatal表示会阻止 Zeek 继续运行的问题warning表示非致命、仅需记录的告警。5.2Pcap::get_filter_state_stringfunction Pcap::get_filter_state_string(id: PcapFilterID): string返回过滤器初始化过程中报告的警告/错误信息有错误信息时返回对应字符串未遇到任何问题时返回空字符串若没有活动包源或过滤器 ID 不存在返回unknown。实现src/iosource/pcap/pcap.bif#L152-L162直接返回BPF_Program::GetStateMessage()src/iosource/BPF_Program.h#L76这是 libpcap 编译过程中产生的原始错误文本。5.3 在 PacketFilter 框架中的组合使用这两个函数被 scripts/base/frameworks/packet-filter/main.zeek 中的install()函数组合使用构成完整的失败处理流程main.zeek#L300-L326if ( ! Pcap::precompile_pcap_filter(DefaultPcapFilter, tmp_filter) ) { local state Pcap::get_filter_state(DefaultPcapFilter); if ( state Pcap::fatal ) { NOTICE(Notice::Info($noteCompile_Failure, $msgfmt(Compiling packet filter failed), $subtmp_filter)); error_string fmt(Bad pcap filter %s: %s, tmp_filter, Pcap::get_filter_state_string(DefaultPcapFilter)); if ( network_time() 0.0 ) Reporter::fatal(error_string); else Reporter::warning(error_string); } else if ( state Pcap::warning ) Reporter::warning(fmt(Warning while compiling pcap filter %s: %s, tmp_filter, Pcap::get_filter_state_string(DefaultPcapFilter))); }安装失败时同样使用状态字符串作为日志与 Notice 的原因main.zeek#L347-L356。由此可见get_filter_state决定错误等级fatal/warningget_filter_state_string提供可读的排错细节二者配合支撑了Compile_Failure、Install_Failure、Too_Long_To_Compile_Filter三类 Noticemain.zeek#L21-L30。六、获取错误信息Pcap::errorfunction Pcap::error(): string返回最后一次 PCAP 函数失败的描述性错误信息若没有活动包源或没有错误则返回no error。实现见 src/iosource/pcap/pcap.bif#L105-L116直接返回包源的ErrorMsg()。该函数通常与下面第七节的地址/子网过滤函数配合使用作为失败诊断的补充。七、相关联的包过滤函数族Pcap模块的函数在文档中多次以zeek:see::交叉引用一组全局过滤函数它们定义在 src/zeek.bif 中用于按概率丢弃特定方向的报文函数签名作用install_src_addr_filter(ip: addr, tcp_flags: count, prob: double): bool安装按源地址丢弃报文的过滤器install_src_net_filter(snet: subnet, tcp_flags: count, prob: double): bool安装按源子网丢弃报文的过滤器uninstall_src_addr_filter(ip: addr): bool移除源地址过滤器uninstall_src_net_filter(snet: subnet): bool移除源子网过滤器install_dst_addr_filter(ip: addr, tcp_flags: count, prob: double): bool安装按目的地址丢弃报文的过滤器install_dst_net_filter(snet: subnet, tcp_flags: count, prob: double): bool安装按目的子网丢弃报文的过滤器uninstall_dst_addr_filter(ip: addr): bool移除目的地址过滤器uninstall_dst_net_filter(snet: subnet): bool移除目的子网过滤器以install_src_addr_filter为例src/zeek.bif#L5333-L5337其实现委托给packet_mgr-GetPacketFilter()-AddSrc(...)tcp_flags表示若这些 TCP 标志位均未设置则以prob概率丢弃来自该地址/子网的报文prob取值区间为[0.0, 1.0]。这类过滤器用于丢包采样与缓解而非 BPF 语法过滤与Pcap::precompile_pcap_filter的机制互补。八、枚举抓包设备Pcap::findalldevsfunction Pcap::findalldevs(): Pcap::Interfaces返回本机全部可用抓包接口的集合类型为Pcap::Interfaces即set[Pcap::Interface]。实现src/iosource/pcap/pcap.bif#L164-L216直接调用 libpcap 的pcap_findalldevs()失败时通过emit_builtin_error报告错误并返回空集合。返回的Pcap::Interface记录scripts/base/init-bare.zeek#L5955-L5971字段如下字段类型说明namestring接口/设备名descriptionstring optional设备的人类可读描述addrsset[addr]设备关联的网络地址is_loopbackbool是否为回环接口如127.0.0.1、[::1]is_upbool optional设备是否处于 up 状态libpcap ≥ 1.6.1 可用is_runningbool optional设备是否处于运行状态libpcap ≥ 1.6.1 可用值得注意的实现细节is_up与is_running字段被#ifdef PCAP_IF_UP保护pcap.bif#L205-L209因为这两个标志直到 libpcap 1.6.1 才出现——这体现了 Zeek 对旧版 libpcap 的兼容性处理。IPv4 与 IPv6 地址会分别从sockaddr_in/sockaddr_in6转换为 Zeek 的addr类型后以set[addr]返回。九、深入实践packet-filter框架中的动态过滤机制9.1 框架如何扩展PcapFilterIDPcapFilterID初始只有Noneinit-bare.zeek#L1533-L1535而 packet-filter/main.zeek#L150-L153 通过redef enum PcapFilterID { DefaultPcapFilter, FilterTester }增加两个内置 IDDefaultPcapFilter当前生效的抓包过滤器FilterTester用于验证过滤器表达式合法性的临时 ID。test_filter()函数main.zeek#L155-L164演示了FilterTester的用途先用Pcap::precompile_pcap_filter(FilterTester, filter)验证表达式失败即返回F。Zeek 启动时用它对capture_filters与restrict_filters中的每个过滤器做预验证非法表达式直接触发Reporter::fatalmain.zeek#L180-L192。9.2 过滤器的组装优先级框架的build()函数main.zeek#L242-L285揭示了 Zeek 中各类过滤器的最终组合逻辑命令行过滤器优先若通过-f等命令行参数指定了cmd_line_bpf_filter直接采用覆盖脚本定义的所有过滤器否则按capture_filters表以or合并捕获过滤器未定义时使用default_capture_filter默认ip or not ip即捕获所有流量若启用enable_auto_protocol_capture_filters再与Analyzer::get_bpf()按协议自动生成的过滤器做or合并所有restrict_filters与动态dynamic_restrict_filters即exclude添加的排除过滤器自动包上not (...)以and合并为限制过滤器最后将捕获过滤器与限制过滤器以and组合并叠加unrestricted_filteror与restricted_filterand两个全局常量默认均为空串。9.3 动态过滤的完整生命周期脚本可通过exclude(filter_id, filter)、exclude_for(filter_id, filter, span)、remove_exclude(filter_id)动态增删排除过滤器main.zeek#L206-L240。每次变更都会触发install()重新构建并安装过滤器install()先比较新过滤器与current_filter未变化则直接返回避免无谓重装见 main.zeek#L294-L296接着调用Pcap::precompile_pcap_filter(DefaultPcapFilter, tmp_filter)预编译通过后调用Pcap::install_pcap_filter(DefaultPcapFilter)真正生效若编译耗时超过max_filter_compile_time默认100msec触发Too_Long_To_Compile_FilterNoticemain.zeek#L327-L330每次安装尝试都会写入packet_filter日志流Info记录含ts、node、filter、init、success、failure_reason等字段见 main.zeek#L34-L54便于审计与排障。此外filter_change_tracking事件每 5 分钟检查一次filter_changed标志main.zeek#L168-L174确保兼容先注册变更、后统一安装的插件式过滤机制。9.4 更多测试用例佐证仓库中另有两条针对性测试 testing/btest/core/pcap/filter-error.zeek 与 testing/btest/core/pcap/input-error.zeek 覆盖了非法过滤器、读取输入失败等错误路径testing/btest/opt/ZAM-bif-tracking.zeek 则验证了Pcap模块函数在 ZAM 优化下的行为。另外 src/script_opt/FuncInfo.cc#L133-L134 将Pcap::get_filter_state与Pcap::get_filter_state_string标记为ATTR_NO_ZEEK_SIDE_EFFECTS无 Zeek 副作用意味着编译器可以对它们进行更积极的优化——这是从源码结构可以推断的实现细节。十、总结与最佳实践围绕 pcap.bif.zeek.rst 文档所定义的函数族Zeek 的Pcap模块提供了一套完整、包源无关的动态过滤能力两阶段过滤precompile_pcap_filter负责语法校验与编译注意 ID 必须小于 100install_pcap_filter负责生效二者分离使运行时切换过滤器成为可能状态可观测get_filter_state给出ok/fatal/warning三态判定get_filter_state_string给出可读错误文本配合Pcap::error可快速定位编译失败还是安装失败框架级集成packet-filter框架将上述函数封装为default_capture_filter、restrict_filters、capture_filters、exclude等高层配置普通用户通常无需直接调用Pcap函数但理解其原理有助于排查packet_filter日志与相关 Notice设备发现findalldevs在需要枚举本机网卡的脚本场景如自动选择抓包接口中可直接使用。实践建议当你在脚本中自定义动态过滤器时优先复用packet-filter框架的exclude/exclude_for接口只有需要精细控制多个独立过滤器的编译与安装时机时才直接使用Pcap::precompile_pcap_filter与Pcap::install_pcap_filter并记得为每个过滤器分配独立的PcapFilterID枚举值同时检查返回值与get_filter_state_string的输出。赞分享网络安全网络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点击查看免费下载相关推荐如何快速掌握Wireshark抓包过滤器BPF语法完全指南如何快速掌握Wireshark抓包过滤器BPF语法完全指南 Wireshark是一款功能强大的网络协议分析工具而BPFBerkeley Packet Fi网络通信obsidian-skills 完全指南AI 看懂 Obsidian 的 5 种文件2 步接入 OpenCodeobsidian skills 完全指南AI 看懂 Obsidian 的 5 种文件2 步接入 OpenCode obsidian skills 是给 AIAI 技能AI 插件上一篇3分钟实现完全离线OCR天若OCR本地版让你的文字识别更安全高效下一篇3分钟构建企业级HTTP文件服务器chfsgui图形化文件共享工具深度解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表