编写bro的插件

源:https://docs.zeek.org/en/stable/devel/plugins.html

一、编写插件

Bro内部提供了一个插件API,支持动态扩展系统,而不需要修改核心代码库。通过这种方式,定制代码保持自包含,并且可以独立地维护、编译和安装。目前,插件可以向Bro添加以下功能:

bro脚本。

为脚本语言构建函数/事件/类型。

协议分析器。

文件分析器。

包源和包转储程序。

日志框架后端。

输入框架阅读器。

插件的功能对于用户来说是可用的,就像Bro有相应的内置代码一样。实际上,Bro的许多组件在内部也是作为插件构造的,它们只是静态编译成二进制文件,而不是在运行时动态加载。

二、快速启动

只要遵循一些约定,编写基本插件是相当简单的。在接下来的代码中,我们创建了一个简单的示例插件,它向Bro添加了一个新的内置函数(bif):我们将添加rot13(s: string): string,一个将字符串中的每个字符旋转13个位置的函数。

通常,插件以目录的形式出现,目录遵循特定的结构。首先,Bro的发行版提供了一个helper脚本aux/ bros -aux/plugin-support/init-plugin,它创建了一个框架skeleton 插件,然后可以对其进行定制。让我们用这个:

# init-plugin ./rot13-plugin Demo Rot13

如您所见,脚本接受三个参数。第一个是一个目录,插件框架( plugin skeleton)将在其中创建。第二个是插件将驻留的名称空间( namespace),第三个是插件本身相对于名称空间的描述性名称(descriptive name)。Bro使用名称空间和名称的组合来标识插件。名称空间( namespace)用于避免独立开发人员编写的插件之间的命名冲突;选择,例如,你的组织名称作为名称空间( namespace)。名称空间(namespace)Bro保留给Bro项目分发的功能。在我们的示例中,这个插件将被称为Demo::Rot13。

init-plugin脚本放置了许多文件。稍后将描述完整的布局。现在,我们只需要src/rot13.bif。它最初是空的,但我们将添加我们的新bif如下:

# cat src/rot13.bif

module Demo;

function rot13%(s: string%) : string

    %{

    char* rot13 = copy_string(s->CheckString());

    for ( char* p = rot13; *p; p++ )

        {

        char b = islower(*p) ? 'a' : 'A';

        *p  = (*p - b + 13) % 26 + b;

        }

    BroString* bs = new BroString(1, reinterpret_cast<byte_vec>(rot13),

                                  strlen(rot13));

    return new StringVal(bs);

    %}

该文件的语法与任何其他*.bif文件一样;我们不在这里讨论。

现在我们已经可以编译我们的插件了,我们只需要告诉configure脚本(创建的init-plugin) Bro源代码树的位置(Bro需要先在那里构建):

# cd rot13-plugin

# ./configure --bro-dist=/path/to/bro/dist && make

[... cmake output ...]

这将在build/子目录中构建插件。事实上,该子目录成为插件:当make完成时,build/拥有Bro将其识别为动态插件所需的一切。

让我们试试。一旦我们将Bro指向build/目录,它将自动拉入我们的新插件,因为我们可以用-N选项检查:

# export BRO_PLUGIN_PATH=/path/to/rot13-plugin/build

# bro -N

[...]

Demo::Rot13 - <Insert description> (dynamic, version 0.1.0)

[...]

这看起来相当不错,除了我们应该用更好的东西替换的虚拟描述,这样用户就会知道我们的插件是关于什么的。我们通过在src/Plugin.cc中编辑config.description行来实现这一点,如下所示:

[...]

plugin::Configuration Plugin::Configure()

    {

    plugin::Configuration config;

    config.name = "Demo::Rot13";

    config.description = "Caesar cipher rotating a string's characters by 13 places.";

    config.version.major = 0;

    config.version.minor = 1;

    config.version.patch = 0;

    return config;

    }

[...]

现在重建并验证描述是否可见:

# make

[...]

# bro -N | grep Rot13

