资讯详情

资讯详情

Zeek OpenFlow 控制框架深入解析:用插件化架构编程 OpenFlow 交换机流表

网络安全网络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 的 OpenFlow 框架是一套内置于脚本库base/frameworks/openflow的插件化控制框架它让 Zeek 能够通过不同插件与各类 OpenFlow 控制器通信从而对支持 OpenFlow 的交换机下发流表规则。本文以官方文档 main.zeek.rst 为骨架结合框架源码、插件实现与 btest 测试用例完整梳理其事件、函数、核心数据类型、插件机制与集群模式帮助你从会抄示例进阶到理解原理、能自写插件。一、框架定位低层原语高层交给 NetControl阅读 main.zeek 顶部的注释可以清晰把握该框架的定位这是一个基于插件的框架通过插件实现与 OpenFlow 控制器的通信从而控制支持 OpenFlow 的交换机。框架必须通过某个插件的new函数完成实例化。本框架只提供非常低层的功能若要用 OpenFlow 交换机做 shunting 之类的高层操作请使用 NetControl 框架——它提供更高层的函数并可以把 OpenFlow 框架作为其后端。这意味着OpenFlow 框架是基础设施它直接操作ofp_match匹配条件、ofp_flow_mod流修改动作这些接近 OpenFlow 协议原语的记录类型开发者需要自己构造规则细节NetControl 是上层建筑例如 netcontrol 文档 中介绍的 shunting 等策略最终可经由base/frameworks/netcontrol/plugins/openflow.zeek这一后端调用 OpenFlow 框架的能力。该文档中controller_activated、flow_mod_success、flow_mod_failure、flow_removed等事件的:source-code:标注也正指向该插件文件openflow.zeek印证了两个框架之间的调用关系命名空间统一为OpenFlow且框架内部加载两个基础文件consts.zeek常量与 types.zeek类型。二、加载机制单机与集群的自适应分支框架的入口是load.zeek其加载顺序设计得非常精巧load ./consts load ./types load ./main load ./plugins # 必须先加载 cluster 框架 load base/frameworks/cluster if ( Cluster::is_enabled() ) load ./cluster else load ./non-cluster endif先加载常量与类型保证后续文件中的记录定义可用main.zeek定义模块导出事件、函数签名、Cookie 处理、注册表plugins/目录下的所有插件__load__.zeek会load进来各自向Plugin枚举追加成员关键分支根据Cluster::is_enabled()决定加载 cluster.zeek集群模式还是 non-cluster.zeek单机模式。flow_mod、flow_clear、register_controller、unregister_controller、lookup_controller这两个文件的实现完全不同详见第七、八节。三、核心数据类型读懂记录就是读懂协议3.1ofp_match描述哪些包命中这条规则定义见 types.zeek它把 OpenFlow 匹配字段映射为 Zeek 记录且声明为log可直接写日志字段类型含义in_portcount optional输入交换机端口dl_src/dl_dststring optional以太网源/目的地址dl_vlan/dl_vlan_pcpcount optional输入 VLAN id / 优先级dl_typecount optional以太网帧类型如ETH_IPv4、ETH_IPv6nw_toscount optionalIP ToS实际是 6 位 DSCP 字段nw_protocount optionalIP 协议号或 ARP opcode 低 8 位nw_src/nw_dstsubnet optionalIP 源/目的地址v4/v6 共用字段tp_src/tp_dstcount optionalTCP/UDP 源/目的端口注意一个实现细节源码注释明确说明当前 v4 与 v6 复用同一字段这与 OpenFlow 协议原生的字段划分并不完全一致是框架作者标注的已知简化。3.2ofp_flow_action对流条目可执行的动作定义见 types.zeek是一个独立记录用于让ofp_flow_mod保持精简out_ports: vector of count defaultvector()输出端口列表最常见的动作vlan_vid/vlan_pcp设置 VLAN id / 优先级vlan_strip: bool defaultF剥离 VLAN 标签dl_src/dl_dst改写以太网源/目的地址nw_tos、nw_src、nw_dst改写 IP 层字段tp_src/tp_dst改写 TCP/UDP 端口。3.3ofp_flow_mod描述对匹配的流做什么定义见 types.zeekcookie: count控制器签发的透明标识符。源码注释强调OpenFlow 规范中它是可选的但框架强制要求提供以便始终能识别自己的流table_id: count optional放置流的表OFPTT_ALL可用于删除所有匹配表中的流command: ofp_flow_mod_command取OFPFC_*之一新增/修改/严格修改/删除/严格删除idle_timeout/hard_timeout空闲超时 / 最大存活时间秒默认 0即不过期priority: count default0流条目优先级out_port/out_group仅用于OFPFC_DELETE*要求被删除条目包含此输出端口/组OFPP_ANY/OFPG_ANY表示无限制flags: count default0OFPFF_*标志位位图actions: ofp_flow_action defaultofp_flow_action()匹配后要执行的动作。3.4Controller与ControllerState控制器实例的契约types.zeek 中的Controller记录定义了插件必须实现的回调集state: ControllerState控制器相关状态插件可用redef扩展字段如 Broker 插件的broker_hostsupports_flow_removed: bool控制器是否支持flow_removed事件决定该事件是否会被触发describe: function(state): string必须实现返回控制器的人类可读描述init/destroy一次性初始化和销毁回调可选flow_mod/flow_clear流修改、清空回调可选供non-cluster.zeek的分发逻辑调用。ControllerState内置三个下划线私有字段types.zeek_plugin插件类型、_name控制器唯一名、_activated是否已激活默认 F。四、常量字典从以太类型到流修改命令4.1 以太类型与 IP 协议号consts.zeek 定义了一组ETH_*如ETH_IPv4 0x0800、ETH_IPv6 0x86DD、ETH_ARP 0x0806、ETH_VLAN 0x8100和IP_*如IP_TCP 0x06、IP_UDP 0x11、IP_ICMP 0x01常量。源码注释指出这些对照表分别来自 IEEE ethertype 注册表与 IANA IP 协议号列表但作者以注释形式保留了原始枚举定义实际暴露为常量。4.2 Cookie 位布局常量框架在consts.zeek中定义了一套用于在 cookie 中编码标识信息的位布局COOKIE_BID_SIZE 1677721624 bits对应低 24 位唯一标识的容量COOKIE_BID_START 10995116277761 40业务 id 起始位ZEEK_COOKIE_ID 41 42Zeek 特定 cookie 标识位COOKIE_GID_SIZE 2568 bits 组标识容量COOKIE_GID_START 42949672961 32组 id 起始位COOKIE_UID_SIZE 429496729632 bits 唯一标识容量COOKIE_UID_START 0INVALID_COOKIE 0x7fffffffffffffff非法 cookie 的返回值。这一布局的具体用法见第六节Cookie 处理函数。4.3 OpenFlow 协议常量consts.zeek还完整定义了协议层常量用于构造底层消息物理/虚拟端口OFPP_*OFPP_IN_PORT0xfffffff8回送输入端口、OFPP_TABLE、OFPP_NORMAL正常 L2/L3 交换、OFPP_FLOOD除输入口和 STP 禁用口外的所有物理口、OFPP_ALL、OFPP_CONTROLLER发送到控制器、OFPP_LOCAL、OFPP_ANY仅用于删除/统计的通配端口流修改标志OFPFF_*OFPFF_SEND_FLOW_REM 0x1流过期或删除时发送 flow removed 消息、OFPFF_CHECK_OVERLAP 0x2、OFPFF_EMERG 0x4应急流仅在控制器断开时使用通配表OFPTT_ALL 0xff动作类型ofp_action_typeOFPAT_OUTPUT、OFPAT_SET_VLAN_VID、OFPAT_SET_VLAN_PCP、OFPAT_STRIP_VLAN、OFPAT_SET_DL_SRC/DST、OFPAT_SET_NW_SRC/DST/TOS、OFPAT_SET_TP_SRC/DST、OFPAT_ENQUEUE、OFPAT_VENDOR流修改命令ofp_flow_mod_commandOFPFC_ADD 0x0、OFPFC_MODIFY 0x1、OFPFC_MODIFY_STRICT 0x2、OFPFC_DELETE 0x3、OFPFC_DELETE_STRICT 0x4分片处理配置ofp_config_flagsOFPC_FRAG_NORMAL、OFPC_FRAG_DROP、OFPC_FRAG_REASM、OFPC_FRAG_MASK。五、框架事件控制器生命周期与流操作结果框架共导出 4 个事件见 main.zeek它们是脚本侧感知 OpenFlow 操作结果的唯一通道。5.1OpenFlow::controller_activatedevent OpenFlow::controller_activated(name: string, controller: Controller)控制器完成初始化并完全激活后触发一次。name是该控制器实例的唯一名称。该事件通常意味着可以开始下发流表——broker-basic 测试正是在此事件中执行首次flow_clear与flow_mod。5.2OpenFlow::flow_mod_successevent OpenFlow::flow_mod_success(name: string, match: ofp_match, flow_mod: ofp_flow_mod, msg: string default)确认某条流规则被成功修改。msg是插件提供的可选说明信息例如 Ryu 插件会把 HTTP 响应体填入。5.3OpenFlow::flow_mod_failureevent OpenFlow::flow_mod_failure(name: string, match: ofp_match, flow_mod: ofp_flow_mod, msg: string default)报告安装流规则时出错参数与flow_mod_success一致msg描述错误信息。Ryu 插件在 HTTP 返回非 200 时会触发它并附带响应体。5.4OpenFlow::flow_removedevent OpenFlow::flow_removed(name: string, match: ofp_match, cookie: count, priority: count, reason: count, duration_sec: count, idle_timeout: count, packet_count: count, byte_count: count)交换机因 hard 或 idle 超时移除某条流时触发。前提条件只有supports_flow_removed为 T 的控制器如 Broker 插件才会产生该事件。参数中的reason是OFPRR_*常量代码中引用其余为流的优先级、存活秒数、空闲超时及包/字节计数。六、框架函数低层原语逐个拆解6.1OpenFlow::flow_mod与OpenFlow::flow_clear在单机模式non-cluster.zeek下二者遵循统一分发逻辑function flow_mod(controller: Controller, match: ofp_match, flow_mod: ofp_flow_mod): bool { if ( ! controller$state$_activated ) return F; if ( controller?$flow_mod ) return controller$flow_mod(controller$state, match, flow_mod); else return F; }控制器未激活直接返回 F插件未实现flow_mod回调也返回 F成功则调用插件的回调函数返回值语义F 表示出错或插件不支持该操作T 表示操作已被排队注意不是已成功执行异步操作结果要通过事件确认。6.2OpenFlow::match_conn连接记录 → OpenFlow 匹配实现见 main.zeek。它把conn_id转换为可直接用于下发的ofp_match默认reverseF以orig作为源、resp作为目的reverseT时二者互换方便同时下发双向规则自动推导字段源地址为 IPv6 则dl_type ETH_IPv6否则ETH_IPv4源端口为 UDP 则nw_proto IP_UDP为 ICMP 则IP_ICMP否则默认IP_TCP输出记录包含dl_type、nw_proto、nw_src/nw_dst以subnet形式、tp_src/tp_dst以count形式。6.3 Cookie 三件套generate_cookie/get_cookie_uid/get_cookie_gid这是框架最有特色的底层设施实现于 main.zeek。其目标是让 Zeek 下发的每条流都携带可识别来源与分组的 cookiegenerate_cookie(cookie: count default0)以ZEEK_COOKIE_ID * COOKIE_BID_START为基底即置位第 42 位再叠加调用者传入的 uid。若 uid ≥COOKIE_UID_SIZE超过 32 位会发出Reporter::warning并丢弃该 uidis_valid_cookie(cookie)内部函数校验cookie / COOKIE_BID_START ZEEK_COOKIE_ID失败则告警用于防止处理非本框架下发的 cookieget_cookie_uid(cookie)取 cookie 低 32 位uid 段非法 cookie 返回INVALID_COOKIEget_cookie_gid(cookie)从第 32 位起的 8 位段提取组 idgid非法 cookie 同样返回INVALID_COOKIE。由此可反推出 cookie 的位布局低 32 位为唯一标识、第 32–39 位为组标识、第 42 位为Zeek 签发标志位。这为上层 NetControl 等框架按组批量管理/删除流提供了依据。6.4 注册与查询register_controller/unregister_controller/lookup_controller/controller_init_done框架内部维护全局表name_to_controller: table[string] of Controllermain.zeek注册、反注册、查询围绕它展开register_controller_impl等实现在 main.zeek注册register_controller(tpe, name, controller)先拼接_name cat(tpe, name)、记录_plugin然后写入映射表若重复注册同名控制器会报错忽略。注册后若插件提供了init回调则调用之否则立即controller_init_done激活controller_init_done(controller)校验控制器已注册后置_activated T并触发OpenFlow::controller_activated事件反注册unregister_controller从映射表删除并调用插件的destroy回调未注册会报错查询lookup_controller(name)返回单元素 vector 含控制器未找到返回空 vector这种返回值形态是为了在集群模式下表达查不到与无权限查询两种空结果。七、三大内置插件实例化与控制器的三条路径框架规定必须通过某个插件的new函数实例化内置插件位于 plugins/每个插件向OpenFlow::Plugin枚举追加一个成员。7.1 Log 插件把流修改命令写成日志log.zeek 是最简单的插件适合测试与离线审计OpenFlow::log_new(dpid: count, success_event: bool defaultT): OpenFlow::Controller枚举成员OFLOG在zeek_initpriority5中创建日志流路径固定为openflow列结构Info含ts、dpid、match、flow_mod四列均loglog_flow_mod回调执行Log::write(LOG, ...)若log_success_eventT还会触发OpenFlow::flow_mod_success不实现flow_clear且supports_flow_removedF暴露log_openflow事件允许脚本在记录进入日志框架前访问Info记录。7.2 Broker 插件跨进程与控制器/交换机通信broker.zeek 通过 Broker 消息总线把流操作发布到远端OpenFlow::broker_new(name: string, host: addr, host_port: port, topic: string, dpid: count): OpenFlow::Controller枚举成员BROKERControllerState扩展broker_host、broker_port、broker_dpid、broker_topic定义两个传输事件broker_flow_mod、broker_flow_clearflow_mod回调即Broker::publish(topic, Broker::make_event(broker_flow_mod, ...))init回调会Broker::subscribe该 topic 并Broker::peer到控制器地址远端对端连上Broker::peer_added时插件通过broker_peers表反向定位到对应 Controller 并调用controller_init_done——这就是 Broker 插件的激活机制声明supports_flow_removedT即远端可把 flow 移除消息经 Broker 回传触发flow_removed注释说明 success/failure 事件由远端另一侧脚本通过 Broker 直接回发。7.3 Ryu 插件走 Ryu ReST API 的 HTTP 控制器ryu.zeek 对接 Ryu 控制器的 ReST APIOpenFlow::ryu_new(host: addr, host_port: count, dpid: count): OpenFlow::Controller枚举成员RYUControllerState扩展ryu_host、ryu_port、ryu_dpid及调试开关ryu_debug请求路径为http://host:port/stats/flowentry/cmd其中cmd由ryu_url表把OFPFC_*命令映射为add、modify、modify_strict、delete、delete_strict由于 Ryu 的 ReST API 用字符串表示动作类型插件定义了ryu_flow_action_typeOUTPUT、_port与ryu_ofp_flow_mod两个适配记录把框架记录转换后经to_json序列化再用ActiveHTTP::request异步 POSTryu_debugT时不发真实请求只把 URL 与 JSON 打印到 stdout 并直接触发flow_mod_success——btest 测试正是靠这个开关做无网络单测HTTP 返回 200 触发flow_mod_successmsg为响应体非 200 触发flow_mod_failureflow_clear则对stats/flowentry/clear/dpid发 DELETEsupports_flow_removedF即 Ryu 插件不产生 flow removed 事件。八、集群模式manager 集中执行worker 只转发cluster.zeek 是集群环境下的同名函数实现设计核心是所有 OpenFlow 状态与执行都集中在 manager 节点flow_mod/flow_clearmanager 上直接调用插件回调worker 上则通过Cluster::publish(Cluster::manager_topic, OpenFlow::cluster_flow_mod, ...)把请求打包成集群事件转发给 managermanager 侧收到cluster_flow_mod/cluster_flow_clear事件后先按名字在name_to_controller中查找找不到报错再检查_activated后才真正执行register_controller/unregister_controller只在 manager 上执行注册与initworker 直接返回lookup_controller非 manager 节点一律返回空 vector——源码注释坦诚地讨论了这一取舍worker 节点无法按名字查询控制器因此也无法在 worker 上对名字做本地反应但与此同时至少 Broker 场景下事件也不会回发到 worker所以该限制当前可接受。加载时通过Cluster::is_enabled()自动二选一见第二节因此同一份脚本在单机与集群下无需改动。九、端到端实战从测试用例看标准用法仓库的 btest 用例testing/btest/scripts/base/frameworks/openflow/是现成的最佳实践范本。9.1 Log 插件完整示例log-basic.zeeklog-basic.zeek 展示最典型的流程——初始化时下发一条全局规则每次连接建立时为双向流量下发流表load base/protocols/conn load base/frameworks/openflow global of_controller: OpenFlow::Controller; global cookie_id: count 42; event zeek_init() { of_controller OpenFlow::log_new(42); OpenFlow::flow_mod(of_controller, [], [$cookieOpenFlow::generate_cookie(1), $commandOpenFlow::OFPFC_ADD, $actions[$out_portsvector(3, 7)]]); } event connection_established(c: connection) { local match OpenFlow::match_conn(c$id); local match_rev OpenFlow::match_conn(c$id, T); local flow_mod: OpenFlow::ofp_flow_mod [ $cookieOpenFlow::generate_cookie(cookie_id), $commandOpenFlow::OFPFC_ADD, $idle_timeout30, $priority5 ]; OpenFlow::flow_mod(of_controller, match, flow_mod); OpenFlow::flow_mod(of_controller, match_rev, flow_mod); }要点空 match[]表示通配所有流量match_conn与match_conn(c$id, T)组合实现双向覆盖cookie一律经generate_cookie生成。测试通过btest-diff openflow.log校验日志输出。9.2 Ryu 调试模式ryu-basic.zeekryu-basic.zeek 展示无网络环境的验证方式——开启ryu_debug后打印 JSON 并触发 success 事件测试断言 stdoutof_controller OpenFlow::ryu_new(127.0.0.1, 8080, 42); of_controller$state$ryu_debugT; OpenFlow::flow_clear(of_controller); OpenFlow::flow_mod(of_controller, [], [...]);同时演示了flow_clear的调用和OpenFlow::flow_mod_success事件处理器的写法。9.3 Broker 双进程联动broker-basic.zeekbroker-basic.zeek 是最完整的端到端样例发送方 Zeek 用broker_new(broker1, 127.0.0.1, port, zeek/openflow, 42)实例化控制器必须等待OpenFlow::controller_activated事件后才能下发接收方脚本订阅 topic 并Broker::listen收到broker_flow_mod后把 success/failure 事件回发到同一 topic。该测试还展示了 Broker 插件激活流程与suspend_processing()的配合。9.4 小结标准使用五步法load base/frameworks/openflow并按需load base/protocols/conn调用某插件的new函数创建OpenFlow::Controller需要异步初始化时等待OpenFlow::controller_activated用match_conn构造匹配用记录构造ofp_flow_mod调用OpenFlow::flow_mod/flow_clear通过flow_mod_success/flow_mod_failure/flow_removed事件跟踪结果。十、扩展你的插件实现Controller回调契约阅读第三节的Controller记录可知编写自定义插件只需三步追加枚举redef enum Plugin { MYPLUGIN, };扩展状态redef record ControllerState { my_field: ... optional; };可仿照 broker/ryu 插件的写法实现回调至少提供describe并按需提供init、destroy、flow_mod、flow_clear在构造函数中设置supports_flow_removed最后调用register_controller(OpenFlow::MYPLUGIN, name, c)完成注册注册会自动触发激活流程见第六节。需要集群支持时无需改动脚本——load.zeek 会自动切换cluster/non-cluster实现插件只需确保在 manager 节点上注册即可。结语Zeek 的 OpenFlow 框架是一套设计清晰的低层控制原语层ofp_match/ofp_flow_mod描述规则flow_mod/flow_clear下发操作Cookie 机制保证流可归属、可追溯插件体系屏蔽了控制器差异日志、Broker、Ryu ReST集群模式则把状态收敛到 manager。实际做 shunting 等安全编排时通常应优先考虑以它为后端的 NetControl 框架而当需要精细控制 OpenFlow 交换机流表时本文梳理的接口、常量与测试用例即可作为直接可用的开发手册。建议结合 types.zeek、consts.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点击查看免费下载相关推荐Firezone 测试栈中的公网模拟路由器基于 nftables 的 scripts/router 容器全解析Firezone 测试栈中的公网模拟路由器基于 nftables 的 scripts/router 容器全解析 导读 Firezone 仓库的 scripts网络安全网络IDSZeek OpenFlow 框架指南从控制器插件到流表下发与集群协作Zeek OpenFlow 框架指南从控制器插件到流表下发与集群协作 导读 Zeek 是一个强调深度分析与可编程性的网络分析框架。它的 OpenFlow 框架网络安全网络IDSZeek OpenFlow 框架类型体系深度解析从 ofp_match 到 Controller 的流表控制模型Zeek OpenFlow 框架类型体系深度解析从 ofp_match 到 Controller 的流表控制模型 本文围绕 Zeek 的 OpenFlow 控网络安全网络IDS上一篇Exposed DAO API 示例工程实战指南构建、运行与 CRUD 全流程解读下一篇《大营销平台系统》活动上架发布预热对接基于 SC 渠道来源的活动分发与 Redis 预热装配实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →