该库实现了 Zeek Broker websocket 接口。
提供了在 Zeek 和 Go 类型之间进行合理映射的辅助函数。
该库包含两个包:
encodingencoding 对用于表示 Zeek 类型的递归 JSON 数据结构(Data 结构体)以及 Zeek 事件和错误消息的 Broker 编码(DataMessage 结构体)进行了建模。这些结构可以直接使用(在某些情况下必须直接使用,参见下一节中的订阅示例),但一些辅助函数使构建消息更加方便。要手动构造一个 Zeek string:
zeekString := encoding.Data{
DataType: encoding.TypeString,
DataValue: "foo",
}
……或通过辅助函数:
zeekString := encoding.String("foo")
尤其是 vector 辅助函数,它是一个接受 encoding.Data 的可变参数函数:
zeekVector := encoding.Vector(encoding.Count(1), encoding.Count(2), encoding.Count(3))
最后,可以直接创建事件:
zeekEvent := encoding.NewEvent("some_event_name", zeekVector, zeekString)
clientclient 提供了与 broker WS API 通信的 websocket 粘合层,封装了 github.com/gorilla/websocket:
要发布事件:
broker, err := client.NewClient(...)
err := broker.PublishEvent("/the/topic", zeekEvent)
主题订阅以字符串切片的形式传递给 client.Newclient()。客户端的 ReadEvent() 方法从 Broker 返回单个事件(在任何一个已订阅的主题上),或者返回库本身可能发生的错误(或从 Broker 接收到的错误):
broker, err := client.NewClient(..., []string{"/the/topic"})
topic, zeekEvent, err := broker.ReadEvent()
如果 broker 连接被正常关闭,可以使用 client.IsNormalWebsocketClose() 函数来检查返回的错误。
客户端代码必须通过类型断言来访问事件参数值:
if len(evt.Arguments) < someConstantGreaterOrEqualToOne {
// handle too few arguments case
}
if evt.Arguments[0].DataType != encoding.TypeString {
// handle unexpected data type case
}
stringArgument0, ok := evt.Arguments[0].DataValue.(string)
if !ok {
// handle type assertion error - this would indicate a bug (we trust+verify).
}
// now we use stringArgument0
对通过订阅接收的事件进行异步处理和分发,最好实现为 Client.ReadEvent() 的包装器。client.AsyncSubscription() 中提供了一个简单实现。
对 websocket 连接进行更高级的处理(例如设置超时、处理重连等)最好实现为 client.Client 的包装器,或者使用 encoding 包的新实现/替代实现(欢迎贡献代码/PR!)。
Broker 网络连接(包括原生连接和 websocket 接口)默认启用 TLS,其配置比较特殊:禁用主机验证,并选择一组允许在没有证书的情况下进行加密的密码套件(匿名 Diffie-Hellman / AECDH)。要使用此模式,需要将 weirdtls.BrokerDefaultTLSDialer 作为 dialer 函数参数传递给 encoding.NewClient。请注意,这会引入 OpenSSL 作为依赖。
或者,如果双方(客户端和 zeek/broker)都配置为使用带有证书的 TLS,则可以使用标准库 crypto/tls 的实现。该库提供了一个方便的辅助函数(securetls.MakeSecureDialer()),它根据 CA 和客户端证书/密钥的 PEM 文件返回一个 dialer 函数。有关此配置的示例,请参见 此 btest 用例。
最后,可以使用 redef Broker::disable_ssl = T; 关闭 broker 连接的 TLS。有关以不安全操作参数调用 encoding.NewClient 的示例,请参见 此 btest 用例。
在 zeek 7.2 中,websocket API 将从 broker 移入 Cluster 框架,并且默认关闭 TLS。此 btest 用例 使用了新的 zeek 端函数,并通过将 secure 参数设置为 false 来调用 encoding.NewClient(),演示了如何使用该库。
当 zeek 7.2 成为 LTS 版本时,该库的新(主要)版本将放弃对上述部分所述 AECDH TLS 模式的支持,从而移除 OpenSSL 依赖。
运行 zeek 端的 broker 脚本:
$ cd example/
$ zeek listen.zeek
现在运行示例:
$ cd example/
$ go build && ./example
2023/05/05 12:56:55 connected to remote endpoint with UUID=c9b0bfd6-3b8d-5de2-a51c-9af7b81aaad3 version=2.5.0-dev
2023/05/05 12:56:55 > topic=/topic/test | event ping("my-message": string, "1": count)
2023/05/05 12:56:55 < topic=/topic/test | event pong("my-message": string, "2": count)
2023/05/05 12:56:56 > topic=/topic/test | event ping("my-message": string, "2": count)
2023/05/05 12:56:56 < topic=/topic/test | event pong("my-message": string, "3": count)
……与此同时,zeek 脚本:
peer added, [id=e537f8b4-de32-52ea-9587-4e6e15bdfe20, network=[address=127.0.0.1, bound_port=50690/tcp]]
receiver got ping: my-message, 1
receiver got ping: my-message, 2
encoding 包中的大多数辅助函数和基本数据结构都有单元测试(运行 go test ./...)。
端到端测试以两个 btest 用例的形式实现(运行 cd tests/; btest)。