Demo::Rot13 - Caesar cipher rotating a string's characters by 13 places. (dynamic, version 0.1.0)

Bro还可以向我们展示这个插件提供的更详细的选项-NN:

# bro -NN

[...]

Demo::Rot13 - Caesar cipher rotating a string's characters by 13 places. (dynamic, version 0.1.0)

    [Function] Demo::rot13

[...]

我们的函数。现在让我们使用它:

# bro -e 'print Demo::rot13("Hello")'

Uryyb

它是有效的。接下来,我们将安装这个插件和Bro本身,这样它就可以直接找到它,而不需要使用BRO_PLUGIN_PATH环境变量。如果我们先取消变量设置,函数将不再可用:

# unset BRO_PLUGIN_PATH

# bro -e 'print Demo::rot13("Hello")'

error in <command line>, line 1: unknown identifier Demo::rot13, at or near "Demo::rot13"

一旦我们安装了它,它再次工作:

# make install

# bro -e 'print Demo::rot13("Hello")'

Uryyb

安装的版本进入<bro-install-prefix>/lib/bro/plugins/Demo_Rot13。

一个插件可以独立于Bro分发给其他人使用。要以源代码形式分发,只需删除build/目录(让make distclean这样做),然后tar up整个rot13-plugin/目录。其他的则在打开包装后按照上面的步骤操作。

为了以二进制形式分发插件,构建过程可以方便地在build/dist/中创建相应的tarball。在本例中,它被称为Demo_Rot13-0.1.0.tar。版本号来自init-plugin放入的版本文件。二进制tarball包含运行插件所需的所有内容,但是没有进一步的源文件。还可以通过bro_plugin_dist_files宏在插件的CMakeLists.txt中指定进一步的文件;骨架对README,VERSION,CHANGES, 和COPYING都是这样做的。要通过二进制tarball使用该插件,只需将其解压缩到/lib/bro/plugins/。或者,如果您将它解压缩到另一个位置,那么您需要将BRO_PLUGIN_PATH指向那里。

在发布插件之前,您应该编辑init-plugin放置的一些元文件。编辑README和VERSION,并在进行更改时更新更改。还应将许可证文件作为副本放置在适当的位置;如果BSD没问题,您将在copy .edit-me中找到一个模板。

三、插件目录布局

插件的目录需要遵循一组约定,以便Bro(1)将其识别为插件,并(2)知道加载什么。虽然init-plugin解决了大部分问题,但以下是全部内容。我们将使用<base>来表示插件的顶级目录。对于骨架skeleton,<base>对应于build/。

(1)<base>/__bro_plugin__

将一个目录标记为包含Bro插件的文件。文件必须存在,并且它的内容必须由带有插件限定名的一行组成(例如,“Demo::Rot13”)。

(2)<base>/lib/<plugin-name>.<os>-<arch>.so

包含插件编译代码的共享库。如果操作系统和体系结构与当前平台匹配,Bro将在运行时动态加载。

(3)scripts/

带有插件自定义Bro脚本的目录。当插件被激活时,这个目录将自动添加到BROPATH中,这样里面的任何脚本/模块都可以被“@load”。

(4)scripts/__load__.bro

当插件被激活时加载的Bro脚本。当这个脚本执行时,插件定义的任何BiF元素都是可用的。有关激活插件的更多信息,请参见下面。

(5)scripts/ __preload__.bro

一个Bro脚本,它将在插件被激活时加载,但在任何BiF元素可用之前加载。有关激活插件的更多信息,请参见下面。

(6)lib / bif /

带有自动生成的Bro脚本的目录,这些脚本声明插件的bif元素。这里的文件是由bifcl生成的。

<base>中的所有其他文件都忽视了Bro。

按照惯例,插件应该将其自定义脚本放入脚本/的子文件夹中,即scripts/<plugin-namespace>/<plugin-name>/<script>.bro,避免冲突。像往常一样,您可以放置一个 __load__.bro 也在其中,例如@load Demo/Rot13可以以多个单独脚本的形式加载整个模块。

