Skip to content
This repository was archived by the owner on Oct 13, 2025. It is now read-only.

Commit 452fc06

Browse files
committed
Add WebSocket API docs to devel section
1 parent cc58d32 commit 452fc06

File tree

3 files changed

+193
-0
lines changed

3 files changed

+193
-0
lines changed

.typos.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ extend-ignore-re = [
2020

2121
# Smoot
2222
"Smoot",
23+
24+
"SIEM",
2325
]
2426

2527
extend-ignore-identifiers-re = [

devel/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ transient, etc. compared to other documentation).
1414

1515
plugins
1616
spicy/index
17+
websocket-api
1718
Documentation Guide </README.rst>
1819
contributors
1920
maintainers

devel/websocket-api.rst

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
.. _websocket-api:
2+
3+
4+
======================================
5+
Interacting with Zeek using WebSockets
6+
======================================
7+
8+
Introduction
9+
============
10+
11+
Usually, Zeek produces protocol logs consumed by external applications. These
12+
external applications might be SIEMs, real-time streaming analysis platforms
13+
or basic archival processes compressing logs for long term storage.
14+
15+
Certain use-cases require interacting and influencing Zeek's runtime behavior
16+
outside of static configuration via ``local.zeek``.
17+
18+
The classic :ref:`framework-input` and :ref:`framework-configuration` can be
19+
leveraged for runtime configuration of Zeek as well as triggering arbitrary
20+
events or script execution via option handlers. These frameworks are mostly
21+
file- or process-based and may feel a bit unusual in environments where creation
22+
of files is uncommon or even impossible due to separation of concerns. In many
23+
of today's environments, interacting using HTTP-based APIs or other remote
24+
interfaces is more common.
25+
26+
.. note::
27+
28+
As an aside, if you need more flexibility than the WebSocket API offers today,
29+
an alternative could be to use :ref:`javascript` within Zeek. This opens the
30+
possibility to run a separate HTTP or a totally different Node.js based server
31+
within a Zeek process for quick experimentation and evaluation of other
32+
approaches.
33+
34+
Background and Setup
35+
====================
36+
37+
Since Zeek 5.0, Zeek allows connections from external clients over WebSocket.
38+
This allows these clients to interact with Zeek's publish-subscribe layer and
39+
exchange Zeek events with other Zeek nodes.
40+
Initially, this implementation resided in the Broker subsystem.
41+
With Zeek 8.0, most of the implementation has been moved into core Zeek
42+
itself with the v1 serialization format remaining in Broker.
43+
44+
WebSocket clients may subscribe to a fixed set of topics and will receive
45+
Zeek events matching these topics that Zeek cluster nodes, but also other
46+
WebSocket clients, publish.
47+
48+
With Zeek 8.0, Zeekctl has received support to interact with Zeek cluster nodes
49+
using the WebSocket protocol. If you're running a Zeekctl based cluster and
50+
want to experiment with WebSocket functionality, add ``UseWebSocket = 1`` to
51+
your ``zeekctl.cfg``:
52+
53+
.. code-block:: ini
54+
55+
# zeekctl.cfg
56+
...
57+
UseWebSocket = 1
58+
59+
This will essentially add the following snippet, enabling a WebSocket server
60+
on the Zeek manager:
61+
62+
.. code-block:: zeek
63+
:caption: websocket.zeek
64+
65+
event zeek_init()
66+
{
67+
if ( Cluster::local_node_type() == Cluster::MANAGER )
68+
{
69+
Cluster::listen_websocket([
70+
$listen_addr=127.0.0.1,
71+
$listen_port=27759/tcp,
72+
]);
73+
}
74+
}
75+
76+
77+
To verify that the WebSocket API is functional in your deployment use, for example,
78+
`websocat <https://github.com/vi/websocat>`_ as a quick check.
79+
80+
.. code-block:: shell
81+
82+
$ echo '[]' | websocat ws://127.0.0.1:27759/v1/messages/json
83+
{"type":"ack","endpoint":"3eece35d-9f94-568d-861c-6a16c433e090-websocket-2","version":"8.0.0-dev.684"}
84+
85+
Zeek's ``cluster.log`` file will also have an entry for the WebSocket client connection.
86+
The empty array in the command specifies the client's subscriptions, in this case none.
87+
88+
Version 1
89+
=========
90+
91+
The currently implemented protocol is accessible at ``/v1/messages/json``.
92+
The `data representation <https://docs.zeek.org/projects/broker/en/current/web-socket.html#data-representation>`_
93+
is documented in detail within the Broker project. Note that this format is a
94+
direct translation of Broker's binary format into JSON, resulting in a fairly
95+
tight coupling between WebSocket clients and the corresponding Zeek scripts.
96+
Most prominently is the representation of record values as vectors instead
97+
of objects, making the protocol sensitive against reordering or introduction
98+
of optional fields to records.
99+
100+
.. note::
101+
102+
We're looking into an iteration of the format. If you have feedback or
103+
would like to contribute, please reach out on the usual community channels.
104+
105+
106+
Handshake and Acknowledgement
107+
-----------------------------
108+
109+
The first message after a WebSocket connection has been established originates
110+
from the client. This message is a JSON array of strings that represent the
111+
topics the WebSocket client wishes to subscribe to.
112+
113+
Zeek replies with an acknowledgement message that's a JSON object or an error.
114+
115+
Events
116+
------
117+
118+
After the acknowledgement, WebSocket clients receive all events arriving on
119+
topics they have subscribed to.
120+
121+
.. code-block:: shell
122+
123+
$ websocat ws://127.0.0.1:27759/v1/messages/json
124+
["zeek.test"]
125+
{"type":"ack","endpoint":"d955d990-ad8a-5ed4-8bc5-bee252d4a2e6-websocket-0","version":"8.0.0-dev.684"}
126+
{"type":"data-message","topic":"zeek.test","@data-type":"vector","data":[{"@data-type":"count","data":1},{"@data-type":"count","data":1},{"@data-type":"vector","data":[{"@data-type":"string","data":"hello"},{"@data-type":"vector","data":[{"@data-type":"count","data":3}]},{"@data-type":"vector","data":[]}]}]}
127+
128+
The received messages, again, are encoded in Broker's JSON format. Above ``data-message``
129+
represents an event received on topic ``zeek.test``. The event's name is ``hello``.
130+
This event has a single argument of type :zeek:type:`count`. In the example above
131+
its value is ``3``.
132+
133+
To send events, WebSocket clients similarly encode their event representation
134+
to Broker's JSON format and send them as `text data frames <https://datatracker.ietf.org/doc/html/rfc6455#section-5.6>`_.
135+
136+
137+
Language Bindings
138+
-----------------
139+
140+
Note that it's possible to use any language that offers WebSocket bindings.
141+
The ones listed below mostly add a bit of convenience features around the
142+
initial Handshake message, error handling and serializing Zeek events and
143+
values into the Broker-specific serialization format.
144+
145+
For example, using the Node.js `builtin WebSocket functionality <https://nodejs.org/en/learn/getting-started/websocket>`_,
146+
the ``websocat`` example from above can be reproduced as follows:
147+
148+
.. code-block:: javascript
149+
:caption: client.js
150+
151+
// client.js
152+
const socket = new WebSocket('ws://192.168.122.107:27759/v1/messages/json');
153+
154+
socket.addEventListener('open', event => {
155+
socket.send('["zeek.test"]');
156+
});
157+
158+
socket.addEventListener('message', event => {
159+
console.log('Message from server: ', event.data);
160+
});
161+
162+
.. code-block:: shell
163+
164+
$ node ./client.js
165+
Message from server: {"type":"ack","endpoint":"2e951b0c-3ca4-504c-ae8a-5d3750fec588-websocket-10","version":"8.0.0-dev.684"}
166+
Message from server: {"type":"data-message","topic":"zeek.test","@data-type":"vector","data":[{"@data-type":"count","data":1},{"@data-type":"count","data":1},{"@data-type":"vector","data":[{"@data-type":"string","data":"hello"},{"@data-type":"vector","data":[{"@data-type":"count","data":374}]},{"@data-type":"vector","data":[]}]}]}
167+
168+
169+
Golang
170+
^^^^^^
171+
172+
* `Zeek Broker websocket interface library for Golang <https://github.com/corelight/go-zeek-broker-ws>`_ (not an official Zeek project)
173+
174+
175+
Rust
176+
^^^^
177+
178+
* `Rust types for interacting with Zeek over WebSocket <https://github.com/bbannier/zeek-websocket-rs>`_ (not an official Zeek project)
179+
180+
Python
181+
^^^^^^
182+
183+
There are no ready to use Python libraries available, but the third-party
184+
`websockets <https://github.com/python-websockets/websockets>`_ package
185+
allows to get started quickly.
186+
You may take inspiration from `zeek-client's implementation <https://github.com/zeek/zeek-client>`_
187+
or the `small helper library <https://raw.githubusercontent.com/zeek/zeek/refs/heads/master/testing/btest/Files/ws/wstest.py>`_ used by various of Zeek's own tests for the
188+
WebSocket API.
189+
Zeekctl similarly ships a `light implementation <https://github.com/zeek/zeekctl/blob/93459b37c3deab4bec9e886211672024fa3e4759/ZeekControl/events.py#L159>`_
190+
using the ``websockets`` library to implement its ``netstats`` and ``print`` commands.

0 commit comments

Comments
 (0)