- 网络安全
- 网络
- IDS
【免费下载链接】zeek
Zeek is a powerful network analysis framework that is much different from the typical IDS you may know.
导读
base/packet-protocols是 Zeek 网络分析框架中负责"报文级"(packet-level)协议解析的基础脚本包。本文以 Zeek 仓库中该包的官方索引文档doc/scripts/base/packet-protocols/index.rst为骨架,逐层讲解其目录结构、加载约定、数据链路层与网络层的协议分发、隧道封装协议链,以及PacketAnalyzer::register_packet_analyzer等注册接口的底层原理。读完本文,你将理解 Zeek 是如何从网卡原始帧一路分拣出 Ethernet、VLAN、IP、TCP/UDP、GRE、VXLAN 等嵌套协议的,并能依据源码路径定位任意一层协议的分析器实现。
包的整体结构与加载顺序
base/packet-protocols是 Zeek 基础脚本集(scripts/base)的一部分,通过 scripts/base/init-default.zeek 等初始化脚本在启动时自动加载。官方索引文档 doc/scripts/base/packet-protocols/index.rst 完整罗列了该包的每一个脚本文件,从中可以归纳出它的组织惯例:
- 每个协议子目录下都包含一个
__load__.zeek(加载入口)和一个main.zeek(核心实现); - 个别协议额外携带类型定义与事件定义文件,例如
igmp/types.zeek和igmp/spicy-events.zeek。
顶层加载入口 scripts/base/packet-protocols/load.zeek 以固定的@load顺序串联全部子模块,这个顺序本身就是报文解析链路的先后顺序:
@load ./main.zeek @load base/packet-protocols/root @load base/packet-protocols/ip @load base/packet-protocols/skip @load base/packet-protocols/ethernet @load base/packet-protocols/fddi @load base/packet-protocols/ieee802_11 @load base/packet-protocols/ieee802_11_radio @load base/packet-protocols/linux_sll @load base/packet-protocols/linux_sll2 @load base/packet-protocols/nflog @load base/packet-protocols/null @load base/packet-protocols/ppp @load base/packet-protocols/ppp_serial @load base/packet-protocols/pppoe @load base/packet-protocols/vlan @load base/packet-protocols/mpls @load base/packet-protocols/pbb @load base/packet-protocols/vntag @load base/packet-protocols/udp @load base/packet-protocols/tcp @load base/packet-protocols/icmp @load base/packet-protocols/igmp @load base/packet-protocols/llc @load base/packet-protocols/novell_802_3 @load base/packet-protocols/snap @load base/packet-protocols/gre @load base/packet-protocols/iptunnel @load base/packet-protocols/ayiya @load base/packet-protocols/geneve @load base/packet-protocols/vxlan @load base/packet-protocols/teredo @load base/packet-protocols/gtpv1可以看到,基础链路层/网络层协议在前,隧道与封装协议(GRE、IPTunnel、AYIYA、Geneve、VXLAN、Teredo、GTPv1)在后,这与"外层先注册、内层后注册"的解析链语义保持一致。
顶层main.zeek(scripts/base/packet-protocols/main.zeek)定义了包的核心 API 与约束,是整个包的"门面":
module PacketAnalyzer; @load base/frameworks/analyzer/main.zeek export { ## Registers a set of well-known ports for an analyzer. ... global register_for_ports: function(parent: PacketAnalyzer::Tag, child: PacketAnalyzer::Tag, server_ports: set[port], non_server_ports: set[port] &default=set()) : bool; ## Registers an individual well-known port for an analyzer. ... global register_for_port: function(parent: PacketAnalyzer::Tag, child: PacketAnalyzer::Tag, p: port) : bool; ## The maximum depth of the packet analyzer chains. ... const max_depth: count = 25 &redef; }其中max_depth默认值为 25,用于限制报文分析器链的最大嵌套深度;一旦超过,会触发max_packet_analyzer_depth_exceeded这一 weird 记录,将其设为 0 可以禁用该限制。对于深度嵌套的隧道报文(如多层 GRE/VXLAN 叠加),这个值决定了 Zeek 能"拆到第几层洋葱"。
注册机制:端口绑定与链深度控制
register_for_ports与register_for_port是脚本层暴露给分析器插件的两个便捷封装,其底层实现在同一个文件中:
function register_for_ports(parent: PacketAnalyzer::Tag, child: PacketAnalyzer::Tag, server_ports: set[port], non_server_ports: set[port] &default=set()) : bool { local rc = T; for ( p in server_ports ) { if ( ! register_for_port(parent, child, p) ) rc = F; } for ( p in non_server_ports ) { if ( ! register_for_port(parent, child, p) ) rc = F; } # Automatically update likely_server_ports with server_ports likely_server_ports += server_ports; return rc; } function register_for_port(parent: PacketAnalyzer::Tag, child: PacketAnalyzer::Tag, p: port) : bool { register_packet_analyzer(parent, p as count, child); if ( child !in Analyzer::ports ) Analyzer::ports[child] = set(); add Analyzer::ports[child][p]; return T; }关键语义(来自源码注释与实现):
register_for_ports是"加法"语义,向已注册的端口集合中追加,而不是替换;server_ports会同时自动加入likely_server_ports,而non_server_ports(如客户端端口)不会;register_for_port最终调用 BIF 函数register_packet_analyzer(声明见 src/packet_analysis/packet_analysis.bif),并在Analyzer::ports表中记录该分析器绑定的端口,供后续报文分发时查询;- 同文件还声明了
try_register_packet_analyzer_by_name(src/packet_analysis/packet_analysis.bif),允许按字符串名称注册分析器,失败时返回 false 而不抛错。
一个典型调用例子是 GRE 分析器把 UDP 端口 4754 绑定给自己(scripts/base/packet-protocols/gre/main.zeek):
module PacketAnalyzer::GRE; export { const default_analyzer: PacketAnalyzer::Tag = PacketAnalyzer::ANALYZER_IPTUNNEL &redef; const gre_ports = { 4754/udp } &redef; } event zeek_init() &priority=20 { PacketAnalyzer::register_for_ports(PacketAnalyzer::ANALYZER_UDP, PacketAnalyzer::ANALYZER_GRE, gre_ports); }这段代码同时展示了两个要点:一是zeek_init() &priority=20的高优先级保证注册早于常规脚本执行;二是default_analyzer可被&redef覆盖,说明默认分析器是允许策略脚本在运行时替换的。
链路层分发:root 分析器与 DLT 映射
报文进入 Zeek 后,第一站是ROOT分析器。scripts/base/packet-protocols/root/main.zeek 负责把 pcap 的数据链路类型(DLT)映射到具体的链路层分析器:
module PacketAnalyzer::ROOT; export { ## Default analyzer (if we don't know the link type, we assume raw IP) const default_analyzer: PacketAnalyzer::Tag = PacketAnalyzer::ANALYZER_IP &redef; } const DLT_EN10MB : count = 1; const DLT_FDDI : count = 10; const DLT_IEEE802_11 : count = 105; const DLT_IEEE802_11_RADIO : count = 127; const DLT_LINUX_SLL : count = 113; const DLT_LINUX_SLL2 : count = 276; const DLT_NFLOG : count = 239; event zeek_init() &priority=20 { PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ROOT, DLT_EN10MB, PacketAnalyzer::ANALYZER_ETHERNET); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ROOT, DLT_FDDI, PacketAnalyzer::ANALYZER_FDDI); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ROOT, DLT_IEEE802_11, PacketAnalyzer::ANALYZER_IEEE802_11); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ROOT, DLT_IEEE802_11_RADIO, PacketAnalyzer::ANALYZER_IEEE802_11_RADIO); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ROOT, DLT_LINUX_SLL, PacketAnalyzer::ANALYZER_LINUXSLL); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ROOT, DLT_LINUX_SLL2, PacketAnalyzer::ANALYZER_LINUXSLL2); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ROOT, DLT_NFLOG, PacketAnalyzer::ANALYZER_NFLOG); }从源码可以整理出这张 DLT 映射表:
| DLT 常量 | 数值 | 对应分析器 | 典型场景 |
|---|---|---|---|
| DLT_EN10MB | 1 | ETHERNET | 标准以太网帧 |
| DLT_FDDI | 10 | FDDI | 光纤分布式数据接口 |
| DLT_IEEE802_11 | 105 | IEEE802_11 | 802.11 无线帧 |
| DLT_IEEE802_11_RADIO | 127 | IEEE802_11_RADIO | 带 Radiotap 头的 802.11 |
| DLT_LINUX_SLL | 113 | LINUXSLL | Linux cooked capture v1 |
| DLT_LINUX_SLL2 | 276 | LINUXSLL2 | Linux cooked capture v2 |
| DLT_NFLOG | 239 | NFLOG | netfilter 日志 |
注意default_analyzer默认是ANALYZER_IP:如果遇到无法识别的链路类型,Zeek 会直接按"裸 IP"解析,这与skip分析器的语义(默认也指向 IP,见下文)互相印证,保证了未知封装下依然能解析到网络层。
链路层协议族:Ethernet、VLAN 与封装链
ethernet/main.zeek(scripts/base/packet-protocols/ethernet/main.zeek)以 ethertype 为分发键注册了完整的二层解析链:
module PacketAnalyzer::ETHERNET; export { # We use some magic numbers here to denote these. The values here are outside the range of the # standard ethertypes, which should always be above 1536. const SNAP_FORWARDING_KEY : count = 0x0001; const NOVELL_FORWARDING_KEY : count = 0x0002; const LLC_FORWARDING_KEY : count = 0x0003; } event zeek_init() &priority=20 { PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, 0x8847, PacketAnalyzer::ANALYZER_MPLS); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, 0x88E7, PacketAnalyzer::ANALYZER_PBB); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, 0x0800, PacketAnalyzer::ANALYZER_IP); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, 0x86DD, PacketAnalyzer::ANALYZER_IP); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, 0x0806, PacketAnalyzer::ANALYZER_ARP); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, 0x8035, PacketAnalyzer::ANALYZER_ARP); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, 0x8100, PacketAnalyzer::ANALYZER_VLAN); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, 0x88A8, PacketAnalyzer::ANALYZER_VLAN); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, 0x9100, PacketAnalyzer::ANALYZER_VLAN); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, 0x8864, PacketAnalyzer::ANALYZER_PPPOE); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, 0x8926, PacketAnalyzer::ANALYZER_VNTAG); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, SNAP_FORWARDING_KEY, PacketAnalyzer::ANALYZER_SNAP); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, NOVELL_FORWARDING_KEY, PacketAnalyzer::ANALYZER_NOVELL_802_3); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_ETHERNET, LLC_FORWARDING_KEY, PacketAnalyzer::ANALYZER_LLC); }从源码可以整理出 Ethertype 分发表:
| Ethertype | 协议 | 子分析器 |
|---|---|---|
| 0x0800 | IPv4 | IP |
| 0x86DD | IPv6 | IP |
| 0x0806 / 0x8035 | ARP / RARP | ARP |
| 0x8100 / 0x88A8 / 0x9100 | VLAN(802.1Q / QinQ) | VLAN |
| 0x8847 | MPLS | MPLS |
| 0x88E7 | PBB(Provider Backbone Bridge) | PBB |
| 0x8864 | PPPoE | PPPOE |
| 0x8926 | VNTAG(VMware 虚拟网络标签) | VNTAG |
文件头部的注释解释了三个"魔法键"的用意:0x0001、0x0002、0x0003故意落在标准 ethertype 区间(1536 以上)之外,用来表示"无法用 ethertype 判断时"转发给 SNAP、Novell 802.3、LLC 的路径。也就是说,当以太网帧长度字段不足以直接判定类型时,Zeek 会走这几条特殊分发路径。
vlan/main.zeek(scripts/base/packet-protocols/vlan/main.zeek)几乎复刻了同样的分发逻辑,只是父分析器从ANALYZER_ETHERNET换成了ANALYZER_VLAN,这样剥离 VLAN 头后的内层帧仍能继续走相同的 ethertype 分拣,实现多级 VLAN(包括 QinQ 嵌套)的连续解析。
网络层分发:IP 分析器与协议号映射
ip/main.zeek(scripts/base/packet-protocols/ip/main.zeek)把 IP 协议号映射到传输层/隧道分析器,是整个网络层分发的枢纽:
module PacketAnalyzer::IP; export { ## Default analyzer const default_analyzer: PacketAnalyzer::Tag = PacketAnalyzer::ANALYZER_UNKNOWN_IP_TRANSPORT &redef; } const IPPROTO_TCP : count = 6; const IPPROTO_UDP : count = 17; const IPPROTO_ICMP : count = 1; const IPPROTO_ICMP6 : count = 58; const IPPROTO_IPIP : count = 4; const IPPROTO_IPV6 : count = 41; const IPPROTO_GRE : count = 47; function analyzer_option_change_ignore_checksums_nets(ID: string, new_value: set[subnet], location: string) : set[subnet] { if ( ID == "ignore_checksums_nets" ) PacketAnalyzer::__set_ignore_checksums_nets(new_value); return new_value; } event zeek_init() &priority=20 { PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_IPIP, PacketAnalyzer::ANALYZER_IPTUNNEL); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_IPV6, PacketAnalyzer::ANALYZER_IPTUNNEL); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_GRE, PacketAnalyzer::ANALYZER_GRE); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_TCP, PacketAnalyzer::ANALYZER_TCP); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_UDP, PacketAnalyzer::ANALYZER_UDP); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_ICMP, PacketAnalyzer::ANALYZER_ICMP); PacketAnalyzer::register_packet_analyzer(PacketAnalyzer::ANALYZER_IP, IPPROTO_ICMP6, PacketAnalyzer::ANALYZER_ICMP); Option::set_change_handler("ignore_checksums_nets", analyzer_option_change_ignore_checksums_nets, 5); }IP 协议号分发表整理如下:
| 协议号 | 名称 | 子分析器 |
|---|---|---|
| 1 | ICMP | ICMP |
| 4 | IP-in-IP | IPTUNNEL |
| 6 | TCP | TCP |
| 17 | UDP | UDP |
| 41 | IPv6(6in4 隧道) | IPTUNNEL |
| 47 | GRE | GRE |
| 58 | ICMPv6 | ICMP |
这段代码还体现了 Zeek 的运行时配置联动机制:analyzer_option_change_ignore_checksums_nets通过Option::set_change_handler挂接到全局选项ignore_checksums_nets上,一旦用户在策略层修改该选项,立即调用PacketAnalyzer::__set_ignore_checksums_nets更新底层校验行为。换句话说,IP 层的校验和忽略网段配置是可热更新的,无需重启 Zeek。
IP 层还有一个值得注意的默认值:default_analyzer为ANALYZER_UNKNOWN_IP_TRANSPORT,即遇到未注册的协议号时,Zeek 不会报错中断,而是走"未知传输层"分析器,继续保持连接状态并上报相关的未知协议信息。
传输层:TCP 与 UDP
udp/main.zeek(scripts/base/packet-protocols/udp/main.zeek)与tcp/main.zeek(scripts/base/packet-protocols/tcp/main.zeek)本身非常精简,前者仅保留module PacketAnalyzer::UDP;声明,后者只有一行模块声明和一段被注释掉的空zeek_init。从源码结构可以推断:TCP/UDP 分析器的解析主体由 C++ 侧实现(src/packet_analysis/protocol/tcp、src/packet_analysis/protocol/udp),脚本侧只承担命名空间与扩展挂钩的角色。真正的端口到应用层分析器分发,发生在 Zeek 的"连接级"分析器框架中——也就是base/frameworks/analyzer(被 scripts/base/packet-protocols/main.zeek 顶部@load base/frameworks/analyzer/main.zeek引入),其职责是把解析好的 TCP/UDP 流交给 HTTP、DNS 等应用层分析器。
隧道与封装协议族
隧道协议是本包的重头戏,索引文档中列出了 GRE、IPTunnel、AYIYA、Geneve、VXLAN、Teredo、GTPv1 七个子目录,覆盖了数据中心、运营商与 IPv6 过渡场景的主要封装手段。
IPTunnel:二层隧道与 Aruba 场景
iptunnel/main.zeek(scripts/base/packet-protocols/iptunnel/main.zeek)把 IP 隧道视为内层又是完整报文的场景。源码注释说明了 Aruba 的处理:Aruba 无线隧道通过 GRE 承载,GRE 设置gre_link_type = DLT_IEEE_802_11使内层按 802.11 解析,否则默认按裸 IP(DLT_RAW)处理。该文件随后把 0x8200 到 0x8370 这一整段 ethertype 区间全部注册为转发到ANALYZER_IEEE802_11,覆盖了 Aruba 隧道内层帧常见的以太类型范围;文件末尾还留有 TODO 注释,讨论 0x9000 应如何丢弃——这些细节体现了隧道解析在真实网络中的边界情况处理。
其他隧道分析器
- GRE(scripts/base/packet-protocols/gre/main.zeek):
default_analyzer为ANALYZER_IPTUNNEL,即 GRE 解封装后的内层默认按 IP 隧道继续解析;同时把 UDP 4754 注册为 GRE 的知名端口。 - VXLAN / Geneve(
vxlan/main.zeek、geneve/main.zeek):与 GRE 类似,将 UDP 知名端口绑定到相应分析器,内层默认进入 IPTUNNEL 或以太网分析链。 - Teredo(
teredo/main.zeek):处理 Teredo 隧道,将 IPv6 报文封装在 UDP 中穿越 IPv4 网络。 - AYIYA(
ayiya/main.zeek):处理 AYIYA(Anything In Anything)隧道协议。 - GTPv1(
gtpv1/main.zeek):GPRS 隧道协议 v1,用于移动运营商核心网,按 GTP 消息类型与 TEID 关联隧道内会话。
这些脚本的注册模式高度一致,都以zeek_init() &priority=20调用register_packet_analyzer或register_for_ports,并把"隧道解封装后的内层交给谁"通过default_analyzer显式声明——这正是 Zeek 能以统一框架支持多层嵌套隧道的关键设计。
skip 与 null:两个"伪协议"
skip/main.zeek(scripts/base/packet-protocols/skip/main.zeek)定义了一个可配置的跳过机制:
module PacketAnalyzer::SKIP; export { ## Default analyzer const default_analyzer: PacketAnalyzer::Tag = PacketAnalyzer::ANALYZER_IP &redef; ## Bytes to skip. const skip_bytes: count = 0 &redef; }skip_bytes允许跳过报文头部指定数量的字节后再交给下一个分析器(默认值 0,可通过&redef修改),默认目标仍是 IP 分析器。它常用于处理某些带自定义前导头的链路。null分析器(null/main.zeek)则是"空转"占位,供父分析器在没有实质内容可解析时使用,两者共同保证了分析链的连续性。
IGMP:脚本层完整示例
IGMP 是索引文档中唯一附带详细说明的协议,也是观察"脚本定义类型 + Spicy 分析器 + 事件出口"完整链路的最佳样例,它包含三个脚本文件:
- scripts/base/packet-protocols/igmp/types.zeek:定义 IGMP 消息类型枚举与 v3 组记录类型,均以 RFC 3376 为准:
module IGMP; export { ## IGMP message types, as defined in :rfc:`3376#section-4`. type MessageType: enum { MEMBERSHIP_QUERY = 0x11, MEMBERSHIP_REPORT_V1 = 0x12, MEMBERSHIP_REPORT_V2 = 0x16, LEAVE_GROUP = 0x17, MEMBERSHIP_REPORT_V3 = 0x22, BAD_CHECKSUM = 0x00 }; ## IGMP Version 3 Membership Report Group record types, as defined in ## :rfc:`3376#section-4.2.12` type GroupType: enum { MODE_IS_INCLUDE = 1, MODE_IS_EXCLUDE = 2, CHANGE_TO_INCLUDE_MODE = 3, CHANGE_TO_EXCLUDE_MODE = 4, ALLOW_NEW_SOURCES = 5, BLOCK_OLD_SOURCES = 6 }; ## IGMP Version 3 Membership Report Group record, as defined in ## :rfc:`3376#section-4.2` type Group: record { group_type: GroupType; aux_data_len: count; num_sources: count; multicast_addr: addr; sources: vector of addr; aux_data: string; }; }- scripts/base/packet-protocols/igmp/main.zeek:把 Spicy 实现的 IGMP 分析器注册到 IP 协议号 2 上:
module IGMP; event zeek_init() &priority=5 { if ( ! PacketAnalyzer::try_register_packet_analyzer_by_name("IP", 0x02, "IGMP") ) { Reporter::error("Failed to register IGMP Spicy analyzer."); } }这里用的是按名称注册的try_register_packet_analyzer_by_name(对应 src/packet_analysis/packet_analysis.bif),优先级为 5;注册失败会通过Reporter::error显式报错——这也是所有 Spicy 分析器插件注册的标准失败处理模式。IGMP 报文在 IP 层由协议号 2 直接分发,无需端口绑定。
- scripts/base/packet-protocols/igmp/spicy-events.zeek:定义 Spicy 分析器向上层抛出的 Zeek 事件,共 45 行,覆盖:
IGMP::message(每个 IGMP 报文一条,携带raw_pkt_hdr与消息类型)、IGMP::membership_query、IGMP::membership_report_v1、IGMP::membership_report_v2、IGMP::leave_group以及 v3 版本的事件(如带源地址向量的 Membership Report v3)。这些事件就是脚本开发者在策略层编写告警与统计逻辑的入口点,例如可以订阅IGMP::leave_group检测组播成员快速离开行为。
其余链路层协议
索引文档中还列出若干链路层分析器,各自承担特定封装:
- LLC / SNAP / Novell 802.3(
llc/、snap/、novell_802_3/):处理以太网 II 帧之外的 IEEE 802.2 LLC、SNAP 子网访问协议以及 Novell 802.3 原始帧格式,是 Ethernet 分析器通过三个"魔法键"(0x0001/0x0002/0x0003)转发的目标; - PPPoE / PPP / PPP_serial(
pppoe/、ppp/、ppp_serial/):宽带拨号链路族,PPPoE 帧经 0x8864 从 Ethernet 进入,解封装后交给 PPP,再继续解析 PPP 承载的网络层协议; - FDDI / IEEE 802.11 / IEEE 802.11 Radio(
fddi/、ieee802_11/、ieee802_11_radio/):由 ROOT 分析器按 DLT 分发,支撑无线与老式局域网; - Linux SLL / SLL2 / NFLOG(
linux_sll/、linux_sll2/、nflog/):Linux cooked 捕获格式与 netfilter 日志设备,常见于tcpdump -i any与 iptables NFLOG 抓包场景; - MPLS / PBB / VNTAG(
mpls/、pbb/、vntag/):由 Ethernet 分析器按 ethertype 分发,分别处理标签交换、运营商骨干桥与 VMware VNTAG 封装。
与源码的对应关系
base/packet-protocols的脚本只承担"注册表"角色,真正的协议解码逻辑位于 C++ 侧 src/packet_analysis/protocol 目录(含ethernet、ip、tcp、udp、icmp、gre、vxlan、geneve、teredo、vntag等子目录),以及 Spicy 分析器目录(如 IGMP 的 Spicy 实现)。register_packet_analyzer的 BIF 声明在 src/packet_analysis/packet_analysis.bif,其运行时行为由 src/packet_analysis/Manager.cc 实现。如果读者想验证本篇文章的分发表,可直接对照各子目录下的main.zeek与 scripts/base/packet-protocols/load.zeek 的@load顺序进行交叉核对。
小结:读透 base/packet-protocols 的三个抓手
- 加载顺序即解析顺序:
__load__.zeek中的@load顺序与报文分析链的构造顺序一一对应,从 root(DLT)到链路层(ethertype)到网络层(协议号)再到隧道(default_analyzer 指定内层去向); - 三张分发表:ROOT 的 DLT 表、ETHERNET/VLAN 的 ethertype 表、IP 的协议号表,是理解任何报文"下一步去哪"的关键;
- 默认值与可 redef 常量:
max_depth(默认 25)、default_analyzer、skip_bytes等均支持&redef,策略脚本可以在不改动核心代码的前提下调整解析深度与默认分发路径。
掌握这些机制后,无论是排查"为什么某个隧道报文没被解析",还是为自定义封装编写自己的 packet analyzer,你都能直接从scripts/base/packet-protocols与src/packet_analysis/protocol定位到对应实现,并沿用register_packet_analyzer+default_analyzer的既有模式完成注册。
- 网络安全
- 网络
- IDS
【免费下载链接】zeek
Zeek is a powerful network analysis framework that is much different from the typical IDS you may know.
相关推荐
RevokeMsgPatcher 微信QQ防撤回补丁
RevokeMsgPatcher 微信QQ防撤回补丁 RevokeMsgPatcher 是一个用于 Windows 电脑版微信、QQ、TIM 的防撤回补丁工具。
网络安全网络IDSZeek Teredo 隧道分析事件详解:从 RFC 4380 封装解析到脚本层事件编程
Zeek Teredo 隧道分析事件详解:从 RFC 4380 封装解析到脚本层事件编程 导读 Teredo(RFC 4380)是一种将 IPv6 报文封装进
网络安全网络IDSZeek 包分析框架(Packet Analysis)深入解析:从链路层解析到会话构建的插件化架构
Zeek 包分析框架(Packet Analysis)深入解析:从链路层解析到会话构建的插件化架构 Packet Analysis(包分析)是 Zeek 负责解
网络安全网络IDS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考