注意,除了上面的路径之外,init-plugin helper还放置了更多的文件和目录来帮助开发和安装(例如,CMakeLists-txt、Makefile和src/中的源代码)。然而,对于Bro来说,所有这些在运行时都没有特殊的意义,插件也不需要运行。

四、init-plugin

init-plugin按照上面的布局放置一个基本的插件结构,并使用CMake构建和安装系统对其进行扩展。具有这种结构的插件既可以直接在其源目录之外使用(在make和设置Bro的BRO_PLUGIN_PATH之后),也可以在Bro旁边安装(在make install之后)。

在lib和scripts目录上安装副本,以及在CMakeLists.txt(例如README, VERSION)中指定的_bro_plugin__ magic文件和任何其他分发文件上安装副本。您可以找到安装在build/MANIFEST中的完整文件列表。在幕后,make install实际上只是将二进制tarball从build/dist解压缩到目标目录中。

init-plugin永远不会覆盖现有文件。如果目标目录已经存在,它将默认拒绝执行任何操作。您可以使用-u运行它来更新现有的插件,但是它永远不会覆盖任何现有的文件;它只会放入它还没有找到的文件。要将文件还原为init-plugin最初创建的文件,请先删除它,然后使用-u重新运行。

init-plugin放置了一个configure脚本,该脚本使用更熟悉的configure-style配置来包装cmake。默认情况下,脚本提供了两个选项,用于指定到Bro源(- bros -dist)和插件安装目录(- install-root)的路径。要使用特定于插件的选项来扩展configure(例如搜索依赖项的路径),不要直接编辑脚本,而是扩展configure.plugin, configure包括。这样,将来当发行版发生更改时,您将能够更容易地更新configure。在configure-plugin中,可以使用预定义的 shell函数append_cache_entry将值种子化到CMake缓存中;有关示例,请参阅已安装的框架版本和现有插件。

五、激活一个插件

需要激活插件才能让用户使用它。激活插件将:

(1)加载动态模块

(2)提供任何bif项目

(3)将scripts/目录添加到BROPATH

(4)加载scripts/__preload__.bro

(5)使BiF元素对脚本可用。

(6)加载脚本scripts/__load__.bro

默认情况下,Bro将自动激活在其搜索路径BRO_PLUGIN_PATH中找到的所有动态插件。但是,在裸机模式下(bro -b),默认情况下不会激活任何动态插件;相反,用户可以使用@load-plugin <qualified-plugin-name>指令(例如,@load-plugin Demo::Rot13)选择性地启用scriptland中的各个插件。</qualified-plugin-name>或者,您可以通过指定插件的全名(Demo::Rot13)从命令行激活插件,或者将环境变量BRO_PLUGIN_ACTIVATE设置为由逗号(!)分隔的插件名称列表,从而无条件地激活插件,即使是在裸机模式下。

bro -N分别显示已激活的插件和尚未激活的插件。注意,静态编译到Bro中的插件总是被激活,因此即使在裸机模式下也会这样显示。

六、插件组件

下面的小节详细介绍了通过插件提供的各种类型的功能。请注意,一个插件可以提供多个组件类型。例如,一个插件可以同时提供多个协议分析器;或者同时使用日志后端和输入读取器。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容

  • 一、Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows、Linux和Uni...
    1b3bd36d9d21阅读 8,153评论 3 13
  • feisky云计算、虚拟化与Linux技术笔记posts - 1014, comments - 298, trac...
    不排版阅读 3,837评论 0 5
  • 这篇文章是手册的中文译版整理而来(英文看着太慢了,感谢前人铺路Orz...),vim的markdown插件和实时预...
    Himryang阅读 6,965评论 0 20
  • Gradle 本身只提供基本框架和核心概念,几乎所有的功能都是以插件的方式提供的。 例如构建 Java 应用的功能...
    佛系编码阅读 373评论 0 0
  • 什么是Http协议 是一种可靠的可以传送文档,声音,图像的一种与服务器交互的方式,它处于应用层。 怎么工作 它是建...
    沈Robbie阅读 349评论 0 0