2.5 Bro脚本入门
时间 | 修改内容 |
2018.02.24 | 完成全文 |
- 解析流量并生成event,整个过程不对使用者开放,也不对生成的event进行分析。
- 分析event并产生输出,Bro自实现了一套脚本语言,并内置了常用功能,使用者可以根据需要实现分析脚本。注意,Bro脚本语言是基于event驱动的。
- 导入:@load+相对路径,结尾无分号。Bro搜索路径+相对路径=导入文件绝对路径。相对路径为目录,则导入该路径下的__load__.bro文件,该文件多包含一组@load指令,类似python包的__init__.py文件;相对路径为文件,可忽略.bro后缀。导入将递归执行,重复导入将被忽略。
- 导出:export{scope name: type = value;},export代码块结束无分号,声明及初始化语句后有。用于声明或重定义公用变量,可供当前和其他脚本使用。需要重定义的一般为常量,常量允许在parse-time重定义,run-time不允许修改,与变量不同。
- 业务逻辑:event/hook/function等可执行代码块,实现业务功能。
- event queue是Bro底层(event生成器)和Bro脚本共用的有序队列(先进先出)。
- event生成器根据解析的流量生成event推入event queue,相当于生产者。这部分功能没有Bro脚本参与,不对使用者开放,基本没有其他有效输出。
- Bro脚本从event queue取出event并触发对应event handler完成既定处理,相当于消费者。
- Bro脚本声明并初始化handler,handler被event触发后接收event携带的信息,并基于这些信息进行决策,也可能修改它们。
- Bro在內建函数脚本和*.bif.bro脚本中使用event关键字声明event handler,涵盖全部內建event类型,event将触发对应名称的event handler。
- handler包含用户对event的自定义处理,因此,哪些需要初始化、如何初始化一般由用户根据业务场景自定义。相同类型的handler可以被初始化多次并指定优先级,Bro将在parse-time合并handler,优先级高低与数值大小正相关,默认为0,接受负数。
- Logging Framework可以配置生成自定义event,用户需要自行声明并初始化log_x event handler,以便完成处理。
- record提供了一个key-value模式的数据类型框架,使用户可以通过type和record关键字自定义数据类型。文档中的record类型多泛指这类自定义数据类型,connection就是其中一种。
- 一条connection数据对应一个连接,连接的生命周期内可能触发多个event handler,connection数据也在这个过程中被不断修改和完善。connection类型就是用于跟踪记录一个连接在其生命周期内的状态变化。
- Bro脚本有两种等价的参数声明方式:
- SCOPE name: TYPE;
- SCOPE name = EXPRESSION;
- SCOPE支持三种关键字:global(全局变量)、const(全局常量)和local(局部变量)。
- global一般定义在parse-time,作用于整个命名空间,只能在run-time修改。
- const一般定义在parse-time,作用于整个命名空间,有&redef属性可以在parse-time修改。
- local只能定义在run-time,作用于当前代码块,只能在run-time的当前代码块修改。注意:event和hook可能由多代码块组成。
- 当前命名空间由当前文件+已导入且module name相同的其他文件组成,所有已导入且module name不同的文件的export区域将根据module name合并后成为当前命名空间的子空间,并通过module name引用。
- Bro启动时将处理脚本中除可执行类型(event/hook/function)以外内容,称为parse-time;然后等待事件触发相应可执行类型,完成处理,即所谓的事件驱动,该阶段称为run-time。
- 相同作用域内,global、const和local均不允许重名。
int | |
简要说明: | 有符号整形 |
显式声明及初始化: |
scope name: int; name = return_int_expression; scope name: int = return_int_expression; # 相比隐式声明,可读性和可维护性更好 |
隐式声明及初始化: | scope name = return_int_expression; |
数据格式: | 略 |
算数运算: | 略 |
比较运算: | 略 |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 容器类型操作,不具备 |
删除成员: | 容器类型操作,不具备 |
成员数量: | 容器类型操作,不具备 |
成员是否存在: | 容器类型操作,不具备 |
索引成员: | 容器类型操作,不具备 |
分片: | 容器类型操作,不具备 |
遍历操作: | 容器类型操作,不具备 |
內建函数: | 略 |
count | |
简要说明: | 无符号整形 |
显式声明及初始化: |
scope name: count; name = return_count_expression; scope name: count = return_count_expression; # 相比隐式声明,可读性和可维护性更好 |
隐式声明及初始化: | scope name = return_count_expression; |
数据格式: | 略 |
算数运算: | 略 |
比较运算: | 略 |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 容器类型操作,不具备 |
删除成员: | 容器类型操作,不具备 |
成员数量: | 容器类型操作,不具备 |
成员是否存在: | 容器类型操作,不具备 |
索引成员: | 容器类型操作,不具备 |
分片: | 容器类型操作,不具备 |
遍历操作: | 容器类型操作,不具备 |
內建函数: | 略 |
double | |
简要说明: | 略 |
显式声明及初始化: |
scope name: double; name = return_double_expression; scope name: double = return_double_expression; # 相比隐式声明,可读性和可维护性更好 |
隐式声明及初始化: | scope name = return_double_expression; |
数据格式: | 略 |
算数运算: | 略 |
比较运算: | 略 |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 容器类型操作,不具备 |
删除成员: | 容器类型操作,不具备 |
成员数量: | 容器类型操作,不具备 |
成员是否存在: | 容器类型操作,不具备 |
索引成员: | 容器类型操作,不具备 |
分片: | 容器类型操作,不具备 |
遍历操作: | 容器类型操作,不具备 |
內建函数: | 略 |
string | |
简要说明: |
字符串类型,与python字符串类型非常类似 支持负索引;具备容器部分特征 注意使用双引号描述字符串 |
显式声明及初始化: |
scope name: string; name = return_str_expression; scope name: string = return_str_expression; # 相比隐式声明,可读性和可维护性更好 |
隐式声明及初始化: | scope name = return_str_expression; |
数据格式: | "hello world" |
算数运算: | 支持加法运算,用于字符串连接,其他不支持 |
比较运算: | 支持,判断相等时,注意 str1 == str2 和 my_pattern == str |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 容器类型操作,不具备 |
删除成员: | 容器类型操作,不具备 |
成员数量: | 支持,使用||操作符 |
成员是否存在: | 支持,使用in或!in,注意 str1 in str2 和 my_pattern in str |
索引成员: | 支持,使用从0开始递增的数字索引,支持负索引 |
分片: | 支持,使用[from : to]操作符,from和to为索引,支持负索引、索引越界、索引缺失 |
遍历操作: | 支持,使用for (...in...) |
內建函数: | 略 |
bool | |
简要说明: | 布尔类型,使用T表示真,使用F表示假 |
显式声明及初始化: |
scope name: bool; name = return_bool_expression; scope name: bool = return_bool_expression; # 相比隐式声明,可读性和可维护性更好 |
隐式声明及初始化: | scope name = return_bool_expression; |
数据格式: | T或F |
算数运算: | 不支持 |
比较运算: | 不支持 |
逻辑运算: | 支持,使用&&和||操作符 |
添加成员: | 容器类型操作,不具备 |
删除成员: | 容器类型操作,不具备 |
成员数量: | 容器类型操作,不具备 |
成员是否存在: | 容器类型操作,不具备 |
索引成员: | 容器类型操作,不具备 |
分片: | 容器类型操作,不具备 |
遍历操作: | 容器类型操作,不具备 |
內建函数: | 略 |
addr | |
简要说明: | 表示网络层地址,支持IPv4和IPv6,Bro自定义数据类型之一 |
显式声明及初始化: |
scope name: addr; name = return_addr_expression; scope name: addr = return_addr_expression; # 相比隐式声明,可读性和可维护性更好 |
隐式声明及初始化: | scope name = return_addr_expression; |
数据格式: |
IPv4:10.136.17.35 IPv6: 域名:www.baidu.com # 域名将进行自动转换,因域名可能对应多个IP,转换为set[addr] # Bro运行过程中,域名-IP映射关系不会更新,建议用于域名稳定的场景 # 因域名自动转换为set[addr],使用显式声明会导致声明和初始化数据类型不一致的报错 |
算数运算: | 不支持 |
比较运算: | 支持 |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 容器类型操作,不具备 |
删除成员: | 容器类型操作,不具备 |
成员数量: | 容器类型操作,不具备 |
成员是否存在: | 容器类型操作,不具备 |
索引成员: | 容器类型操作,不具备 |
分片: | 容器类型操作,不具备 |
遍历操作: | 容器类型操作,不具备 |
內建函数: | 略 |
port | |
简要说明: | 表示传输层端口,支持UDP/TCP/ICMP/UNKNOWN协议,Bro自定义数据类型之一 |
显式声明及初始化: |
scope name: port; name = return_port_expression; scope name: port = return_port_expression; # 相比隐式声明,可读性和可维护性更好 |
隐式声明及初始化: | scope name = return_port_expression; |
数据格式: |
端口号/协议 UDP:514/udp TCP:80/tcp ICMP:/icmp,没有端口概念,Bro将ICMP类型和编码设置为来源和目的端口 UNKNOWN:/unknown |
算数运算: | 不支持 |
比较运算: | 支持,默认unknown < tcp < udp < icmp |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 容器类型操作,不具备 |
删除成员: | 容器类型操作,不具备 |
成员数量: | 容器类型操作,不具备 |
成员是否存在: | 容器类型操作,不具备 |
索引成员: | 容器类型操作,不具备 |
分片: | 容器类型操作,不具备 |
遍历操作: | 容器类型操作,不具备 |
內建函数: | 略 |
subnet | |
简要说明: | 表示子网,使用CIDR记法,支持容器类型部分特征,Bro自定义数据类型之一 |
显式声明及初始化: |
scope name: subnet; name = return_subnet_expression; scope name: subnet = return_subnet_expression; # 相比隐式声明,可读性和可维护性更好 |
隐式声明及初始化: | scope name = return_subnet_expression; |
数据格式: | 10.136.17.35/24 |
算数运算: | 不支持 |
比较运算: | 仅支持==和!= |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 容器类型操作,不具备 |
删除成员: | 容器类型操作,不具备 |
成员数量: | 支持,使用||操作符 |
成员是否存在: | 支持,使用in或!in,用于判断IP是否属于该子网 |
索引成员: | 容器类型操作,不具备 |
分片: | 容器类型操作,不具备 |
遍历操作: | 容器类型操作,不具备 |
內建函数: | 略 |
time | |
简要说明: | 表示时间戳,Bro自定义数据类型之一 |
显式声明及初始化: |
scope name: time; name = return_time_expression; scope name: time = return_time_expression; # 相比隐式声明,可读性和可维护性更好 |
隐式声明及初始化: | scope name = return_time_expression; |
数据格式: | 无法直接初始化,需要借助current_time()或network_time()函数 |
算数运算: | 支持,注意time类型相减返回interval类型,注意time类型和interval类型的加减法 |
比较运算: | 支持 |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 容器类型操作,不具备 |
删除成员: | 容器类型操作,不具备 |
成员数量: | 容器类型操作,不具备 |
成员是否存在: | 容器类型操作,不具备 |
索引成员: | 容器类型操作,不具备 |
分片: | 容器类型操作,不具备 |
遍历操作: | 容器类型操作,不具备 |
內建函数: |
current_time() # 返回操作系统当前时间 network_time() # 返回最后一个已处理数据包内记录的时间,未曾处理数据包则返回当前时间 strftime("%Y-%m-%d %H:%M:%S", current_time()) # 将time转换为可读字符串,注意时区 |
interval | |
简要说明: | 表示相对时间,Bro自定义数据类型之一 |
显式声明及初始化: |
scope name: interval; name = return_interval_expression; scope name: interval = return_interval_expression; # 相比隐式声明,可读性和可维护性更好 |
隐式声明及初始化: | scope name = return_interval_expression; |
数据格式: |
数字+0或1个空格+单位 数字支持整数、浮点数、负数 单位支持:微秒(usec)、毫秒(msec)、秒(sec)、分( min)、时(hr)和天(day) 单位单数复数均可,即:print 1hr == 1 hrs; # return T |
算数运算: | 支持,注意time类型相减返回interval类型,注意time类型和interval类型的加减法 |
比较运算: | 支持 |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 容器类型操作,不具备 |
删除成员: | 容器类型操作,不具备 |
成员数量: | 容器类型操作,不具备 |
成员是否存在: | 容器类型操作,不具备 |
索引成员: | 容器类型操作,不具备 |
分片: | 容器类型操作,不具备 |
遍历操作: | 容器类型操作,不具备 |
內建函数: | 略 |
pattern | |
简要说明: | 表示正则表达式,用于对文本快速检索,具备容器类型的部分特征,Bro自定义数据类型之一 |
显式声明及初始化: |
scope name: pattern; name = return_pattern_expression; scope name: pattern = return_pattern_expression; # 相比隐式声明,可读性和可维护性更好 |
隐式声明及初始化: | scope name = return_pattern_expression; |
数据格式: | /regular expression/ |
算数运算: | 不支持 |
比较运算: | 仅支持文本完整匹配,使用==或!=操作符 |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 容器类型操作,不具备 |
删除成员: | 容器类型操作,不具备 |
成员数量: | 容器类型操作,不具备 |
成员是否存在: | 支持文本嵌入式匹配,使用in或!in,正则表达式必须位于左侧 |
索引成员: | 容器类型操作,不具备 |
分片: | 容器类型操作,不具备 |
遍历操作: | 容器类型操作,不具备 |
內建函数: | split(str, my_pattern) # 返回数字索引的table,索引由1开始,有序保存分割后的字符串 |
set | |
简要说明: | 表示成员唯一的集合,类似于python中的set,但要求成员类型一致 |
显式声明及初始化: |
scope name: set[int]; name = set(1, 2, 3); scope name: set[int] = set(1, 2, 3); # 可读性和可维护性更好 |
隐式声明及初始化: | scope name = set(1, 2, 3); |
数据格式: | |
算数运算: | 不支持 |
比较运算: | 不支持 |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 支持,使用add关键字:local s = set(1, 2); add s[3]; print s; # return {1, 2, 3} |
删除成员: | 支持,使用delete关键字,用法同add |
成员数量: | 支持,使用||操作符 |
成员是否存在: | 支持,使用in或!in |
索引成员: | 不支持 |
分片: | 不支持 |
遍历操作: | 支持,使用for (...in...) |
內建函数: | 略 |
table | |
简要说明: | 表示key-value间的映射,key唯一,类似python的dict,但key类型一致且value类型一致 |
显式声明及初始化: |
scope name: table[string] of string; name = table(["a"]="b", ["c"]="b"); scope name: table[string] of string =table(["a"]="b", ["c"]="b"); # 可读性和可维护性更好 |
隐式声明及初始化: | scope name = table(["a"]="b", ["c"]="b"); |
数据格式: |
支持多个基本数据类型组合作为key,如:local t: table[int, string] of int = table([1, "2"]=3); 后续初始化和赋值时需要注意key需要遵循声明时的格式 |
算数运算: | 不支持 |
比较运算: | 不支持 |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 支持,使用赋值语句即可 |
删除成员: | 支持,使用delete关键字,用法同set |
成员数量: | 支持,使用||操作符 |
成员是否存在: |
支持,使用in或!in,注意,仅针对key进行检测,如: local t = table([1, "2"] = 3); print [1, "2"] in t; # return T |
索引成员: | 支持 |
分片: | 不支持 |
遍历操作: |
支持,使用for (...in...),注意,仅针对key进行遍历,对组合key的遍历只能整体遍历,如: for ([i, j] in table([1, "2"] = 3)) { print i; } # return 1 |
內建函数: | 略 |
vector | |
简要说明: | 表示有序数组,类似python的list,但要求成员类型一致 |
显式声明及初始化: |
scope name: vector of int; name = vector(1, 1, 2); scope name: vector of int = vector(1, 1, 2); # 可读性和可维护性更好 |
隐式声明及初始化: | scope name = vector(1, 1, 2); |
数据格式: | 索引由0开始递增,连续不间断 |
算数运算: | 不支持 |
比较运算: | 不支持 |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 支持,使用赋值语句即可,注意索引连续 |
删除成员: | 不支持 |
成员数量: | 支持,使用||操作符 |
成员是否存在: | 支持,使用in或!in,注意,仅针对索引进行检测 |
索引成员: | 支持 |
分片: | 不支持 |
遍历操作: | 支持,使用for (...in...),注意,仅针对索引进行遍历 |
內建函数: | 略 |
自定义数据类型 | |
简要说明: |
使用type和record关键字自定义数据类型,类似于C语言的结构体 可以任意定义数据类型中每个成员key和value的数据类型,但使用时必须按定义初始化或赋值 |
类型自定义 |
type Service: record { name: string; ports: set[port]; }; 自定义数据类型时允许嵌套包含其他自定义的数据类型 类型定义需在Bro解析阶段完成,即类型定义必须位于可执行代码(event/hook/function)外部 |
显式声明及初始化: |
scope name: Service; name = Service($name="dns", $ports=set(53/tcp, 53/udp)); scope name: Service = Service($name="dns", $ports=set(53/tcp, 53/udp)); 后者可读性和可维护性更好 初始化时在key前添加$符号 |
隐式声明及初始化: | scope name = Service($name="dns", $ports=set(53/tcp, 53/udp)); |
数据格式: | 略 |
算数运算: | 不支持 |
比较运算: | 不支持 |
逻辑运算: | 不可自动转换为bool类型,因此不可参与逻辑运算 |
添加成员: | 容器类型操作,不具备 |
删除成员: | 容器类型操作,不具备 |
成员数量: | 支持,使用||操作符 |
成员是否存在: | 容器类型操作,不具备 |
索引成员: | 访问自定义类型数据的成员使用$符号 |
分片: | 容器类型操作,不具备 |
遍历操作: | 容器类型操作,不具备 |
內建函数: | 略 |
- 日志生成主要涉及Log Stream、Filter和Writer三部分,具体含义如下:
- Log Stream:定义字段种类、字段类型、日志类型、日志名等日志处理过程中的基本规则,以便用户根据这些要求提供源数据。
- Filter:对源进行过滤、修改、重定向等处理,默认Filter不进行任何处理。
- Writer:决定日志输出方式和格式,默认writer将日志输出为tab分隔的文本文件,也支持ES等输出方式。
- 使用Logging Framework的步骤如下:
- Bro解析阶段:注册Log Stream ID、自定义数据类型Info描述日志内容
- Bro运行初始化阶段:创建Log Stream、修改Log Stream的Filter
- Bro运行阶段:写入Log Steam。
- Logging Framework可以配置生成自定义的event,用户需要自行声明并初始化log_x event handler,并在其t中进行后置处理,避免了解析文本日志再分析的冗余操作,提高分析实时性。
- Bro解析阶段:注册Notice Type。
- Bro运行阶段:根据Notice::Info生成notice数据,通过NOTICE函数传入Notice Framework。
- Notice Framework:通过hook修改notice数据并触发相应通知行为(可以在Bro解析阶段定义Notice Policy shortcut简化该步骤)。
2.5 Bro脚本入门相关推荐
- 用python写脚本看什么书-终于知晓python编写脚本入门教程
PyQt5是基于Digia公司强大的图形程式框架Qt5的python接口,由一组python模块构成.PyQt5本身拥有超过620个类和6000函数及方法.在可以运行于多个平台.PyQt5拥有双重协议 ...
- Linux Shell脚本入门--wget 命令用法详解
Linux Shell脚本入门--wget 命令用法详解 wget是在Linux下开发的开放源代码的软件,作者是Hrvoje Niksic,后来被移植到包括Windows在内的各个平台上.它有以下功能 ...
- Linux之Shell脚本入门
一.Shell概述 Shell是一个命令行解释器,它接受应用程序/用户命令,然后调用操作系统内核. Shell还是一个功能强大的编程语言,易编写.易调试.灵活性强. 二.Shell脚本入门 1.脚本格 ...
- Linux Shell脚本入门教程系列之(十六) Shell输入输出重定向
本文是Linux Shell系列教程的第(十六)篇,更多Linux Shell教程请看:Linux Shell系列教程 Shell中的输出和输入的重定向是在使用中经常用到的一个功能,非常实用,今天就为 ...
- Linux Shell脚本入门教程系列之(十五) Shell函数简介
本文是Linux Shell脚本系列教程的第(十五)篇,更多Linux Shell教程请看:Linux Shell脚本系列教程 上一篇之后,函数可以将一个复杂功能划分成若干模块,从而使程序结构更加清晰 ...
- Linux Shell脚本入门教程系列之(十四) Shell Select教程
本文是Linux Shell脚本系列教程的第(十四)篇,更多Linux Shell教程请看:Linux Shell脚本系列教程 在上一篇文章:Linux Shell系列教程之(十三)Shell分支语句 ...
- Linux Shell脚本入门教程系列之(十三)Shell分支语句case … esac教程
本文是Linux Shell脚本系列教程的第(十三)篇,更多Linux Shell教程请看:Linux Shell脚本系列教程 上一篇之 后,分支语句非常实用,基本上高级语言都支持分支语句(pytho ...
- Linux Shell脚本入门教程系列之(十二)Shell until循环
本文是Linux Shell脚本系列教程的第(十二)篇,更多Linux Shell教程请看:Linux Shell脚本系列教程 在上两篇文章Linux Shell系列教程之(十)Shell for循环 ...
- Linux Shell脚本入门教程系列之(十一)Shell while循环
本文是Linux Shell脚本系列教程的第(十一)篇,更多Linux Shell教程请看:Linux Shell脚本系列教程 在上一篇Linux Shell系列教程之(十)Shell for循环中, ...
最新文章
- Pycharm快捷键及一些常用设置
- TensorFlowSharp入门使用C#编写TensorFlow人工智能应用
- 使用Spring MVC HandlerExceptionResolver处理异常
- gevent.hub.LoopExit: ('This operation would block forever'
- view里文书删除时报错的解决案
- java的时间变化_通过java记录数据持续变化时间代码解析
- Redis的session管理和Memcached的session管理不同
- 基于POI的读写Excel文件的工具类
- 【渝粤教育】国家开放大学2019年春季 2508学前儿童语言教育 参考试题
- Java Thread类最终同步的void join(long time_in_ms)方法,带有示例
- android 引用非 android 工程,Unity3D调用android方法(非插件方式)
- 火狐浏览器如何更改字体 火狐浏览器字体更改方法分享
- 使用Python往Elasticsearch插入数据
- 开源计算机集群监控Ganglia应用视频
- The content of element type configuration must match (properties?,settings?,typeAliases?,typeHand...
- window下Jekyll+github搭建自己的博客
- 《CUDA C编程权威指南》——2.4节设备管理
- socket通信问题
- 修改Android模拟器存储位置,更改AndroidAVD模拟器创建路径位置的方法
- 【SAMMY】DOS下操作隐藏文件、文件夹
热门文章
- Android 进阶17:Fragment FragmentManager FragmentTransaction 深入理解
- 苹果手机文件转换html,手机html文件怎么打开?1分钟打开苹果html文件
- 如何在万米高空畅享5G?
- java 获取对象属性值为空或者非空的属性名称
- Linux软件包管理-rpm、yum
- 山东电网计算机专业录取率,国家电网太难进?网友:这个二本高校进山东电网的人数仅次于山大...
- 再谈Android的许可证
- 苹果手机来电铃声设置方法
- ajax动态加载div,JQuery/AJAX:使用动态内容加载外部DIV使用动态内容
- hdu 4481 Time travel(高斯求期望)