diff --git a/CHANGES b/CHANGES index 43db51c454..9030c782b4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,14 @@ +8.1.0-dev.531 | 2025-09-08 11:19:36 -0700 + + * btest/core/suspend_processing: Add WebSocket example (Arne Welzel, Corelight) + + Add a test/example forwarding all new_connection() events produced during + `zeek -r wikipedia.trace` as my_new_connection() to a WebSocket client. + + This is mostly to demonstrate and verify usage of suspend_processing(), + websocket_client_added(), resume_processing(), Pcap::file_done(), + websocket_client_lost() and terminate() together. + 8.1.0-dev.529 | 2025-09-08 11:02:39 -0700 * Bump Spicy for Coverity fixes (Evan Typanski, Corelight) diff --git a/VERSION b/VERSION index 7ce5698eda..4babdbe604 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.1.0-dev.529 +8.1.0-dev.531 diff --git a/testing/btest/Baseline/core.suspend_processing.websocket/client..stdout b/testing/btest/Baseline/core.suspend_processing.websocket/client..stdout new file mode 100644 index 0000000000..95f3f558ef --- /dev/null +++ b/testing/btest/Baseline/core.suspend_processing.websocket/client..stdout @@ -0,0 +1,37 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +Connected! +test.conns.CHhAvVGS1DHFjwGM9 my_new_connection ['CHhAvVGS1DHFjwGM9', 1] +test.conns.ClEkJM2Vm5giqnMf4h my_new_connection ['ClEkJM2Vm5giqnMf4h', 2] +test.conns.C4J4Th3PJpwUYZZ6gc my_new_connection ['C4J4Th3PJpwUYZZ6gc', 3] +test.conns.CtPZjS20MLrsMUOJi2 my_new_connection ['CtPZjS20MLrsMUOJi2', 4] +test.conns.CUM0KZ3MLUfNB0cl11 my_new_connection ['CUM0KZ3MLUfNB0cl11', 5] +test.conns.CmES5u32sYpV7JYN my_new_connection ['CmES5u32sYpV7JYN', 6] +test.conns.CP5puj4I8PtEU4qzYg my_new_connection ['CP5puj4I8PtEU4qzYg', 7] +test.conns.C37jN32gN3y3AZzyf6 my_new_connection ['C37jN32gN3y3AZzyf6', 8] +test.conns.C3eiCBGOLw3VtHfOj my_new_connection ['C3eiCBGOLw3VtHfOj', 9] +test.conns.CwjjYJ2WqgTbAqiHl6 my_new_connection ['CwjjYJ2WqgTbAqiHl6', 10] +test.conns.C0LAHyvtKSQHyJxIl my_new_connection ['C0LAHyvtKSQHyJxIl', 11] +test.conns.CFLRIC3zaTU1loLGxh my_new_connection ['CFLRIC3zaTU1loLGxh', 12] +test.conns.C9rXSW3KSpTYvPrlI1 my_new_connection ['C9rXSW3KSpTYvPrlI1', 13] +test.conns.Ck51lg1bScffFj34Ri my_new_connection ['Ck51lg1bScffFj34Ri', 14] +test.conns.C9mvWx3ezztgzcexV7 my_new_connection ['C9mvWx3ezztgzcexV7', 15] +test.conns.CNnMIj2QSd84NKf7U3 my_new_connection ['CNnMIj2QSd84NKf7U3', 16] +test.conns.C7fIlMZDuRiqjpYbb my_new_connection ['C7fIlMZDuRiqjpYbb', 17] +test.conns.CykQaM33ztNt0csB9a my_new_connection ['CykQaM33ztNt0csB9a', 18] +test.conns.CtxTCR2Yer0FR1tIBg my_new_connection ['CtxTCR2Yer0FR1tIBg', 19] +test.conns.CpmdRlaUoJLN3uIRa my_new_connection ['CpmdRlaUoJLN3uIRa', 20] +test.conns.C1Xkzz2MaGtLrc1Tla my_new_connection ['C1Xkzz2MaGtLrc1Tla', 21] +test.conns.CqlVyW1YwZ15RhTBc4 my_new_connection ['CqlVyW1YwZ15RhTBc4', 22] +test.conns.CLNN1k2QMum1aexUK7 my_new_connection ['CLNN1k2QMum1aexUK7', 23] +test.conns.CBA8792iHmnhPLksKa my_new_connection ['CBA8792iHmnhPLksKa', 24] +test.conns.CGLPPc35OzDQij1XX8 my_new_connection ['CGLPPc35OzDQij1XX8', 25] +test.conns.CiyBAq1bBLNaTiTAc my_new_connection ['CiyBAq1bBLNaTiTAc', 26] +test.conns.CFSwNi4CNGxcuffo49 my_new_connection ['CFSwNi4CNGxcuffo49', 27] +test.conns.Cipfzj1BEnhejw8cGf my_new_connection ['Cipfzj1BEnhejw8cGf', 28] +test.conns.CV5WJ42jPYbNW9JNWf my_new_connection ['CV5WJ42jPYbNW9JNWf', 29] +test.conns.CPhDKt12KQPUVbQz06 my_new_connection ['CPhDKt12KQPUVbQz06', 30] +test.conns.CAnFrb2Cvxr5T7quOc my_new_connection ['CAnFrb2Cvxr5T7quOc', 31] +test.conns.C8rquZ3DjgNW06JGLl my_new_connection ['C8rquZ3DjgNW06JGLl', 32] +test.conns.CzrZOtXqhwwndQva3 my_new_connection ['CzrZOtXqhwwndQva3', 33] +test.conns.CaGCc13FffXe6RkQl9 my_new_connection ['CaGCc13FffXe6RkQl9', 34] +test.finish Pcap::file_done ['<...>/wikipedia.trace'] diff --git a/testing/btest/Baseline/core.suspend_processing.websocket/worker..stdout b/testing/btest/Baseline/core.suspend_processing.websocket/worker..stdout new file mode 100644 index 0000000000..c4be2ab185 --- /dev/null +++ b/testing/btest/Baseline/core.suspend_processing.websocket/worker..stdout @@ -0,0 +1,41 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +0.0, zeek_init: suspend_processing() +0.0: Cluster::websocket_client_added [<...>/, test.] +1300475167.096535, network_time_init +1300475167.096535, new_connection, CHhAvVGS1DHFjwGM9, 1 +1300475167.097012, new_connection, ClEkJM2Vm5giqnMf4h, 2 +1300475167.099816, new_connection, C4J4Th3PJpwUYZZ6gc, 3 +1300475168.652003, new_connection, CtPZjS20MLrsMUOJi2, 4 +1300475168.724007, new_connection, CUM0KZ3MLUfNB0cl11, 5 +1300475168.853899, new_connection, CmES5u32sYpV7JYN, 6 +1300475168.854378, new_connection, CP5puj4I8PtEU4qzYg, 7 +1300475168.854837, new_connection, C37jN32gN3y3AZzyf6, 8 +1300475168.855305, new_connection, C3eiCBGOLw3VtHfOj, 9 +1300475168.85533, new_connection, CwjjYJ2WqgTbAqiHl6, 10 +1300475168.857956, new_connection, C0LAHyvtKSQHyJxIl, 11 +1300475168.858306, new_connection, CFLRIC3zaTU1loLGxh, 12 +1300475168.858713, new_connection, C9rXSW3KSpTYvPrlI1, 13 +1300475168.859163, new_connection, Ck51lg1bScffFj34Ri, 14 +1300475168.891644, new_connection, C9mvWx3ezztgzcexV7, 15 +1300475168.892037, new_connection, CNnMIj2QSd84NKf7U3, 16 +1300475168.892414, new_connection, C7fIlMZDuRiqjpYbb, 17 +1300475168.892913, new_connection, CykQaM33ztNt0csB9a, 18 +1300475168.892936, new_connection, CtxTCR2Yer0FR1tIBg, 19 +1300475168.893988, new_connection, CpmdRlaUoJLN3uIRa, 20 +1300475168.894422, new_connection, C1Xkzz2MaGtLrc1Tla, 21 +1300475168.894787, new_connection, CqlVyW1YwZ15RhTBc4, 22 +1300475168.895267, new_connection, CLNN1k2QMum1aexUK7, 23 +1300475168.901749, new_connection, CBA8792iHmnhPLksKa, 24 +1300475168.902195, new_connection, CGLPPc35OzDQij1XX8, 25 +1300475168.902635, new_connection, CiyBAq1bBLNaTiTAc, 26 +1300475169.780331, new_connection, CFSwNi4CNGxcuffo49, 27 +1300475169.899438, new_connection, Cipfzj1BEnhejw8cGf, 28 +1300475170.862384, new_connection, CV5WJ42jPYbNW9JNWf, 29 +1300475171.675372, new_connection, CPhDKt12KQPUVbQz06, 30 +1300475171.677081, new_connection, CAnFrb2Cvxr5T7quOc, 31 +1300475173.116749, new_connection, C8rquZ3DjgNW06JGLl, 32 +1300475173.117362, new_connection, CzrZOtXqhwwndQva3, 33 +1300475173.153679, new_connection, CaGCc13FffXe6RkQl9, 34 +1300475173.475401, Pcap::file_done, <...>/wikipedia.trace +1300475173.475401: Cluster::websocket_client_lost: 1000, +1300475173.475401, zeek_done diff --git a/testing/btest/Files/ws/wstest.py b/testing/btest/Files/ws/wstest.py index f01ec3d9f6..b8f35b9e57 100644 --- a/testing/btest/Files/ws/wstest.py +++ b/testing/btest/Files/ws/wstest.py @@ -33,8 +33,14 @@ import time from typing import Any, Callable, Optional, Union import websockets.sync.client +from websockets.exceptions import ( + ConnectionClosedError, + ConnectionClosedOK, +) from websockets.sync.client import ClientConnection +_ = ConnectionClosedOK, ConnectionClosedError + WS_PORT = ( int(os.environ["WEBSOCKET_PORT"].split("/")[0]) if "WEBSOCKET_PORT" in os.environ diff --git a/testing/btest/core/suspend_processing/websocket.zeek b/testing/btest/core/suspend_processing/websocket.zeek new file mode 100644 index 0000000000..631d57dd95 --- /dev/null +++ b/testing/btest/core/suspend_processing/websocket.zeek @@ -0,0 +1,93 @@ +# @TEST-DOC: Suspend pcap processing on a single-node worker, wait for a WebSocket client, resume processing and publish all new_connection() events on test.conns.{uid} +# +# @TEST-REQUIRES: python3 -c 'import websockets.sync' +# +# @TEST-PORT: WEBSOCKET_PORT +# +# @TEST-EXEC: cp $FILES/ws/wstest.py . +# +# @TEST-EXEC: zeek --parse-only %INPUT +# +# @TEST-EXEC: btest-bg-run worker "zeek -r $TRACES/wikipedia.trace -b %INPUT" +# @TEST-EXEC: btest-bg-run client "python3 ../client.py" +# @TEST-EXEC: btest-bg-wait 30 +# +# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff worker/.stdout +# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff client/.stdout + +global my_new_connection: event(uid: string, c: count); + +event zeek_init() + { + print network_time(), "zeek_init: suspend_processing()"; + suspend_processing(); + } + +event zeek_init() &priority=-5 + { + Cluster::listen_websocket([ + $listen_addr=127.0.0.1, + $listen_port=to_port(getenv("WEBSOCKET_PORT")) + ]); + } + +event Cluster::websocket_client_added(info: Cluster::EndpointInfo, subscriptions: string_vec) + { + print fmt("%s: Cluster::websocket_client_added %s", network_time(), subscriptions); + continue_processing(); + } + +event Cluster::websocket_client_lost(info: Cluster::EndpointInfo, code: count, reason: string) + { + print fmt("%s: Cluster::websocket_client_lost: %s, %s", network_time(), code, reason); + terminate(); + } + +event network_time_init() + { + print network_time(), "network_time_init"; + } + +global conns = 0; + +event new_connection(c: connection) + { + ++conns; + print network_time(), "new_connection", c$uid, conns; + Cluster::publish(fmt("test.conns.%s", c$uid), my_new_connection, c$uid, conns); + } + +event Pcap::file_done(path: string) + { + print network_time(), "Pcap::file_done", path; + Cluster::publish("test.finish", Pcap::file_done, path); + } + +event zeek_done() + { + print network_time(), "zeek_done"; + } + +# @TEST-START-FILE client.py +import wstest + +def run(ws_url): + with wstest.connect("ws1", ws_url) as tc: + print("Connected!") + tc.hello_v1(["test."]) + + while True: + try: + msg = tc.recv_json() + ev = msg["data"][2]["data"][0]["data"] + args = msg["data"][2]["data"][1]["data"] + print(msg["topic"], ev, [a["data"] for a in args]) + if ev == "Pcap::file_done": + break; + except wstest.ConnectionClosedOK: + print("Connection closed OK") + break + +if __name__ == "__main__": + wstest.main(run, wstest.WS4_URL_V1) +# @TEST-END-FILE