diff --git a/CHANGES b/CHANGES index abb86692d2..869cf14d0d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,115 @@ +6.2.0-dev.445 | 2024-01-23 18:01:50 +0100 + + * websocket: Handle breaking from WebSocket::configure_analyzer() (Arne Welzel, Corelight) + + ...and various nits from the review. + + * websocket: Address review feedback for BinPac code (Arne Welzel, Corelight) + + * Rename mask_ to masking_key_ + * Fold FrameHeaderFixed into FrameHeader directly + * Drop WebSocket_FramePayloadUnmask type + + Thanks a bunch @ckreibich! + + * fuzzers: Add WebSocket fuzzer (Arne Welzel, Corelight) + + It immediately found an issue with &transient, but fairly stable thereafter. + + This is a separate fuzzer implementation as there's a custom Configure() + call for the analyzer as well as disabling all other analyzers so we + don't fuzz unrelated protocols. + + * websocket: Fix crash for fragmented messages (Arne Welzel, Corelight) + + The &transient attribute does not work well with $element as that won't + be available within &until anymore apparently. + + Found after a few seconds building out the fuzzer. + + * websocket: Verify Sec-WebSocket-Key/Accept headers and review feedback (Arne Welzel, Corelight) + + Don't log them, they are random and arbitrary in the normal case. Users + can do the following to log them if wanted. + + redef += WebSocket::Info$client_key += { &log }; + redef += WebSocket::Info$server_accept += { &log }; + + * btest/websocket: Test for coalesced reply-ping (Arne Welzel, Corelight) + + Add a constructed PCAP where the HTTP/websocket server send a WebSocket + ping message directly with the packet of the HTTP reply. Ensure this is + interpreted the same as if the WebSocket message is in a separate packet + following the HTTP reply. + + For the server side this should work, for the client side we'd need to + synchronize suspend parsing the client side as we currently cannot quite + know whether it's a pipelined HTTP request following, or upgraded protocol + data and we don't have "suspend parsing" functionality here. + + * HTTP/CONNECT: Also weird on extra data in reply (Arne Welzel, Corelight) + + * HTTP/Upgrade: Weird when more data is available (Arne Welzel, Corelight) + + After an HTTP upgrade to another protocol, create a weird if the packet + that contains the HTTP reply *also* contains some additional data + belonging to the upgraded to protocol already. + + * ContentLine: Add GetDeliverStreamRemainingLength() accessor (Arne Welzel, Corelight) + + Helper to get information from the ContentLine analyzer about + bytes still pending to be delivered. In certain cases this can + be a signal for weirdness. + + * HTTP: Drain event queue after instantiating upgrade analyzer (Arne Welzel, Corelight) + + With configurability through script-land comes the draw back + that we actually need to execute event handlers in the middle + of the parsing process: This might not be the best model, but + the script-side configurability it enables is kind of nice. + + This explicit call only matters here when the HTTP reply is + directly followed by some WebSocket message data within the + same network packet, otherwise the queue is drained once the + packet has been completely processed anyhow. + + * btest/http: Explain switching-protocols test change as comment (Arne Welzel, Corelight) + + DPD enables HTTP based on the content of the WebSocket frames. However, + it's not HTTP, the protocol is x-kaazing-handshake and the server sends + some form of status/acknowledge to the client first, so the HTTP and the + HTTP analyzer receives that as the first bytes of the response and + bails, oh well. + + * GH-3424: WebSocket: Introduce new analyzer and log (Arne Welzel, Corelight) + + This adds a new WebSocket analyzer that is enabled with the HTTP upgrade + mechanism introduced previously. It is a first implementation in BinPac with + manual chunking of frame payload. Configuration of the analyzer is sketched + via the new websocket_handshake() event and a configuration BiF called + WebSocket::__configure_analyzer(). In short, script land collects WebSocket + related HTTP headers and can forward these to the analyzer to change its + parsing behavior at websocket_handshake() time. For now, however, there's + no actual logic that would change behavior based on agreed upon extensions + exchanged via HTTP headers (e.g. frame compression). WebSocket::Configure() + simply attaches a PIA_TCP analyzer to the WebSocket analyzer for dynamic + protocol detection (or a custom analyzer if set). The added pcaps show this + in action for tunneled ssh, http and https using wstunnel. One test pcap is + Broker's WebSocket traffic from our own test suite, the other is the + Jupyter websocket traffic from the ticket/discussion. + + This commit further adds a basic websocket.log that aggregates the WebSocket + specific headers (Sec-WebSocket-*) headers into a single log. + + Closes #3424 + + * HTTP: Add mechanism to instantiate Upgrade analyzer (Arne Welzel, Corelight) + + When a HTTP upgrade request/reply is detected, lookup an analyzer tag + from HTTP::upgrade_analyzers, or if nothing is found, attach PIA_TCP. + + * Update doc submodule [nomail] [skip ci] (zeek-bot) + 6.2.0-dev.430 | 2024-01-22 10:36:11 -0700 * Make BIFs just return ValPtr directly instead of BifReturnVal (Tim Wojtulewicz, Corelight) diff --git a/NEWS b/NEWS index b373a5c250..a2dd0177d1 100644 --- a/NEWS +++ b/NEWS @@ -101,6 +101,22 @@ New Functionality Given this is the first iteration of this feature, feedback around usability and use-cases that aren't covered are more than welcome. +- A WebSocket analyzer has been added together with a new ``websocket.log``. + + The WebSocket analyzer is instantiated when a WebSocket handshake over HTTP is + recognized. By default, the payload of WebSocket messages is fed into Zeek's dynamic + protocol detection framework, possibly discovering and analyzing tunneled protocols. + + The format of the log and the event semantics should be considered preliminary until + the arrival of the next long-term-stable release (7.0). + + To disable the analyzer in case of fatal errors or unexpected resource usage, + use the ``Analyzer::disabled_analyzers`` pattern: + + redef Analyzer::disabled_analyzers += { + Analyzer::ANALYZER_WEBSOCKET, + }; + - The SMTP analyzer was extended to recognize and properly handle the BDAT command from RFC 3030. This improves visibility into the SMTP protocol when mail agents and servers support and use this extension. diff --git a/VERSION b/VERSION index c2839c3889..80d9f3e53c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.2.0-dev.430 +6.2.0-dev.445 diff --git a/scripts/base/init-bare.zeek b/scripts/base/init-bare.zeek index 0d818cdf80..8345d71290 100644 --- a/scripts/base/init-bare.zeek +++ b/scripts/base/init-bare.zeek @@ -423,7 +423,6 @@ export { ## The full list of TCP Option fields parsed from a TCP header. type OptionList: vector of Option; } -module GLOBAL; module Tunnel; export { @@ -449,6 +448,51 @@ export { const max_changes_per_connection: count = 5 &redef; } # end export + +module HTTP; +export { + ## Lookup table for Upgrade analyzers. First, a case sensitive lookup + ## is done using the client's Upgrade header. If no match is found, + ## the all lower-case value is used. If there's still no match Zeek + ## uses dynamic protocol detection for the upgraded to protocol instead. + const upgrade_analyzers: table[string] of Analyzer::Tag &redef; +} + +module WebSocket; +export { + ## The WebSocket analyzer consumes and forwards + ## frame payload in chunks to keep memory usage + ## bounded. There should not be a reason to change + ## this value except for debugging and + ## testing reasons. + const payload_chunk_size = 8192 &redef; + + ## Whether to enable DPD on WebSocket frame payload by default. + const use_dpd_default = T &redef; + + ## Record type that is passed to :zeek:see:`WebSocket::configure_analyzer`. + ## + ## This record allows to configure the WebSocket analyzer given + ## parameters collected from HTTP headers. + type AnalyzerConfig: record { + ## The analyzer to attach for analysis of the WebSocket + ## frame payload. See *use_dpd* below for the behavior + ## when unset. + analyzer: Analyzer::Tag &optional; + + ## If *analyzer* is unset, determines whether to attach a + ## PIA_TCP analyzer for dynamic protocol detection with + ## WebSocket payload. + use_dpd: bool &default=use_dpd_default; + + ## The subprotocol as selected by the server, if any. + subprotocol: string &optional; + + ## The WebSocket extensions as selected by the server, if any. + server_extensions: vector of string &optional; + }; +} + module GLOBAL; ## A type alias for a vector of encapsulating "connections", i.e. for when diff --git a/scripts/base/init-default.zeek b/scripts/base/init-default.zeek index 95b1c64628..3a3efb6853 100644 --- a/scripts/base/init-default.zeek +++ b/scripts/base/init-default.zeek @@ -78,6 +78,7 @@ @load base/protocols/ssh @load base/protocols/ssl @load base/protocols/syslog +@load base/protocols/websocket @load base/protocols/tunnels @load base/protocols/xmpp diff --git a/scripts/base/protocols/websocket/__load__.zeek b/scripts/base/protocols/websocket/__load__.zeek new file mode 100644 index 0000000000..465d04deda --- /dev/null +++ b/scripts/base/protocols/websocket/__load__.zeek @@ -0,0 +1,2 @@ +@load ./consts.zeek +@load ./main.zeek diff --git a/scripts/base/protocols/websocket/consts.zeek b/scripts/base/protocols/websocket/consts.zeek new file mode 100644 index 0000000000..c422710bb9 --- /dev/null +++ b/scripts/base/protocols/websocket/consts.zeek @@ -0,0 +1,23 @@ +##! WebSocket constants. + +module WebSocket; + +export { + const OPCODE_CONTINUATION = 0x00; + const OPCODE_TEXT = 0x01; + const OPCODE_BINARY = 0x02; + const OPCODE_CLOSE = 0x08; + const OPCODE_PING = 0x09; + const OPCODE_PONG = 0x0a; + + const opcodes: table[count] of string = { + [OPCODE_CONTINUATION] = "continuation", + [OPCODE_TEXT] = "text", + [OPCODE_BINARY] = "binary", + [OPCODE_CLOSE] = "close", + [OPCODE_PING] = "ping", + [OPCODE_PONG] = "pong", + } &default=function(opcode: count): string { return fmt("unknown-%x", opcode); } &redef; + + const HANDSHAKE_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; +} diff --git a/scripts/base/protocols/websocket/main.zeek b/scripts/base/protocols/websocket/main.zeek new file mode 100644 index 0000000000..ab11a46a08 --- /dev/null +++ b/scripts/base/protocols/websocket/main.zeek @@ -0,0 +1,232 @@ +##! Implements base functionality for WebSocket analysis. +##! +##! Upon a websocket_established() event, logs all gathered information into +##! websocket.log and configures the WebSocket analyzer with the headers +##! collected via http events. + +@load base/protocols/http + +@load ./consts + +module WebSocket; + +# Register the WebSocket analyzer as HTTP upgrade analyzer. +redef HTTP::upgrade_analyzers += { + ["websocket"] = Analyzer::ANALYZER_WEBSOCKET, +}; + +export { + redef enum Log::ID += { LOG }; + + ## The record type for the WebSocket log. + type Info: record { + ## Timestamp + ts: time &log; + ## Unique ID for the connection. + uid: string &log; + ## The connection's 4-tuple of endpoint addresses/ports. + id: conn_id &log; + ## Same as in the HTTP log. + host: string &log &optional; + ## Same as in the HTTP log. + uri: string &log &optional; + ## Same as in the HTTP log. + user_agent: string &log &optional; + ## The WebSocket subprotocol as selected by the server. + subprotocol: string &log &optional; + ## The protocols requested by the client, if any. + client_protocols: vector of string &log &optional; + ## The extensions selected by the the server, if any. + server_extensions: vector of string &log &optional; + ## The extensions requested by the client, if any. + client_extensions: vector of string &log &optional; + ## The Sec-WebSocket-Key header from the client. + client_key: string &optional; + ## The Sec-WebSocket-Accept header from the server. + server_accept: string &optional; + }; + + ## Event that can be handled to access the WebSocket record as it is + ## sent on to the logging framework. + global log_websocket: event(rec: Info); + + ## Log policy hook. + global log_policy: Log::PolicyHook; + + ## Experimental: Hook to intercept WebSocket analyzer configuration. + ## + ## Breaking from this hook disables the WebSocket analyzer immediately. + ## To modify the configuration of the analyzer, use the + ## :zeek:see:`WebSocket::AnalyzerConfig` type. + ## + ## While this API allows quite some flexibility currently, should be + ## considered experimental and may change in the future with or + ## without a deprecation phase. + ## + ## c: The connection + ## + ## aid: The analyzer ID for the WebSocket analyzer. + ## + ## config: The configuration record, also containing information + ## about the subprotocol and extensions. + global configure_analyzer: hook(c: connection, aid: count, config: AnalyzerConfig); +} + +redef record connection += { + websocket: Info &optional; +}; + +function set_websocket(c: connection) + { + c$websocket = Info( + $ts=network_time(), + $uid=c$uid, + $id=c$id, + ); + } + +function expected_accept_for(key: string): string + { + return encode_base64(hexstr_to_bytestring(sha1_hash(key + HANDSHAKE_GUID))); + } + +event http_header(c: connection, is_orig: bool, name: string, value: string) + { + if ( ! starts_with(name, "SEC-WEBSOCKET-") ) + return; + + if ( ! c?$websocket ) + set_websocket(c); + + local ws = c$websocket; + + if ( is_orig ) + { + if ( name == "SEC-WEBSOCKET-PROTOCOL" ) + { + if ( ! ws?$client_protocols ) + ws$client_protocols = vector(); + + ws$client_protocols += split_string(value, / *, */); + } + + else if ( name == "SEC-WEBSOCKET-EXTENSIONS" ) + { + if ( ! ws?$client_extensions ) + ws$client_extensions = vector(); + + ws$client_extensions += split_string(value, / *, */); + } + else if ( name == "SEC-WEBSOCKET-KEY" ) + { + if ( ws?$client_key ) + Reporter::conn_weird("websocket_multiple_key_headers", c, "", "WebSocket"); + + ws$client_key = value; + } + } + else + { + if ( name == "SEC-WEBSOCKET-PROTOCOL" ) + { + if ( ws?$subprotocol ) + Reporter::conn_weird("websocket_multiple_protocol_headers", c, "", "WebSocket"); + + ws$subprotocol = value; + } + else if ( name == "SEC-WEBSOCKET-EXTENSIONS" ) + { + if ( ! ws?$server_extensions ) + ws$server_extensions = vector(); + + ws$server_extensions += split_string(value, / *, */); + } + else if ( name == "SEC-WEBSOCKET-ACCEPT" ) + { + if ( ws?$server_accept ) + Reporter::conn_weird("websocket_multiple_accept_headers", c, "", "WebSocket"); + + ws$server_accept = value; + } + } + } + +event http_request(c: connection, method: string, original_URI: string, + unescaped_URI: string, version: string) + { + # If we see a http_request and have websocket state, wipe it as + # we should've seen a websocket_established even on success and + # likely no more http events. + if ( ! c?$websocket ) + delete c$websocket; + } + +event websocket_established(c: connection, aid: count) &priority=5 + { + if ( ! c?$websocket ) + { + # This means we never saw a Sec-WebSocket-* header, weird. + Reporter::conn_weird("websocket_established_unexpected", c, "", "WebSocket"); + set_websocket(c); + } + + local ws = c$websocket; + + if ( ! ws?$client_key ) + Reporter::conn_weird("websocket_missing_key_header", c, "", "WebSocket"); + + if ( ! ws?$server_accept ) + Reporter::conn_weird("websocket_missing_accept_header", c, "", "WebSocket"); + + # Verify the Sec-WebSocket-Accept header's value given the Sec-WebSocket-Key header's value. + if ( ws?$client_key && ws?$server_accept ) + { + local expected_accept = expected_accept_for(ws$client_key); + if ( ws$server_accept != expected_accept ) + Reporter::conn_weird("websocket_wrong_accept_header", c, + fmt("expected=%s, found=%s", expected_accept, ws$server_accept), + "WebSocket"); + } + + # Replicate some information from the HTTP.log + if ( c?$http ) + { + if ( c$http?$host ) + ws$host = c$http$host; + + if ( c$http?$uri ) + ws$uri = c$http$uri; + + if ( c$http?$user_agent ) + ws$user_agent = c$http$user_agent; + } + } + +event websocket_established(c: connection, aid: count) &priority=-5 + { + local ws = c$websocket; + + local config = AnalyzerConfig(); + if ( ws?$subprotocol ) + config$subprotocol = ws$subprotocol; + + if ( ws?$server_extensions ) + config$server_extensions = ws$server_extensions; + + # Give other scripts a chance to modify the analyzer configuration. + # + # Breaking from this hook disables the new WebSocket analyzer + # completely instead of configuring it. + if ( hook WebSocket::configure_analyzer(c, aid, config) ) + WebSocket::__configure_analyzer(c, aid, config); + else + disable_analyzer(c$id, aid); + + ws$ts = network_time(); + Log::write(LOG, ws); + } + +event zeek_init() + { + Log::create_stream(LOG, [$columns=Info, $ev=log_websocket, $path="websocket", $policy=log_policy]); + } diff --git a/src/analyzer/protocol/CMakeLists.txt b/src/analyzer/protocol/CMakeLists.txt index 79e5b6cea0..896c53b4e6 100644 --- a/src/analyzer/protocol/CMakeLists.txt +++ b/src/analyzer/protocol/CMakeLists.txt @@ -42,5 +42,6 @@ add_subdirectory(ssh) add_subdirectory(ssl) add_subdirectory(syslog) add_subdirectory(tcp) +add_subdirectory(websocket) add_subdirectory(xmpp) add_subdirectory(zip) diff --git a/src/analyzer/protocol/http/HTTP.cc b/src/analyzer/protocol/http/HTTP.cc index 4a4eaca9d0..e9c0ff4a2d 100644 --- a/src/analyzer/protocol/http/HTTP.cc +++ b/src/analyzer/protocol/http/HTTP.cc @@ -12,6 +12,7 @@ #include "zeek/Event.h" #include "zeek/NetVar.h" +#include "zeek/analyzer/Manager.h" #include "zeek/analyzer/protocol/http/events.bif.h" #include "zeek/analyzer/protocol/mime/MIME.h" #include "zeek/file_analysis/Manager.h" @@ -775,12 +776,9 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) { if ( TCP() && TCP()->IsPartial() ) return; - if ( upgraded ) - return; - - if ( pia ) { + if ( upgraded || pia ) { // There will be a PIA instance if this connection has been identified - // as a connect proxy. + // as a connect proxy, or a child analyzer if there was an upgrade. ForwardStream(len, data, is_orig); return; } @@ -951,6 +949,19 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig) { pia->FirstPacket(true, nullptr); pia->FirstPacket(false, nullptr); + int remaining_in_content_line = content_line_resp->GetDeliverStreamRemainingLength(); + if ( remaining_in_content_line > 0 ) { + // If there's immediately data following the empty line + // of a successful CONNECT reply, that's at least curious. + // Further, switch the responder's ContentLine analyzer + // into plain delivery mode so anything left is sent to + // PIA unaltered. + const char* addl = zeek::util::fmt("%d", remaining_in_content_line); + Weird("protocol_data_with_HTTP_CONNECT_reply", addl); + content_line_resp->SetPlainDelivery(remaining_in_content_line); + } + + // This connection has transitioned to no longer // being http and the content line support analyzers // need to be removed. @@ -1311,15 +1322,8 @@ void HTTP_Analyzer::ReplyMade(bool interrupted, const char* msg) { reply_reason_phrase = nullptr; // unanswered requests = 1 because there is no pop after 101. - if ( reply_code == 101 && unanswered_requests.size() == 1 && upgrade_connection && upgrade_protocol.size() ) { - // Upgraded connection that switches immediately - e.g. websocket. - upgraded = true; - RemoveSupportAnalyzer(content_line_orig); - RemoveSupportAnalyzer(content_line_resp); - - if ( http_connection_upgrade ) - EnqueueConnEvent(http_connection_upgrade, ConnVal(), make_intrusive(upgrade_protocol)); - } + if ( reply_code == 101 && unanswered_requests.size() == 1 && upgrade_connection && upgrade_protocol.size() ) + HTTP_Upgrade(); reply_code = 0; upgrade_connection = false; @@ -1331,6 +1335,80 @@ void HTTP_Analyzer::ReplyMade(bool interrupted, const char* msg) { reply_state = EXPECT_REPLY_LINE; } +void HTTP_Analyzer::HTTP_Upgrade() { + // Upgraded connection that switches immediately - e.g. websocket. + + int remaining_in_content_line = content_line_resp->GetDeliverStreamRemainingLength(); + + if ( remaining_in_content_line > 0 ) { + // We've seen a complete HTTP response for an upgrade request and there's + // more data buffered in the ContentLine analyzer. This means the next + // protocol's data is in the same packet as the HTTP reply. Log a weird + // as this seems not very likely to happen in the wild. + const char* addl = zeek::util::fmt("%d", remaining_in_content_line); + Weird("protocol_data_with_HTTP_upgrade_reply", addl); + + // Switch the ContentLine analyzer to deliver anything remaining in + // plain mode so it can be forwarded to the upgrade analyzer. + content_line_resp->SetPlainDelivery(remaining_in_content_line); + } + + // Lookup an analyzer tag in the HTTP::upgrade_analyzer table. + static const auto& upgrade_analyzers = id::find_val("HTTP::upgrade_analyzers"); + + auto upgrade_protocol_val = make_intrusive(upgrade_protocol); + auto v = upgrade_analyzers->Find(upgrade_protocol_val); + if ( ! v ) { + // If not found, try the all lower version, too. + auto lower_upgrade_protocol = util::strtolower(upgrade_protocol); + upgrade_protocol_val = make_intrusive(lower_upgrade_protocol); + v = upgrade_analyzers->Find(upgrade_protocol_val); + } + + if ( v ) { + auto analyzer_tag_val = cast_intrusive(v); + DBG_LOG(DBG_ANALYZER, "Found %s in HTTP::upgrade_analyzers for %s", + analyzer_tag_val->GetType()->Lookup(analyzer_tag_val->AsEnum()), + upgrade_protocol_val->CheckString()); + auto analyzer_tag = analyzer_mgr->GetComponentTag(analyzer_tag_val.get()); + auto* analyzer = analyzer_mgr->InstantiateAnalyzer(analyzer_tag, Conn()); + if ( analyzer ) { + AddChildAnalyzer(analyzer); + + // The analyzer's Init() may have scheduled an event for analyzer configuration. + // Drain the event queue now to process it. This further ensures that other + // events already in the event queue (http_reply, http_header, ...) are drained + // as well and accessible when the configuration runs. + // + // Don't just copy this code into a new analyzer, there might be better and more + // more general approaches. + // + // Alternative proposal from Robin: + // + // Collect all HTTP headers (pattern/names configurable by script land) + // and forward the collected headers to the analyzer via a custom + // configuration method or some in-band channel. + event_mgr.Drain(); + } + } + else { + DBG_LOG(DBG_ANALYZER, "No mapping for %s in HTTP::upgrade_analyzers, using PIA instead", + upgrade_protocol.c_str()); + pia = new analyzer::pia::PIA_TCP(Conn()); + if ( AddChildAnalyzer(pia) ) { + pia->FirstPacket(true, nullptr); + pia->FirstPacket(false, nullptr); + } + } + + upgraded = true; + RemoveSupportAnalyzer(content_line_orig); + RemoveSupportAnalyzer(content_line_resp); + + if ( http_connection_upgrade ) + EnqueueConnEvent(http_connection_upgrade, ConnVal(), make_intrusive(upgrade_protocol)); +} + void HTTP_Analyzer::RequestClash(Val* /* clash_val */) { Weird("multiple_HTTP_request_elements"); diff --git a/src/analyzer/protocol/http/HTTP.h b/src/analyzer/protocol/http/HTTP.h index 016ba4f2e1..62f519201d 100644 --- a/src/analyzer/protocol/http/HTTP.h +++ b/src/analyzer/protocol/http/HTTP.h @@ -220,6 +220,7 @@ protected: void HTTP_Request(); void HTTP_Reply(); + void HTTP_Upgrade(); void RequestMade(bool interrupted, const char* msg); void ReplyMade(bool interrupted, const char* msg); diff --git a/src/analyzer/protocol/tcp/ContentLine.cc b/src/analyzer/protocol/tcp/ContentLine.cc index 1bbc730db8..5544338434 100644 --- a/src/analyzer/protocol/tcp/ContentLine.cc +++ b/src/analyzer/protocol/tcp/ContentLine.cc @@ -30,6 +30,7 @@ void ContentLine_Analyzer::InitState() { delivery_length = -1; is_plain = false; suppress_weirds = false; + deliver_stream_remaining_length = 0; InitBuffer(0); } @@ -149,6 +150,7 @@ void ContentLine_Analyzer::DoDeliver(int len, const u_char* data) { plain_delivery_length -= deliver_plain; is_plain = true; + deliver_stream_remaining_length = len - deliver_plain; ForwardStream(deliver_plain, data, IsOrig()); is_plain = false; @@ -207,6 +209,7 @@ int ContentLine_Analyzer::DoDeliverOnce(int len, const u_char* data) { int seq_len = data + 1 - data_start; \ seq_delivered_in_lines = seq + seq_len; \ last_char = c; \ + deliver_stream_remaining_length = len - 1; \ ForwardStream(offset, buf, IsOrig()); \ offset = 0; \ return seq_len; \ diff --git a/src/analyzer/protocol/tcp/ContentLine.h b/src/analyzer/protocol/tcp/ContentLine.h index 5572e76535..4d473a5f84 100644 --- a/src/analyzer/protocol/tcp/ContentLine.h +++ b/src/analyzer/protocol/tcp/ContentLine.h @@ -47,6 +47,11 @@ public: int64_t GetPlainDeliveryLength() const { return plain_delivery_length; } bool IsPlainDelivery() { return is_plain; } + // Helper to check how many bytes are still in-flight for the + // current DeliverStream() invocation. This can be called + // by the parent during its DeliverStream() invocation. + int GetDeliverStreamRemainingLength() const { return deliver_stream_remaining_length; } + // Skip bytes after this line. // Can be used to skip HTTP data for performance considerations. void SkipBytesAfterThisLine(int64_t length); @@ -107,6 +112,8 @@ protected: // Whether to skip partial conns. bool skip_partial; + + int deliver_stream_remaining_length; }; } // namespace zeek::analyzer::tcp diff --git a/src/analyzer/protocol/websocket/CMakeLists.txt b/src/analyzer/protocol/websocket/CMakeLists.txt new file mode 100644 index 0000000000..d522c58821 --- /dev/null +++ b/src/analyzer/protocol/websocket/CMakeLists.txt @@ -0,0 +1,15 @@ +zeek_add_plugin( + Zeek + WebSocket + SOURCES + WebSocket.cc + Plugin.cc + BIFS + consts.bif + events.bif + functions.bif + types.bif + PAC + websocket.pac + websocket-analyzer.pac + websocket-protocol.pac) diff --git a/src/analyzer/protocol/websocket/Plugin.cc b/src/analyzer/protocol/websocket/Plugin.cc new file mode 100644 index 0000000000..c3ef84765a --- /dev/null +++ b/src/analyzer/protocol/websocket/Plugin.cc @@ -0,0 +1,24 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#include "zeek/plugin/Plugin.h" + +#include "zeek/analyzer/Component.h" + +#include "analyzer/protocol/websocket/WebSocket.h" + +namespace zeek::plugin::detail::Zeek_WebSocket { + +class Plugin : public zeek::plugin::Plugin { +public: + zeek::plugin::Configuration Configure() override { + AddComponent( + new zeek::analyzer::Component("WebSocket", zeek::analyzer::websocket::WebSocket_Analyzer::Instantiate)); + + zeek::plugin::Configuration config; + config.name = "Zeek::WebSocket"; + config.description = "WebSocket analyzer"; + return config; + } +} plugin; + +} // namespace zeek::plugin::detail::Zeek_WebSocket diff --git a/src/analyzer/protocol/websocket/WebSocket.cc b/src/analyzer/protocol/websocket/WebSocket.cc new file mode 100644 index 0000000000..de098e472c --- /dev/null +++ b/src/analyzer/protocol/websocket/WebSocket.cc @@ -0,0 +1,103 @@ +// See the file in the main distribution directory for copyright. + +#include "zeek/analyzer/protocol/websocket/WebSocket.h" + +#include + +#include "zeek/analyzer/Manager.h" +#include "zeek/analyzer/protocol/pia/PIA.h" +#include "zeek/analyzer/protocol/websocket/events.bif.h" + +namespace zeek::analyzer::websocket { + +WebSocket_Analyzer::WebSocket_Analyzer(Connection* conn) : analyzer::tcp::TCP_ApplicationAnalyzer("WebSocket", conn) { + // TODO: Consider approaches dispatching to optionally use a + // Spicy analyzer here instead of the BinPac interpreter. + // + // E.g. we could instantiate a SPICY_WEBSOCKET analyzer and pass it the necessary + // information and call DeliverStream() directly on it. + interp = std::make_unique(this); +} + +void WebSocket_Analyzer::Init() { + tcp::TCP_ApplicationAnalyzer::Init(); + + // This event gives scriptland a chance to log and configure the analyzer. + // The WebSocket analyzer ships with a handler that calls back into + // Configure(), via WebSocket::__configure_analyzer(). + zeek::BifEvent::enqueue_websocket_established(this, Conn(), GetID()); +} + +bool WebSocket_Analyzer::Configure(zeek::RecordValPtr config) { + // TODO: Check extensions and modify parsing if needed, e.g. WebSocket frame + // compression extension: https://www.rfc-editor.org/rfc/rfc7692.html + // + // interp->SetExtensions(...) + // + // TODO: The Sec-WebSocket-Protocol header might provide some information + // that we could leverage to instantiate a more specific analyzer. + // + // For now, we just attach a PIA analyzer as child analyzer. + + static const auto& config_type = id::find_type("WebSocket::AnalyzerConfig"); + static int analyzer_idx = config_type->FieldOffset("analyzer"); + static int use_dpd_idx = config_type->FieldOffset("use_dpd"); + + if ( config->HasField(analyzer_idx) ) { + const auto& analyzer_tag_val = config->GetField(analyzer_idx); + auto analyzer_tag = analyzer_mgr->GetComponentTag(analyzer_tag_val.get()); + + if ( analyzer_tag == zeek::Tag() ) { + reporter->InternalWarning("no component tag for enum '%s'", + analyzer_tag_val->GetType()->Lookup(analyzer_tag_val->AsEnum())); + return false; + } + + DBG_LOG(DBG_ANALYZER, "%s Configure() using analyzer %s", fmt_analyzer(this).c_str(), + analyzer_tag_val->GetType()->Lookup(analyzer_tag_val->AsEnum())); + + auto* analyzer = analyzer_mgr->InstantiateAnalyzer(analyzer_tag, Conn()); + if ( ! analyzer ) + return false; + + return AddChildAnalyzer(analyzer); + } + else if ( config->GetField(use_dpd_idx)->AsBool() ) { + DBG_LOG(DBG_ANALYZER, "%s Configure() enables DPD via PIA_TCP", fmt_analyzer(this).c_str()); + + auto* pia = new analyzer::pia::PIA_TCP(Conn()); + if ( AddChildAnalyzer(pia) ) { + pia->FirstPacket(true, nullptr); + pia->FirstPacket(false, nullptr); + return true; + } + + return false; + } + + // Neither analyzer nor dpd was enabled, success. + return true; +} + + +void WebSocket_Analyzer::DeliverStream(int len, const u_char* data, bool orig) { + analyzer::tcp::TCP_ApplicationAnalyzer::DeliverStream(len, data, orig); + if ( had_gap ) { + DBG_LOG(DBG_ANALYZER, "Skipping data after gap len=%d orig=%d", len, orig); + return; + } + + try { + interp->NewData(orig, data, data + len); + } catch ( const binpac::Exception& e ) { + AnalyzerViolation(e.c_msg(), reinterpret_cast(data), len); + } +} + +void WebSocket_Analyzer::Undelivered(uint64_t seq, int len, bool orig) { + analyzer::tcp::TCP_ApplicationAnalyzer::Undelivered(seq, len, orig); + interp->NewGap(orig, len); + had_gap = true; +} + +} // namespace zeek::analyzer::websocket diff --git a/src/analyzer/protocol/websocket/WebSocket.h b/src/analyzer/protocol/websocket/WebSocket.h new file mode 100644 index 0000000000..394eab194e --- /dev/null +++ b/src/analyzer/protocol/websocket/WebSocket.h @@ -0,0 +1,38 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#pragma once + +#include + +#include "zeek/analyzer/protocol/tcp/TCP.h" +#include "zeek/analyzer/protocol/websocket/websocket_pac.h" + +namespace zeek::analyzer::websocket { + +/** + * A WebSocket analyzer to be used directly on top of HTTP. + */ +class WebSocket_Analyzer : public analyzer::tcp::TCP_ApplicationAnalyzer { +public: + WebSocket_Analyzer(zeek::Connection* conn); + ~WebSocket_Analyzer() = default; + + /** + * Allows script land to configure the WebSocket analyzer before analysis. + * + * @param config Zeek value of type WebSocket::AnalyzerConfig + */ + bool Configure(zeek::RecordValPtr config); + + void Init() override; + void DeliverStream(int len, const u_char* data, bool orig) override; + void Undelivered(uint64_t seq, int len, bool orig) override; + + static zeek::analyzer::Analyzer* Instantiate(Connection* conn) { return new WebSocket_Analyzer(conn); } + +private: + std::unique_ptr interp; + bool had_gap = false; +}; + +} // namespace zeek::analyzer::websocket diff --git a/src/analyzer/protocol/websocket/consts.bif b/src/analyzer/protocol/websocket/consts.bif new file mode 100644 index 0000000000..164181474c --- /dev/null +++ b/src/analyzer/protocol/websocket/consts.bif @@ -0,0 +1 @@ +const WebSocket::payload_chunk_size: count; diff --git a/src/analyzer/protocol/websocket/events.bif b/src/analyzer/protocol/websocket/events.bif new file mode 100644 index 0000000000..04ea73484f --- /dev/null +++ b/src/analyzer/protocol/websocket/events.bif @@ -0,0 +1,65 @@ +## Generated when a WebSocket handshake completed. +## +## c: The WebSocket connection. +## +## aid: The analyzer identifier of the WebSocket analyzer. +## +## .. zeek:see:: WebSocket::__configure_analyzer WebSocket::configure_analyzer +event websocket_established%(c: connection, aid: count%); + +## Generated for every WebSocket frame. +## +## c: The WebSocket connection. +## +## is_orig: True if the frame is from the originator, else false. +## +## fin: True if the fin bit is set, else false. +## +## rsv: The value of the RSV1, RSV2 and RSV3 bits. +## +## opcode: The frame's opcode. +## +## payload_len: The frame's payload length. +## +event websocket_frame%(c: connection, is_orig: bool, fin: bool, rsv: count, opcode: count, payload_len: count%); + +## Generated for every chunk of WebSocket frame payload data. +## +## Do not use it to extract data from a WebSocket connection unless for testing +## or experimentation. Consider implementing a proper analyzer instead. +## +## c: The WebSocket connection. +## +## is_orig: True if the frame is from the originator, else false. +## +## data: One data chunk of frame payload. The length of is at most +## :zeek:see:`WebSocket::payload_chunk_size` bytes. A frame with +## a longer payload will result in multiple events events. +## +## .. zeek:see:: WebSocket::payload_chunk_size +event websocket_frame_data%(c: connection, is_orig: bool, data: string%); + + +## Generated for every completed WebSocket message. +## +## c: The WebSocket connection. +## +## is_orig: True if the frame is from the originator, else false. +## +## opcode: The first frame's opcode. +event websocket_message%(c: connection, is_orig: bool, opcode: count%); + +## Generated for WebSocket Close frames. +## +## c: The WebSocket connection. +## +## is_orig: True if the frame is from the originator, else false. +## +## status: If the CloseFrame had no payload, this is 0, otherwise the value +## of the first two bytes in the frame's payload. +## +## reason: Remaining payload after *status*. This is capped at +## 2 bytes less than :zeek:see:`WebSocket::payload_chunk_size`. +## +## .. zeek:see:: WebSocket::payload_chunk_size +event websocket_close%(c: connection, is_orig: bool, status: count, reason: string%); diff --git a/src/analyzer/protocol/websocket/functions.bif b/src/analyzer/protocol/websocket/functions.bif new file mode 100644 index 0000000000..dfa33f631d --- /dev/null +++ b/src/analyzer/protocol/websocket/functions.bif @@ -0,0 +1,46 @@ +%%{ +#include "zeek/analyzer/protocol/websocket/WebSocket.h" +%%} + +module WebSocket; + +## Configure the WebSocket analyzer. +## +## Called during :zeek:see:`websocket_established` to configure +## the WebSocket analyzer given the selected protocol and extension +## as chosen by the server. +## +## c: The WebSocket connection. +# +## aid: The identifier for the WebSocket analyzer as provided to :zeek:see:`websocket_established`. +## +## server_protocol: The protocol as found in the server's Sec-WebSocket-Protocol HTTP header, or empty. +## +## server_extensions: The extension as selected by the server via the Sec-WebSocket-Extensions HTTP Header. +## +## .. zeek:see:: websocket_established +function __configure_analyzer%(c: connection, aid: count, config: WebSocket::AnalyzerConfig%): bool + %{ + auto* analyzer = c->FindAnalyzer(aid); + auto* ws_analyzer = dynamic_cast(analyzer); + if ( ! ws_analyzer ) + { + reporter->Warning("WebSocket analyzer to configure not found"); + return zeek::val_mgr->False(); + } + + static const auto& config_type = zeek::id::find_type("WebSocket::AnalyzerConfig"); + + if ( config->GetType() != config_type ) + { + reporter->Warning("config has wrong type %s, expected %s", + config->GetType()->GetName().c_str(), + config_type->GetName().c_str()); + return zeek::val_mgr->False(); + } + + if ( ! ws_analyzer->Configure({zeek::NewRef{}, config->AsRecordVal()}) ) + return zeek::val_mgr->False(); + + return zeek::val_mgr->True(); + %} diff --git a/src/analyzer/protocol/websocket/types.bif b/src/analyzer/protocol/websocket/types.bif new file mode 100644 index 0000000000..90378cef1b --- /dev/null +++ b/src/analyzer/protocol/websocket/types.bif @@ -0,0 +1,4 @@ +module WebSocket; + +# A configuration record used for the WebSocket analyzer. +type AnalyzerConfig: record; diff --git a/src/analyzer/protocol/websocket/websocket-analyzer.pac b/src/analyzer/protocol/websocket/websocket-analyzer.pac new file mode 100644 index 0000000000..fc60538161 --- /dev/null +++ b/src/analyzer/protocol/websocket/websocket-analyzer.pac @@ -0,0 +1,111 @@ +# See the file "COPYING" in the main distribution directory for copyright. +# +# The WebSocket analyzer. +# + +refine flow WebSocket_Flow += { + + function process_message(msg: WebSocket_Message): bool + %{ + connection()->zeek_analyzer()->AnalyzerConfirmation(); + + if ( websocket_message ) + { + zeek::BifEvent::enqueue_websocket_message(connection()->zeek_analyzer(), + connection()->zeek_analyzer()->Conn(), + is_orig(), + ${msg.opcode}); + } + + return true; + %} + + function process_header(hdr: WebSocket_FrameHeader): bool + %{ + if ( websocket_frame ) + { + zeek::BifEvent::enqueue_websocket_frame(connection()->zeek_analyzer(), + connection()->zeek_analyzer()->Conn(), + is_orig(), + ${hdr.fin}, + ${hdr.reserved}, + ${hdr.opcode}, + ${hdr.payload_len}); + } + + return true; + %} + + function process_payload_close(close: WebSocket_FramePayloadClose): bool + %{ + if ( websocket_close ) + { + const auto& reason = ${close.reason}; + auto reason_val = zeek::make_intrusive(reason.length(), + reinterpret_cast(reason.data())); + zeek::BifEvent::enqueue_websocket_close(connection()->zeek_analyzer(), + connection()->zeek_analyzer()->Conn(), + is_orig(), + ${close.status}, + reason_val); + } + + return true; + %} + + function process_empty_close(hdr: WebSocket_FrameHeader): bool + %{ + if ( websocket_close ) + { + zeek::BifEvent::enqueue_websocket_close(connection()->zeek_analyzer(), + connection()->zeek_analyzer()->Conn(), + is_orig(), + 0, /* use placeholder status */ + zeek::val_mgr->EmptyString()); + } + + return true; + %} + + function process_payload_chunk(chunk: WebSocket_FramePayloadChunk): bool + %{ + auto& data = ${chunk.data}; + + // In-place unmasking if frame payload is masked. + if ( has_mask_ ) + { + auto *d = data.data(); + for ( int i = 0; i < data.length(); i++ ) + d[i] = d[i] ^ masking_key_[masking_key_idx_++ % masking_key_.size()]; + } + + if ( websocket_frame_data ) + { + auto data_val = zeek::make_intrusive(data.length(), reinterpret_cast(data.data())); + zeek::BifEvent::enqueue_websocket_frame_data(connection()->zeek_analyzer(), + connection()->zeek_analyzer()->Conn(), + is_orig(), + data_val); + } + + // Forward text and binary data to downstream analyzers. + if ( ${chunk.hdr.opcode} == OPCODE_TEXT|| ${chunk.hdr.opcode} == OPCODE_BINARY) + connection()->zeek_analyzer()->ForwardStream(data.length(), + data.data(), + is_orig()); + + return true; + %} +}; + +refine typeattr WebSocket_Message += &let { + proc_message = $context.flow.process_message(this); +}; + +refine typeattr WebSocket_FrameHeader += &let { + proc_header = $context.flow.process_header(this); +}; + +refine typeattr WebSocket_FramePayloadClose += &let { + proc_payload_close = $context.flow.process_payload_close(this); +}; diff --git a/src/analyzer/protocol/websocket/websocket-protocol.pac b/src/analyzer/protocol/websocket/websocket-protocol.pac new file mode 100644 index 0000000000..1abd317859 --- /dev/null +++ b/src/analyzer/protocol/websocket/websocket-protocol.pac @@ -0,0 +1,142 @@ +# See the file "COPYING" in the main distribution directory for copyright. +# +# The WebSocket protocol. +# +# https://datatracker.ietf.org/doc/html/rfc6455 + +enum Opcodes { + OPCODE_CONTINUATION = 0x00, + OPCODE_TEXT = 0x01, + OPCODE_BINARY = 0x02, + OPCODE_CLOSE = 0x08, + OPCODE_PING = 0x09, + OPCODE_PONG = 0x0a, +} + +type WebSocket_FrameHeader(first_frame: bool) = record { + first2: uint16 &enforce((first_frame && opcode != 0) || (!first_frame && opcode == 0)); + maybe_more_len: case payload_len1 of { + 126 -> payload_len2: uint16; + 127 -> payload_len8: uint64; + default -> short_len: empty; + }; + + maybe_masking_key: case has_mask of { + true -> masking_key: bytestring &length=4; + false -> no_masking_key: empty; + }; +} &let { + fin: bool = (first2 & 0x8000) ? true : false; + reserved: uint8 = ((first2 & 0x7000) >> 12); + opcode: uint8 = (first2 & 0x0f00) >> 8; + payload_len1: uint8 = (first2 & 0x007f); + has_mask: bool = (first2 & 0x0080) ? true : false; + + # Derived fields. + rest_header_len: uint64 = (has_mask ? 4 : 0) + (payload_len1 < 126 ? 0 : (payload_len1 == 126 ? 2 : 8)); + payload_len: uint64 = payload_len1 < 126 ? payload_len1 : (payload_len1 == 126 ? payload_len2 : payload_len8); + + new_frame_payload = $context.flow.new_frame_payload(this); +} &length=2+rest_header_len; + +type WebSocket_FramePayloadClose = record { + status: uint16; + reason: bytestring &restofdata; +} &byteorder=bigendian; + +type WebSocket_FramePayloadChunk(len: uint64, hdr: WebSocket_FrameHeader) = record { + data: bytestring &restofdata; +} &let { + consumed_payload = $context.flow.consumed_chunk_len(len); + payload_chunk = $context.flow.process_payload_chunk(this); # unmasks if needed + close_payload: WebSocket_FramePayloadClose withinput data &length=len &if(hdr.opcode == OPCODE_CLOSE); +} &length=len; + +type WebSocket_Frame(first_frame: bool, msg: WebSocket_Message) = record { + hdr: WebSocket_FrameHeader(first_frame); + + # This is implementing frame payload chunking so that we do not + # attempt to buffer huge frames and forward data to downstream + # analyzers in chunks. + # + # I tried &chunked and it didn't do anything very useful. + chunks: WebSocket_FramePayloadChunk($context.flow.next_chunk_len(), hdr)[] + &until($context.flow.remaining_frame_payload_len() == 0) + &transient; +} &let { + # If we find a close frame without payload, raise the event here + # as the close won't have been parsed via chunks. + empty_close = $context.flow.process_empty_close(hdr) &if(hdr.opcode == OPCODE_CLOSE) && hdr.payload_len == 0; +}; + +type WebSocket_Message = record { + first_frame: WebSocket_Frame(true, this); + optional_more_frames: case first_frame.hdr.fin of { + true -> no_more_frames: empty; + false -> more_frames: WebSocket_Frame(false, this)[] &until($element.hdr.fin); + }; +} &let { + opcode = first_frame.hdr.opcode; +} &byteorder=bigendian; + +flow WebSocket_Flow(is_orig: bool) { + flowunit = WebSocket_Message withcontext(connection, this); + + %member{ + bool has_mask_; + uint64_t masking_key_idx_; + uint64_t frame_payload_len_; + std::array masking_key_; + %} + + %init{ + has_mask_ = false; + masking_key_idx_ = 0; + frame_payload_len_ = 0; + %} + + function new_frame_payload(hdr: WebSocket_FrameHeader): uint64 + %{ + if ( frame_payload_len_ > 0 ) + connection()->zeek_analyzer()->Weird("websocket_frame_not_consumed"); + + frame_payload_len_ = ${hdr.payload_len}; + has_mask_ = ${hdr.has_mask}; + masking_key_idx_ = 0; + if ( has_mask_ ) { + assert(${hdr.masking_key}.length() == static_cast(masking_key_.size())); + memcpy(masking_key_.data(), ${hdr.masking_key}.data(), masking_key_.size()); + } + return frame_payload_len_; + %} + + function remaining_frame_payload_len(): uint64 + %{ + return frame_payload_len_; + %} + + function consumed_chunk_len(len: uint64): uint64 + %{ + if ( len > frame_payload_len_ ) { + connection()->zeek_analyzer()->Weird("websocket_frame_consuming_too_much"); + len = frame_payload_len_; + } + + frame_payload_len_ -= len; + return len; + %} + + function next_chunk_len(): uint64 + %{ + uint64_t len = frame_payload_len_; + + // It would be somewhat nicer if we could just consume + // anything still left to consume from the current packet, + // but couldn't figure out if that information can be pulled + // flow buffer. + if ( len > zeek::BifConst::WebSocket::payload_chunk_size ) + len = zeek::BifConst::WebSocket::payload_chunk_size; + + return len; + %} +}; diff --git a/src/analyzer/protocol/websocket/websocket.pac b/src/analyzer/protocol/websocket/websocket.pac new file mode 100644 index 0000000000..4e710e2712 --- /dev/null +++ b/src/analyzer/protocol/websocket/websocket.pac @@ -0,0 +1,24 @@ +# See the file "COPYING" in the main distribution directory for copyright. + +%include binpac.pac +%include zeek.pac + +%extern{ +#include + +#include "zeek/analyzer/protocol/websocket/consts.bif.h" +#include "zeek/analyzer/protocol/websocket/events.bif.h" +%} + +analyzer WebSocket withcontext { + connection: WebSocket_Conn; + flow: WebSocket_Flow; +}; + +connection WebSocket_Conn(zeek_analyzer: ZeekAnalyzer) { + upflow = WebSocket_Flow(true); + downflow = WebSocket_Flow(false); +}; + +%include websocket-protocol.pac +%include websocket-analyzer.pac diff --git a/src/fuzzers/CMakeLists.txt b/src/fuzzers/CMakeLists.txt index ef9012b9c1..41a46dc64a 100644 --- a/src/fuzzers/CMakeLists.txt +++ b/src/fuzzers/CMakeLists.txt @@ -94,6 +94,7 @@ target_link_libraries(zeek_fuzzer_shared PUBLIC ${zeek_fuzzer_shared_deps} add_fuzz_target(packet) add_fuzz_target(dns) +add_fuzz_target(websocket) add_generic_analyzer_fuzz_target(ftp) add_generic_analyzer_fuzz_target(http) diff --git a/src/fuzzers/corpora/websocket-corpus.zip b/src/fuzzers/corpora/websocket-corpus.zip new file mode 100644 index 0000000000..d2f3b23363 Binary files /dev/null and b/src/fuzzers/corpora/websocket-corpus.zip differ diff --git a/src/fuzzers/websocket-fuzzer.cc b/src/fuzzers/websocket-fuzzer.cc new file mode 100644 index 0000000000..1d1b47d39e --- /dev/null +++ b/src/fuzzers/websocket-fuzzer.cc @@ -0,0 +1,107 @@ +#include + +#include "zeek/Conn.h" +#include "zeek/ID.h" +#include "zeek/RunState.h" +#include "zeek/analyzer/Analyzer.h" +#include "zeek/analyzer/Manager.h" +#include "zeek/analyzer/protocol/pia/PIA.h" +#include "zeek/analyzer/protocol/tcp/TCP.h" +#include "zeek/analyzer/protocol/websocket/WebSocket.h" +#include "zeek/fuzzers/FuzzBuffer.h" +#include "zeek/fuzzers/fuzzer-setup.h" +#include "zeek/packet_analysis/protocol/tcp/TCPSessionAdapter.h" +#include "zeek/session/Manager.h" + +static constexpr auto FUZZ_ANALYZER_NAME = "websocket"; + +static zeek::Connection* add_connection() { + static constexpr double network_time_start = 1439471031; + zeek::run_state::detail::update_network_time(network_time_start); + + zeek::Packet p; + zeek::ConnTuple conn_id; + conn_id.src_addr = zeek::IPAddr("1.2.3.4"); + conn_id.dst_addr = zeek::IPAddr("5.6.7.8"); + conn_id.src_port = htons(23132); + conn_id.dst_port = htons(80); + conn_id.is_one_way = false; + conn_id.proto = TRANSPORT_TCP; + zeek::detail::ConnKey key(conn_id); + zeek::Connection* conn = new zeek::Connection(key, network_time_start, &conn_id, 1, &p); + conn->SetTransport(TRANSPORT_TCP); + zeek::session_mgr->Insert(conn); + return conn; +} + +static std::tuple add_analyzer( + zeek::Connection* conn, const zeek::Tag& analyzer_tag) { + auto* tcp = new zeek::packet_analysis::TCP::TCPSessionAdapter(conn); + auto* pia = new zeek::analyzer::pia::PIA_TCP(conn); + auto a = zeek::analyzer_mgr->InstantiateAnalyzer(analyzer_tag, conn); + tcp->AddChildAnalyzer(a); + tcp->AddChildAnalyzer(pia->AsAnalyzer()); + conn->SetSessionAdapter(tcp, pia); + + return {a, tcp}; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + static auto analyzer_tag = zeek::analyzer_mgr->GetComponentTag(FUZZ_ANALYZER_NAME); + if ( ! analyzer_tag ) { + std::fprintf(stderr, "Unable to find component tag for '%s'", FUZZ_ANALYZER_NAME); + abort(); + } + + // Would be nice to have that in LLVMFuzzerInitialize, oh well... + static bool one_time_setup = false; + if ( ! one_time_setup ) { + zeek::analyzer_mgr->DisableAllAnalyzers(); + zeek::analyzer_mgr->EnableAnalyzer(analyzer_tag); + const auto& pia_tcp_tag = zeek::analyzer_mgr->GetComponentTag("PIA_TCP"); + zeek::analyzer_mgr->EnableAnalyzer(pia_tcp_tag); + one_time_setup = true; + } + + zeek::detail::FuzzBuffer fb{data, size}; + + if ( ! fb.Valid() ) + return 0; + + auto conn = add_connection(); + if ( new_connection ) + conn->Event(new_connection, nullptr); + + auto [a, adapter] = add_analyzer(conn, analyzer_tag); + + // WebSocket specific initialization. May also want to fuzz + // this in the future. + static const auto& config_type = zeek::id::find_type("WebSocket::AnalyzerConfig"); + static const auto& config_rec = zeek::make_intrusive(config_type); + auto wsa = static_cast(a); + wsa->Configure(config_rec); + + for ( ;; ) { + auto chunk = fb.Next(); + + if ( ! chunk ) + break; + + try { + a->NextStream(chunk->size, chunk->data.get(), chunk->is_orig); + } catch ( const binpac::Exception& e ) { + } + + chunk = {}; // Release buffer before draining events. + zeek::event_mgr.Drain(); + + // Has the analyzer been disabled during event processing? + if ( ! adapter->HasChildAnalyzer(analyzer_tag) ) + break; + } + + zeek::event_mgr.Drain(); + zeek::detail::fuzzer_cleanup_one_input(); + + return 0; +} diff --git a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log index 13a58ed17e..f7ca9ce013 100644 --- a/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.bare-load-baseline/canonified_loaded_scripts.log @@ -244,6 +244,10 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_TCP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_TCP.types.bif.zeek build/scripts/base/bif/plugins/Zeek_TCP.functions.bif.zeek + build/scripts/base/bif/plugins/Zeek_WebSocket.consts.bif.zeek + build/scripts/base/bif/plugins/Zeek_WebSocket.events.bif.zeek + build/scripts/base/bif/plugins/Zeek_WebSocket.functions.bif.zeek + build/scripts/base/bif/plugins/Zeek_WebSocket.types.bif.zeek build/scripts/base/bif/plugins/Zeek_XMPP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ARP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek diff --git a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log index 43d87b3515..77e4e88706 100644 --- a/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log +++ b/testing/btest/Baseline/coverage.default-load-baseline/canonified_loaded_scripts.log @@ -244,6 +244,10 @@ scripts/base/init-frameworks-and-bifs.zeek build/scripts/base/bif/plugins/Zeek_TCP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_TCP.types.bif.zeek build/scripts/base/bif/plugins/Zeek_TCP.functions.bif.zeek + build/scripts/base/bif/plugins/Zeek_WebSocket.consts.bif.zeek + build/scripts/base/bif/plugins/Zeek_WebSocket.events.bif.zeek + build/scripts/base/bif/plugins/Zeek_WebSocket.functions.bif.zeek + build/scripts/base/bif/plugins/Zeek_WebSocket.types.bif.zeek build/scripts/base/bif/plugins/Zeek_XMPP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_ARP.events.bif.zeek build/scripts/base/bif/plugins/Zeek_UDP.events.bif.zeek @@ -465,6 +469,9 @@ scripts/base/init-default.zeek scripts/base/protocols/syslog/spicy-events.zeek scripts/base/protocols/syslog/consts.zeek scripts/base/protocols/syslog/main.zeek + scripts/base/protocols/websocket/__load__.zeek + scripts/base/protocols/websocket/consts.zeek + scripts/base/protocols/websocket/main.zeek scripts/base/protocols/tunnels/__load__.zeek scripts/base/protocols/xmpp/__load__.zeek scripts/base/protocols/xmpp/main.zeek diff --git a/testing/btest/Baseline/coverage.find-bro-logs/out b/testing/btest/Baseline/coverage.find-bro-logs/out index efe4d98b6d..ad46a67218 100644 --- a/testing/btest/Baseline/coverage.find-bro-logs/out +++ b/testing/btest/Baseline/coverage.find-bro-logs/out @@ -65,6 +65,7 @@ telemetry_histogram traceroute tunnel unknown_protocols +websocket weird weird_stats x509 diff --git a/testing/btest/Baseline/coverage.record-fields/out.default b/testing/btest/Baseline/coverage.record-fields/out.default index cf0204c6dd..37d4a8083f 100644 --- a/testing/btest/Baseline/coverage.record-fields/out.default +++ b/testing/btest/Baseline/coverage.record-fields/out.default @@ -884,4 +884,20 @@ connection { } * uid: string, log=F, optional=F * vlan: int, log=F, optional=T + * websocket: record WebSocket::Info, log=F, optional=T + WebSocket::Info { + * client_extensions: vector of string, log=T, optional=T + * client_key: string, log=F, optional=T + * client_protocols: vector of string, log=T, optional=T + * host: string, log=T, optional=T + * id: record conn_id, log=T, optional=F + conn_id { ... } + * server_accept: string, log=F, optional=T + * server_extensions: vector of string, log=T, optional=T + * subprotocol: string, log=T, optional=T + * ts: time, log=T, optional=F + * uid: string, log=T, optional=F + * uri: string, log=T, optional=T + * user_agent: string, log=T, optional=T + } } diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output index 386e891e7a..db0b88a431 100644 --- a/testing/btest/Baseline/plugins.hooks/output +++ b/testing/btest/Baseline/plugins.hooks/output @@ -463,6 +463,10 @@ 0.000000 MetaHookPost LoadFile(0, ./Zeek_Teredo.functions.bif.zeek, <...>/Zeek_Teredo.functions.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, ./Zeek_UDP.events.bif.zeek, <...>/Zeek_UDP.events.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, ./Zeek_VXLAN.events.bif.zeek, <...>/Zeek_VXLAN.events.bif.zeek) -> -1 +0.000000 MetaHookPost LoadFile(0, ./Zeek_WebSocket.consts.bif.zeek, <...>/Zeek_WebSocket.consts.bif.zeek) -> -1 +0.000000 MetaHookPost LoadFile(0, ./Zeek_WebSocket.events.bif.zeek, <...>/Zeek_WebSocket.events.bif.zeek) -> -1 +0.000000 MetaHookPost LoadFile(0, ./Zeek_WebSocket.functions.bif.zeek, <...>/Zeek_WebSocket.functions.bif.zeek) -> -1 +0.000000 MetaHookPost LoadFile(0, ./Zeek_WebSocket.types.bif.zeek, <...>/Zeek_WebSocket.types.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, ./Zeek_X509.events.bif.zeek, <...>/Zeek_X509.events.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, ./Zeek_X509.functions.bif.zeek, <...>/Zeek_X509.functions.bif.zeek) -> -1 0.000000 MetaHookPost LoadFile(0, ./Zeek_X509.ocsp_events.bif.zeek, <...>/Zeek_X509.ocsp_events.bif.zeek) -> -1 @@ -752,6 +756,10 @@ 0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_Teredo.functions.bif.zeek, <...>/Zeek_Teredo.functions.bif.zeek) -> (-1, ) 0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_UDP.events.bif.zeek, <...>/Zeek_UDP.events.bif.zeek) -> (-1, ) 0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_VXLAN.events.bif.zeek, <...>/Zeek_VXLAN.events.bif.zeek) -> (-1, ) +0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_WebSocket.consts.bif.zeek, <...>/Zeek_WebSocket.consts.bif.zeek) -> (-1, ) +0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_WebSocket.events.bif.zeek, <...>/Zeek_WebSocket.events.bif.zeek) -> (-1, ) +0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_WebSocket.functions.bif.zeek, <...>/Zeek_WebSocket.functions.bif.zeek) -> (-1, ) +0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_WebSocket.types.bif.zeek, <...>/Zeek_WebSocket.types.bif.zeek) -> (-1, ) 0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_X509.events.bif.zeek, <...>/Zeek_X509.events.bif.zeek) -> (-1, ) 0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_X509.functions.bif.zeek, <...>/Zeek_X509.functions.bif.zeek) -> (-1, ) 0.000000 MetaHookPost LoadFileExtended(0, ./Zeek_X509.ocsp_events.bif.zeek, <...>/Zeek_X509.ocsp_events.bif.zeek) -> (-1, ) @@ -1389,6 +1397,10 @@ 0.000000 MetaHookPre LoadFile(0, ./Zeek_Teredo.functions.bif.zeek, <...>/Zeek_Teredo.functions.bif.zeek) 0.000000 MetaHookPre LoadFile(0, ./Zeek_UDP.events.bif.zeek, <...>/Zeek_UDP.events.bif.zeek) 0.000000 MetaHookPre LoadFile(0, ./Zeek_VXLAN.events.bif.zeek, <...>/Zeek_VXLAN.events.bif.zeek) +0.000000 MetaHookPre LoadFile(0, ./Zeek_WebSocket.consts.bif.zeek, <...>/Zeek_WebSocket.consts.bif.zeek) +0.000000 MetaHookPre LoadFile(0, ./Zeek_WebSocket.events.bif.zeek, <...>/Zeek_WebSocket.events.bif.zeek) +0.000000 MetaHookPre LoadFile(0, ./Zeek_WebSocket.functions.bif.zeek, <...>/Zeek_WebSocket.functions.bif.zeek) +0.000000 MetaHookPre LoadFile(0, ./Zeek_WebSocket.types.bif.zeek, <...>/Zeek_WebSocket.types.bif.zeek) 0.000000 MetaHookPre LoadFile(0, ./Zeek_X509.events.bif.zeek, <...>/Zeek_X509.events.bif.zeek) 0.000000 MetaHookPre LoadFile(0, ./Zeek_X509.functions.bif.zeek, <...>/Zeek_X509.functions.bif.zeek) 0.000000 MetaHookPre LoadFile(0, ./Zeek_X509.ocsp_events.bif.zeek, <...>/Zeek_X509.ocsp_events.bif.zeek) @@ -1678,6 +1690,10 @@ 0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_Teredo.functions.bif.zeek, <...>/Zeek_Teredo.functions.bif.zeek) 0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_UDP.events.bif.zeek, <...>/Zeek_UDP.events.bif.zeek) 0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_VXLAN.events.bif.zeek, <...>/Zeek_VXLAN.events.bif.zeek) +0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_WebSocket.consts.bif.zeek, <...>/Zeek_WebSocket.consts.bif.zeek) +0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_WebSocket.events.bif.zeek, <...>/Zeek_WebSocket.events.bif.zeek) +0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_WebSocket.functions.bif.zeek, <...>/Zeek_WebSocket.functions.bif.zeek) +0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_WebSocket.types.bif.zeek, <...>/Zeek_WebSocket.types.bif.zeek) 0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_X509.events.bif.zeek, <...>/Zeek_X509.events.bif.zeek) 0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_X509.functions.bif.zeek, <...>/Zeek_X509.functions.bif.zeek) 0.000000 MetaHookPre LoadFileExtended(0, ./Zeek_X509.ocsp_events.bif.zeek, <...>/Zeek_X509.ocsp_events.bif.zeek) @@ -2314,6 +2330,10 @@ 0.000000 | HookLoadFile ./Zeek_Teredo.functions.bif.zeek <...>/Zeek_Teredo.functions.bif.zeek 0.000000 | HookLoadFile ./Zeek_UDP.events.bif.zeek <...>/Zeek_UDP.events.bif.zeek 0.000000 | HookLoadFile ./Zeek_VXLAN.events.bif.zeek <...>/Zeek_VXLAN.events.bif.zeek +0.000000 | HookLoadFile ./Zeek_WebSocket.consts.bif.zeek <...>/Zeek_WebSocket.consts.bif.zeek +0.000000 | HookLoadFile ./Zeek_WebSocket.events.bif.zeek <...>/Zeek_WebSocket.events.bif.zeek +0.000000 | HookLoadFile ./Zeek_WebSocket.functions.bif.zeek <...>/Zeek_WebSocket.functions.bif.zeek +0.000000 | HookLoadFile ./Zeek_WebSocket.types.bif.zeek <...>/Zeek_WebSocket.types.bif.zeek 0.000000 | HookLoadFile ./Zeek_X509.events.bif.zeek <...>/Zeek_X509.events.bif.zeek 0.000000 | HookLoadFile ./Zeek_X509.functions.bif.zeek <...>/Zeek_X509.functions.bif.zeek 0.000000 | HookLoadFile ./Zeek_X509.ocsp_events.bif.zeek <...>/Zeek_X509.ocsp_events.bif.zeek @@ -2603,6 +2623,10 @@ 0.000000 | HookLoadFileExtended ./Zeek_Teredo.functions.bif.zeek <...>/Zeek_Teredo.functions.bif.zeek 0.000000 | HookLoadFileExtended ./Zeek_UDP.events.bif.zeek <...>/Zeek_UDP.events.bif.zeek 0.000000 | HookLoadFileExtended ./Zeek_VXLAN.events.bif.zeek <...>/Zeek_VXLAN.events.bif.zeek +0.000000 | HookLoadFileExtended ./Zeek_WebSocket.consts.bif.zeek <...>/Zeek_WebSocket.consts.bif.zeek +0.000000 | HookLoadFileExtended ./Zeek_WebSocket.events.bif.zeek <...>/Zeek_WebSocket.events.bif.zeek +0.000000 | HookLoadFileExtended ./Zeek_WebSocket.functions.bif.zeek <...>/Zeek_WebSocket.functions.bif.zeek +0.000000 | HookLoadFileExtended ./Zeek_WebSocket.types.bif.zeek <...>/Zeek_WebSocket.types.bif.zeek 0.000000 | HookLoadFileExtended ./Zeek_X509.events.bif.zeek <...>/Zeek_X509.events.bif.zeek 0.000000 | HookLoadFileExtended ./Zeek_X509.functions.bif.zeek <...>/Zeek_X509.functions.bif.zeek 0.000000 | HookLoadFileExtended ./Zeek_X509.ocsp_events.bif.zeek <...>/Zeek_X509.ocsp_events.bif.zeek diff --git a/testing/btest/Baseline/scripts.base.files.x509.files/files.log b/testing/btest/Baseline/scripts.base.files.x509.files/files.log index e64dfc52c0..ce19924fa1 100644 --- a/testing/btest/Baseline/scripts.base.files.x509.files/files.log +++ b/testing/btest/Baseline/scripts.base.files.x509.files/files.log @@ -7,10 +7,10 @@ #open XXXX-XX-XX-XX-XX-XX #fields ts fuid uid id.orig_h id.orig_p id.resp_h id.resp_p source depth analyzers mime_type filename duration local_orig is_orig seen_bytes total_bytes missing_bytes overflow_bytes timedout parent_fuid md5 sha1 sha256 #types time string string addr port addr port string count set[string] string string interval bool bool count count count count bool string string string string -XXXXXXXXXX.XXXXXX FgN3AE3of2TRIqaeQe CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43 -XXXXXXXXXX.XXXXXX Fv2Agc4z5boBOacQi6 CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d -XXXXXXXXXX.XXXXXX Ftmyeg2qgI2V38Dt3g CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0 -XXXXXXXXXX.XXXXXX FUFNf84cduA0IJCp07 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43 -XXXXXXXXXX.XXXXXX F1H4bd2OKGbLPEdHm4 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d -XXXXXXXXXX.XXXXXX Fgsbci2jxFXYMOHOhi ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0 +XXXXXXXXXX.XXXXXX FgN3AE3of2TRIqaeQe CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43 +XXXXXXXXXX.XXXXXX Fv2Agc4z5boBOacQi6 CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d +XXXXXXXXXX.XXXXXX Ftmyeg2qgI2V38Dt3g CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0 +XXXXXXXXXX.XXXXXX FUFNf84cduA0IJCp07 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43 +XXXXXXXXXX.XXXXXX F1H4bd2OKGbLPEdHm4 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d +XXXXXXXXXX.XXXXXX Fgsbci2jxFXYMOHOhi ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0 #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.http.101-switching-protocols/.stdout b/testing/btest/Baseline/scripts.base.protocols.http.101-switching-protocols/.stdout index 3ad275db0c..59953c34b1 100644 --- a/testing/btest/Baseline/scripts.base.protocols.http.101-switching-protocols/.stdout +++ b/testing/btest/Baseline/scripts.base.protocols.http.101-switching-protocols/.stdout @@ -1,2 +1,3 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +WebSocket::configure_analyzer, CHhAvVGS1DHFjwGM9, 7, x-kaazing-handshake Connection upgraded to websocket diff --git a/testing/btest/Baseline/scripts.base.protocols.http.101-switching-protocols/websocket.log b/testing/btest/Baseline/scripts.base.protocols.http.101-switching-protocols/websocket.log new file mode 100644 index 0000000000..6e576ea12a --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.http.101-switching-protocols/websocket.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path websocket +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p host uri user_agent subprotocol client_protocols server_extensions client_extensions +#types time string addr port addr port string string string string vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 192.168.0.5 50798 54.148.114.85 80 sandbox.kaazing.net /echo?.kl=Y Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:54.0) Gecko/20100101 Firefox/54.0 x-kaazing-handshake x-kaazing-handshake - permessage-deflate +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.broker-websocket/conn.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.broker-websocket/conn.log.cut new file mode 100644 index 0000000000..f5bd2aa2ab --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.broker-websocket/conn.log.cut @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid history service +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ShADadfF websocket,http diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.broker-websocket/websocket.log b/testing/btest/Baseline/scripts.base.protocols.websocket.broker-websocket/websocket.log new file mode 100644 index 0000000000..ba6652b2bb --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.broker-websocket/websocket.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path websocket +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p host uri user_agent subprotocol client_protocols server_extensions client_extensions +#types time string addr port addr port string string string string vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 38776 127.0.0.1 27599 localhost:27599 /v1/messages/json Python/3.10 websockets/12.0 - - - permessage-deflate; client_max_window_bits +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.coalesced-reply-ping/out-coalesced b/testing/btest/Baseline/scripts.base.protocols.websocket.coalesced-reply-ping/out-coalesced new file mode 100644 index 0000000000..bb559170db --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.coalesced-reply-ping/out-coalesced @@ -0,0 +1,16 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +websocket_established, CHhAvVGS1DHFjwGM9, 7 +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, ping, payload_len, 4 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 4, data, Zeek +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, pong, payload_len, 4 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 4, data, Zeek +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, text, payload_len, 11 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 11, data, Hello Zeek! +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, text, payload_len, 12 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 12, data, Hello there! +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, close, payload_len, 2 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 2, data, \x03\xe8 +websocket_close, CHhAvVGS1DHFjwGM9, T, status, 1000, reason, +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, close, payload_len, 2 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 2, data, \x03\xe8 +websocket_close, CHhAvVGS1DHFjwGM9, F, status, 1000, reason, diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.coalesced-reply-ping/out-separate b/testing/btest/Baseline/scripts.base.protocols.websocket.coalesced-reply-ping/out-separate new file mode 100644 index 0000000000..bb559170db --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.coalesced-reply-ping/out-separate @@ -0,0 +1,16 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +websocket_established, CHhAvVGS1DHFjwGM9, 7 +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, ping, payload_len, 4 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 4, data, Zeek +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, pong, payload_len, 4 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 4, data, Zeek +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, text, payload_len, 11 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 11, data, Hello Zeek! +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, text, payload_len, 12 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 12, data, Hello there! +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, close, payload_len, 2 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 2, data, \x03\xe8 +websocket_close, CHhAvVGS1DHFjwGM9, T, status, 1000, reason, +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, close, payload_len, 2 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 2, data, \x03\xe8 +websocket_close, CHhAvVGS1DHFjwGM9, F, status, 1000, reason, diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.coalesced-reply-ping/weird.log b/testing/btest/Baseline/scripts.base.protocols.websocket.coalesced-reply-ping/weird.log new file mode 100644 index 0000000000..16031b4969 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.coalesced-reply-ping/weird.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path weird +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer source +#types time string addr port addr port string string bool string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 45838 127.0.0.1 8080 protocol_data_with_HTTP_upgrade_reply 6 F zeek HTTP +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.events/out b/testing/btest/Baseline/scripts.base.protocols.websocket.events/out new file mode 100644 index 0000000000..af9e938aaf --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.events/out @@ -0,0 +1,128 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +jupyter-websocket.pcap +websocket_established, CHhAvVGS1DHFjwGM9, 7, [ts=XXXXXXXXXX.XXXXXX, uid=CHhAvVGS1DHFjwGM9, id=[orig_h=127.0.0.1, orig_p=40492/tcp, resp_h=127.0.0.1, resp_p=51185/tcp], host=192.168.122.182, uri=/user/christian/api/kernels/f8645ecd-0a76-4bb1-9e6e-cb464276bc69/channels?session_id=deeecee7-efc2-42a1-a7c1-e1c0569436e3, user_agent=Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0, subprotocol=v1.kernel.websocket.jupyter.org, client_protocols=[v1.kernel.websocket.jupyter.org], server_extensions=, client_extensions=[permessage-deflate], client_key=7K5Qx7HwJUsja5KzBhGvfQ==, server_accept=USseDip1PofjB67M6I5CNkbYbp0=] +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, binary, payload_len, 262 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 262, data, \x06\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x02\x01\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x00\x00\x00\x00\x06\x01\x00\x00\x00\x00\x00\x00shell{"date":"2023-09-29T23:25:05.568Z","msg_id":"5af8fd02-14a1- +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, binary, payload_len, 539 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 539, data, \x06\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x00\x00\x00\x00\x14\x01\x00\x00\x00\x00\x00\x00\xfe\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x1b\x02\x00\x00\x00\x00\x00\x00iopub{"msg_id": "5accb611-84744090d18c920147a97eb5_25702_7", "ms +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, binary, payload_len, 527 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 527, data, \x06\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x00\x00\x00\x00\x14\x01\x00\x00\x00\x00\x00\x00\xf2\x01\x00\x00\x00\x00\x00\x00\xf4\x01\x00\x00\x00\x00\x00\x00\x0f\x02\x00\x00\x00\x00\x00\x00iopub{"msg_id": "5accb611-84744090d18c920147a97eb5_25702_9", "ms +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, binary, payload_len, 1647 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 1647, data, \x06\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x00\x00\x00\x00 \x01\x00\x00\x00\x00\x00\x00\xf1\x01\x00\x00\x00\x00\x00\x00\xf3\x01\x00\x00\x00\x00\x00\x00o\x06\x00\x00\x00\x00\x00\x00shell{"msg_id": "5accb611-84744090d18c920147a97eb5_25702_14", "m +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, binary, payload_len, 540 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 540, data, \x06\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x00\x00\x00\x00\x15\x01\x00\x00\x00\x00\x00\x00\xff\x01\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x00\x1c\x02\x00\x00\x00\x00\x00\x00iopub{"msg_id": "5accb611-84744090d18c920147a97eb5_25702_10", "m +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, binary, payload_len, 540 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 540, data, \x06\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x00\x00\x00\x00\x15\x01\x00\x00\x00\x00\x00\x00\xff\x01\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x00\x1c\x02\x00\x00\x00\x00\x00\x00iopub{"msg_id": "5accb611-84744090d18c920147a97eb5_25702_12", "m +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, binary, payload_len, 515 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 515, data, \x06\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x00\x00\x00\x00\x15\x01\x00\x00\x00\x00\x00\x00\xe6\x01\x00\x00\x00\x00\x00\x00\xe8\x01\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x00\x00\x00iopub{"msg_id": "5accb611-84744090d18c920147a97eb5_25702_13", "m +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, binary, payload_len, 515 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 515, data, \x06\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x00\x00\x00\x00\x15\x01\x00\x00\x00\x00\x00\x00\xe6\x01\x00\x00\x00\x00\x00\x00\xe8\x01\x00\x00\x00\x00\x00\x00\x03\x02\x00\x00\x00\x00\x00\x00iopub{"msg_id": "5accb611-84744090d18c920147a97eb5_25702_15", "m +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, binary, payload_len, 540 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 540, data, \x06\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x00\x00\x00\x00\x15\x01\x00\x00\x00\x00\x00\x00\xff\x01\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x00\x1c\x02\x00\x00\x00\x00\x00\x00iopub{"msg_id": "5accb611-84744090d18c920147a97eb5_25702_16", "m +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, binary, payload_len, 540 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 540, data, \x06\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x00\x00\x00\x00\x15\x01\x00\x00\x00\x00\x00\x00\xff\x01\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x00\x1c\x02\x00\x00\x00\x00\x00\x00iopub{"msg_id": "5accb611-84744090d18c920147a97eb5_25702_18", "m +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, binary, payload_len, 540 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 540, data, \x06\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x00\x00\x00\x00\x15\x01\x00\x00\x00\x00\x00\x00\xff\x01\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x00\x1c\x02\x00\x00\x00\x00\x00\x00iopub{"msg_id": "5accb611-84744090d18c920147a97eb5_25702_20", "m +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, binary, payload_len, 540 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 540, data, \x06\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x00\x00\x00\x00\x15\x01\x00\x00\x00\x00\x00\x00\xff\x01\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x00\x00\x00\x00\x1c\x02\x00\x00\x00\x00\x00\x00iopub{"msg_id": "5accb611-84744090d18c920147a97eb5_25702_21", "m +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, close, payload_len, 0 +websocket_close, CHhAvVGS1DHFjwGM9, T, status, 0, reason, +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, close +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, close, payload_len, 0 +websocket_close, CHhAvVGS1DHFjwGM9, F, status, 0, reason, +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, close +wstunnel-http.pcap +websocket_established, CHhAvVGS1DHFjwGM9, 7, [ts=XXXXXXXXXX.XXXXXX, uid=CHhAvVGS1DHFjwGM9, id=[orig_h=127.0.0.1, orig_p=51102/tcp, resp_h=127.0.0.1, resp_p=8888/tcp], host=localhost:8888, uri=/v1/events, user_agent=, subprotocol=v1, client_protocols=[v1, authorization.bearer.eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjAxOGNmZWFiLWY5OWQtNzBmNy05NmFmLTBlOGJhNjk2YTFmNiIsInAiOiJUY3AiLCJyIjoiemVlay5vcmciLCJycCI6ODB9.FsquetBp_jsIDzBslWyyTPlS2hcMprVuWmbT2r57N0A], server_extensions=, client_extensions=, client_key=FdRecb4tsolqJgO+HrbUfg==, server_accept=PbXiEPoL5O2wxc6/MdNHnSOXy+c=] +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, binary, payload_len, 72 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 72, data, GET / HTTP/1.1\x0d\x0aHost: zeek.org\x0d\x0aUser-Agent: curl/7.81.0\x0d\x0aAccept: */*\x0d\x0a\x0d\x0a +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, binary, payload_len, 409 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 409, data, HTTP/1.1 301 Moved Permanently\x0d\x0aServer: nginx\x0d\x0aDate: Fri, 12 Jan 2024 17:15:32 GMT\x0d\x0aContent-Type: text/html\x0d\x0aContent-Len +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, close, payload_len, 2 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 2, data, \x03\xe8 +websocket_close, CHhAvVGS1DHFjwGM9, T, status, 1000, reason, +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, close +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, close, payload_len, 2 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 2, data, \x03\xe8 +websocket_close, CHhAvVGS1DHFjwGM9, F, status, 1000, reason, +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, close +broker-websocket.pcap +websocket_established, CHhAvVGS1DHFjwGM9, 7, [ts=XXXXXXXXXX.XXXXXX, uid=CHhAvVGS1DHFjwGM9, id=[orig_h=127.0.0.1, orig_p=38776/tcp, resp_h=127.0.0.1, resp_p=27599/tcp], host=localhost:27599, uri=/v1/messages/json, user_agent=Python/3.10 websockets/12.0, subprotocol=, client_protocols=, server_extensions=, client_extensions=[permessage-deflate; client_max_window_bits], client_key=E58pVwft35HPkD/MFCjtEA==, server_accept=HxOmr1a2nvOOc4Qiv7Ou3wrCsJc=] +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, text, payload_len, 24 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 24, data, ["/zeek/event/my_topic"] +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, text +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, text, payload_len, 91 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 91, data, {"type": "ack", "endpoint": "cfc03c41-7983-5fe2-b22e-6894100e6305", "version": "2.8.0-dev"} +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, text +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, text, payload_len, 533 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 533, data, {"type": "data-message", "topic": "/zeek/event/my_topic", "@data-type": "vector", "data": [{"@data-type": "count", "data +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, text +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, text, payload_len, 361 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 361, data, {"type": "data-message", "topic": "/zeek/event/my_topic", "@data-type": "vector", "data": [{"@data-type": "count", "data +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, text +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, text, payload_len, 533 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 533, data, {"type": "data-message", "topic": "/zeek/event/my_topic", "@data-type": "vector", "data": [{"@data-type": "count", "data +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, text +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, text, payload_len, 361 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 361, data, {"type": "data-message", "topic": "/zeek/event/my_topic", "@data-type": "vector", "data": [{"@data-type": "count", "data +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, text +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, text, payload_len, 533 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 533, data, {"type": "data-message", "topic": "/zeek/event/my_topic", "@data-type": "vector", "data": [{"@data-type": "count", "data +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, text +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, text, payload_len, 361 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 361, data, {"type": "data-message", "topic": "/zeek/event/my_topic", "@data-type": "vector", "data": [{"@data-type": "count", "data +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, text +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, close, payload_len, 2 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 2, data, \x03\xe8 +websocket_close, CHhAvVGS1DHFjwGM9, T, status, 1000, reason, +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, close +message-too-big-status.pcap +websocket_established, CHhAvVGS1DHFjwGM9, 7, [ts=XXXXXXXXXX.XXXXXX, uid=CHhAvVGS1DHFjwGM9, id=[orig_h=127.0.0.1, orig_p=60956/tcp, resp_h=127.0.0.1, resp_p=8080/tcp], host=localhost:8080, uri=/, user_agent=Python/3.10 websockets/12.0, subprotocol=v1, client_protocols=[v1], server_extensions=, client_extensions=[permessage-deflate; client_max_window_bits], client_key=iTel1Ova5Nhz/G7VlI2qKg==, server_accept=YsQYYLj7ZCpzTLsVLb+w/ydy79E=] +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, ping, payload_len, 4 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 4, data, Zeek +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, ping +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, close, payload_len, 31 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 31, data, \x03\xf1over size limit (4 > 2 bytes) +websocket_close, CHhAvVGS1DHFjwGM9, T, status, 1009, reason, over size limit (4 > 2 bytes) +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, close +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, close, payload_len, 2 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 2, data, \x03\xe8 +websocket_close, CHhAvVGS1DHFjwGM9, F, status, 1000, reason, +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, close +two-binary-fragments.pcap +websocket_established, CHhAvVGS1DHFjwGM9, 7, [ts=XXXXXXXXXX.XXXXXX, uid=CHhAvVGS1DHFjwGM9, id=[orig_h=127.0.0.1, orig_p=50198/tcp, resp_h=127.0.0.1, resp_p=8080/tcp], host=localhost:8080, uri=/, user_agent=Python/3.10 websockets/12.0, subprotocol=v1, client_protocols=[v1], server_extensions=, client_extensions=[permessage-deflate; client_max_window_bits], client_key=cQGA5Z1nvyUJ9XOVIaLaQA==, server_accept=zWaHVUKxEGPDs+xJeKtzkE1bm54=] +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, ping, payload_len, 4 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 4, data, Zeek +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, ping +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, pong, payload_len, 4 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 4, data, Zeek +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, pong +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, binary, payload_len, 11 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 11, data, Hello Zeek! +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, F, rsv, 0, opcode, binary, payload_len, 5 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 5, data, Hello +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, continuation, payload_len, 7 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 7, data, there! +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, binary +websocket_frame, CHhAvVGS1DHFjwGM9, T, fin, T, rsv, 0, opcode, close, payload_len, 2 +websocket_frame_data, CHhAvVGS1DHFjwGM9, T, len, 2, data, \x03\xe8 +websocket_close, CHhAvVGS1DHFjwGM9, T, status, 1000, reason, +websocket_message, CHhAvVGS1DHFjwGM9, T, opcode, close +websocket_frame, CHhAvVGS1DHFjwGM9, F, fin, T, rsv, 0, opcode, close, payload_len, 2 +websocket_frame_data, CHhAvVGS1DHFjwGM9, F, len, 2, data, \x03\xe8 +websocket_close, CHhAvVGS1DHFjwGM9, F, status, 1000, reason, +websocket_message, CHhAvVGS1DHFjwGM9, F, opcode, close diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.jupyter-websocket/conn.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.jupyter-websocket/conn.log.cut new file mode 100644 index 0000000000..f5bd2aa2ab --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.jupyter-websocket/conn.log.cut @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid history service +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ShADadfF websocket,http diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.jupyter-websocket/websocket.log b/testing/btest/Baseline/scripts.base.protocols.websocket.jupyter-websocket/websocket.log new file mode 100644 index 0000000000..c9c00fc79f --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.jupyter-websocket/websocket.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path websocket +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p host uri user_agent subprotocol client_protocols server_extensions client_extensions +#types time string addr port addr port string string string string vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 40492 127.0.0.1 51185 192.168.122.182 /user/christian/api/kernels/f8645ecd-0a76-4bb1-9e6e-cb464276bc69/channels?session_id=deeecee7-efc2-42a1-a7c1-e1c0569436e3 Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0 v1.kernel.websocket.jupyter.org v1.kernel.websocket.jupyter.org - permessage-deflate +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.key-accept-wrong/websocket.log b/testing/btest/Baseline/scripts.base.protocols.websocket.key-accept-wrong/websocket.log new file mode 100644 index 0000000000..077a4e7b65 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.key-accept-wrong/websocket.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path websocket +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p host uri user_agent subprotocol client_protocols server_extensions client_extensions +#types time string addr port addr port string string string string vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 53654 127.0.0.1 8080 localhost:8080 / Python/3.10 websockets/12.0 v1 v1 - permessage-deflate; client_max_window_bits +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.key-accept-wrong/weird.log b/testing/btest/Baseline/scripts.base.protocols.websocket.key-accept-wrong/weird.log new file mode 100644 index 0000000000..7f15a7082c --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.key-accept-wrong/weird.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path weird +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p name addl notice peer source +#types time string addr port addr port string string bool string string +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 53654 127.0.0.1 8080 websocket_wrong_accept_header expected=N8ntNYkX6Qerw4tK3s/CYzpSZNc=, found=N8ntNYkX6Qerw4tK3s/CYzpSZNc=-wrong F zeek WebSocket +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-http/conn.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-http/conn.log.cut new file mode 100644 index 0000000000..bb892cdeb5 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-http/conn.log.cut @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid history service +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ShADadFR websocket,http diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-http/http.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-http/http.log.cut new file mode 100644 index 0000000000..0aa3a4d7a5 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-http/http.log.cut @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid host uri status_code user_agent +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 localhost:8888 /v1/events 301 - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 zeek.org / - curl/7.81.0 diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-http/websocket.log b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-http/websocket.log new file mode 100644 index 0000000000..e577952088 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-http/websocket.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path websocket +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p host uri user_agent subprotocol client_protocols server_extensions client_extensions +#types time string addr port addr port string string string string vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 51102 127.0.0.1 8888 localhost:8888 /v1/events - v1 v1,authorization.bearer.eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjAxOGNmZWFiLWY5OWQtNzBmNy05NmFmLTBlOGJhNjk2YTFmNiIsInAiOiJUY3AiLCJyIjoiemVlay5vcmciLCJycCI6ODB9.FsquetBp_jsIDzBslWyyTPlS2hcMprVuWmbT2r57N0A - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-https/conn.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-https/conn.log.cut new file mode 100644 index 0000000000..b61cd3bda1 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-https/conn.log.cut @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid history service +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ShADadFR websocket,ssl,http diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-https/ssl.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-https/ssl.log.cut new file mode 100644 index 0000000000..e98e26c97c --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-https/ssl.log.cut @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid version server_name ssl_history +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 TLSv13 zeek.org CsiI diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-https/websocket.log b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-https/websocket.log new file mode 100644 index 0000000000..a814ca5986 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-https/websocket.log @@ -0,0 +1,11 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path websocket +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p host uri user_agent subprotocol client_protocols server_extensions client_extensions +#types time string addr port addr port string string string string vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 39992 127.0.0.1 8888 localhost:8888 /v1/events - v1 v1,authorization.bearer.eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjAxOGQwNTY1LTlmZTItNzFkZS1iNjRlLTU5MzhmZTI0ZmIyZCIsInAiOiJUY3AiLCJyIjoiMTkyLjAuNzguMTUwIiwicnAiOjQ0M30.xyDNRR4kK4fQSGfEyGzuUINn0xBVltxrFVBieMlqwEI - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-break/conn.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-break/conn.log.cut new file mode 100644 index 0000000000..43dce97d68 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-break/conn.log.cut @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid history service +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ShADadR http +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ShADadR http diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-break/out b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-break/out new file mode 100644 index 0000000000..d4a94d5da7 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-break/out @@ -0,0 +1,5 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +WebSocket::configure_analyzer, CHhAvVGS1DHFjwGM9, 7 +disabling_analyzer, CHhAvVGS1DHFjwGM9, Analyzer::ANALYZER_WEBSOCKET, 7 +WebSocket::configure_analyzer, ClEkJM2Vm5giqnMf4h, 14 +disabling_analyzer, ClEkJM2Vm5giqnMf4h, Analyzer::ANALYZER_WEBSOCKET, 14 diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-break/websocket.log b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-break/websocket.log new file mode 100644 index 0000000000..e993d7b4cf --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-break/websocket.log @@ -0,0 +1,12 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path websocket +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p host uri user_agent subprotocol client_protocols server_extensions client_extensions +#types time string addr port addr port string string string string vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 42906 127.0.0.1 8888 localhost:8888 /v1/events - v1 v1,authorization.bearer.eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjAxOGQwNTVkLTQ5OTgtNzI5Zi04Yjg2LTMwZTBiZWEyZGE4ZiIsInAiOiJUY3AiLCJyIjoiMTk1LjIwMS4xNDguMjA5IiwicnAiOjIyfQ.jjTNJL12tQbAuhTB9p_geFXRkEHkxcvOS6zf76qDklQ - - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 46796 127.0.0.1 8888 localhost:8888 /v1/events - v1 v1,authorization.bearer.eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjAxOGQwNTVkLTc4MWYtNzNiYi1hZDkwLTEzNjA5NzRjY2JmMyIsInAiOiJUY3AiLCJyIjoiMTk1LjIwMS4xNDguMjA5IiwicnAiOjIyfQ.2HQ4uC23p_OYIXnQWeSZCqdA3jc_lVVH7-T5xZDPrz4 - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-wrong/conn.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-wrong/conn.log.cut new file mode 100644 index 0000000000..e8d2c4ae9a --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-wrong/conn.log.cut @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid history service +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ShADadR websocket,http +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ShADadR websocket,http diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-wrong/websocket.log b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-wrong/websocket.log new file mode 100644 index 0000000000..e993d7b4cf --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure-wrong/websocket.log @@ -0,0 +1,12 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path websocket +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p host uri user_agent subprotocol client_protocols server_extensions client_extensions +#types time string addr port addr port string string string string vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 42906 127.0.0.1 8888 localhost:8888 /v1/events - v1 v1,authorization.bearer.eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjAxOGQwNTVkLTQ5OTgtNzI5Zi04Yjg2LTMwZTBiZWEyZGE4ZiIsInAiOiJUY3AiLCJyIjoiMTk1LjIwMS4xNDguMjA5IiwicnAiOjIyfQ.jjTNJL12tQbAuhTB9p_geFXRkEHkxcvOS6zf76qDklQ - - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 46796 127.0.0.1 8888 localhost:8888 /v1/events - v1 v1,authorization.bearer.eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjAxOGQwNTVkLTc4MWYtNzNiYi1hZDkwLTEzNjA5NzRjY2JmMyIsInAiOiJUY3AiLCJyIjoiMTk1LjIwMS4xNDguMjA5IiwicnAiOjIyfQ.2HQ4uC23p_OYIXnQWeSZCqdA3jc_lVVH7-T5xZDPrz4 - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure/conn.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure/conn.log.cut new file mode 100644 index 0000000000..72dcb1c5fa --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure/conn.log.cut @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid history service +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ShADadR websocket,ssh,http +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ShADadR websocket,ssh,http diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure/ssh.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure/ssh.log.cut new file mode 100644 index 0000000000..0780213a89 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure/ssh.log.cut @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid client server auth_success auth_attempts kex_alg host_key_alg +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6 SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.5 F 4 curve25519-sha256 ssh-ed25519 +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6 SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.5 T 5 curve25519-sha256 ssh-ed25519 diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure/websocket.log b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure/websocket.log new file mode 100644 index 0000000000..e993d7b4cf --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-configure/websocket.log @@ -0,0 +1,12 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path websocket +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p host uri user_agent subprotocol client_protocols server_extensions client_extensions +#types time string addr port addr port string string string string vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 42906 127.0.0.1 8888 localhost:8888 /v1/events - v1 v1,authorization.bearer.eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjAxOGQwNTVkLTQ5OTgtNzI5Zi04Yjg2LTMwZTBiZWEyZGE4ZiIsInAiOiJUY3AiLCJyIjoiMTk1LjIwMS4xNDguMjA5IiwicnAiOjIyfQ.jjTNJL12tQbAuhTB9p_geFXRkEHkxcvOS6zf76qDklQ - - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 46796 127.0.0.1 8888 localhost:8888 /v1/events - v1 v1,authorization.bearer.eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjAxOGQwNTVkLTc4MWYtNzNiYi1hZDkwLTEzNjA5NzRjY2JmMyIsInAiOiJUY3AiLCJyIjoiMTk1LjIwMS4xNDguMjA5IiwicnAiOjIyfQ.2HQ4uC23p_OYIXnQWeSZCqdA3jc_lVVH7-T5xZDPrz4 - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-disabled/conn.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-disabled/conn.log.cut new file mode 100644 index 0000000000..43dce97d68 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh-disabled/conn.log.cut @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid history service +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ShADadR http +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ShADadR http diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh/conn.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh/conn.log.cut new file mode 100644 index 0000000000..72dcb1c5fa --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh/conn.log.cut @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid history service +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ShADadR websocket,ssh,http +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h ShADadR websocket,ssh,http diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh/ssh.log.cut b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh/ssh.log.cut new file mode 100644 index 0000000000..0780213a89 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh/ssh.log.cut @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +ts uid client server auth_success auth_attempts kex_alg host_key_alg +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6 SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.5 F 4 curve25519-sha256 ssh-ed25519 +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6 SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.5 T 5 curve25519-sha256 ssh-ed25519 diff --git a/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh/websocket.log b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh/websocket.log new file mode 100644 index 0000000000..e993d7b4cf --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.websocket.wstunnel-ssh/websocket.log @@ -0,0 +1,12 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +#separator \x09 +#set_separator , +#empty_field (empty) +#unset_field - +#path websocket +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p host uri user_agent subprotocol client_protocols server_extensions client_extensions +#types time string addr port addr port string string string string vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 42906 127.0.0.1 8888 localhost:8888 /v1/events - v1 v1,authorization.bearer.eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjAxOGQwNTVkLTQ5OTgtNzI5Zi04Yjg2LTMwZTBiZWEyZGE4ZiIsInAiOiJUY3AiLCJyIjoiMTk1LjIwMS4xNDguMjA5IiwicnAiOjIyfQ.jjTNJL12tQbAuhTB9p_geFXRkEHkxcvOS6zf76qDklQ - - +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 46796 127.0.0.1 8888 localhost:8888 /v1/events - v1 v1,authorization.bearer.eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjAxOGQwNTVkLTc4MWYtNzNiYi1hZDkwLTEzNjA5NzRjY2JmMyIsInAiOiJUY3AiLCJyIjoiMTk1LjIwMS4xNDguMjA5IiwicnAiOjIyfQ.2HQ4uC23p_OYIXnQWeSZCqdA3jc_lVVH7-T5xZDPrz4 - - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Traces/websocket/broker-websocket.pcap b/testing/btest/Traces/websocket/broker-websocket.pcap new file mode 100644 index 0000000000..4d7ea41199 Binary files /dev/null and b/testing/btest/Traces/websocket/broker-websocket.pcap differ diff --git a/testing/btest/Traces/websocket/jupyter-websocket.pcap b/testing/btest/Traces/websocket/jupyter-websocket.pcap new file mode 100644 index 0000000000..6c2f292202 Binary files /dev/null and b/testing/btest/Traces/websocket/jupyter-websocket.pcap differ diff --git a/testing/btest/Traces/websocket/message-too-big-status.pcap b/testing/btest/Traces/websocket/message-too-big-status.pcap new file mode 100644 index 0000000000..7f51e3f583 Binary files /dev/null and b/testing/btest/Traces/websocket/message-too-big-status.pcap differ diff --git a/testing/btest/Traces/websocket/reply-ping-coalesced.pcap b/testing/btest/Traces/websocket/reply-ping-coalesced.pcap new file mode 100644 index 0000000000..9fbb2ac70a Binary files /dev/null and b/testing/btest/Traces/websocket/reply-ping-coalesced.pcap differ diff --git a/testing/btest/Traces/websocket/reply-ping-separate.pcap b/testing/btest/Traces/websocket/reply-ping-separate.pcap new file mode 100644 index 0000000000..5fa723bc2c Binary files /dev/null and b/testing/btest/Traces/websocket/reply-ping-separate.pcap differ diff --git a/testing/btest/Traces/websocket/two-binary-fragments.pcap b/testing/btest/Traces/websocket/two-binary-fragments.pcap new file mode 100644 index 0000000000..043c46e61f Binary files /dev/null and b/testing/btest/Traces/websocket/two-binary-fragments.pcap differ diff --git a/testing/btest/Traces/websocket/wrong-accept-header.pcap b/testing/btest/Traces/websocket/wrong-accept-header.pcap new file mode 100644 index 0000000000..80ba9b1d4e Binary files /dev/null and b/testing/btest/Traces/websocket/wrong-accept-header.pcap differ diff --git a/testing/btest/Traces/websocket/wstunnel-http.pcap b/testing/btest/Traces/websocket/wstunnel-http.pcap new file mode 100644 index 0000000000..338fe62374 Binary files /dev/null and b/testing/btest/Traces/websocket/wstunnel-http.pcap differ diff --git a/testing/btest/Traces/websocket/wstunnel-https.pcap b/testing/btest/Traces/websocket/wstunnel-https.pcap new file mode 100644 index 0000000000..ff653db770 Binary files /dev/null and b/testing/btest/Traces/websocket/wstunnel-https.pcap differ diff --git a/testing/btest/Traces/websocket/wstunnel-ssh.pcap b/testing/btest/Traces/websocket/wstunnel-ssh.pcap new file mode 100644 index 0000000000..29d1da9cd1 Binary files /dev/null and b/testing/btest/Traces/websocket/wstunnel-ssh.pcap differ diff --git a/testing/btest/scripts/base/protocols/http/101-switching-protocols.zeek b/testing/btest/scripts/base/protocols/http/101-switching-protocols.zeek index e8ec4ff491..5a7231ac30 100644 --- a/testing/btest/scripts/base/protocols/http/101-switching-protocols.zeek +++ b/testing/btest/scripts/base/protocols/http/101-switching-protocols.zeek @@ -1,13 +1,31 @@ -# This tests that the HTTP analyzer does not generate a dpd error as a -# result of seeing an upgraded connection. +# This tests that the HTTP analyzer upgrades to the WebSocket analyzer. +# +# Further, we implement a WebSocket::configure_analyzer() hook to prevent +# DPD on the inner connection. # # @TEST-EXEC: zeek -r $TRACES/http/websocket.pcap %INPUT -# @TEST-EXEC: test ! -f dpd.log # @TEST-EXEC: test ! -f weird.log +# @TEST-EXEC: test ! -f dpd.log # @TEST-EXEC: btest-diff http.log +# @TEST-EXEC: btest-diff websocket.log # @TEST-EXEC: btest-diff .stdout event http_connection_upgrade(c: connection, protocol: string) { print fmt("Connection upgraded to %s", protocol); } + +hook WebSocket::configure_analyzer(c: connection, aid: count, config: WebSocket::AnalyzerConfig) + { + if ( ! config?$subprotocol ) + return; + + print "WebSocket::configure_analyzer", c$uid, aid, config$subprotocol; + if ( config$subprotocol == "x-kaazing-handshake" ) + # The originator's WebSocket frames match HTTP, so DPD would + # enable HTTP for the frame's payload, but the responder's frames + # contain some ack/status junk just before HTTP response that + # trigger a violation. Disable DPD for to prevent a dpd.log + # entry. + config$use_dpd = F; + } diff --git a/testing/btest/scripts/base/protocols/websocket/broker-websocket.zeek b/testing/btest/scripts/base/protocols/websocket/broker-websocket.zeek new file mode 100644 index 0000000000..bd66b7ce7e --- /dev/null +++ b/testing/btest/scripts/base/protocols/websocket/broker-websocket.zeek @@ -0,0 +1,13 @@ +# @TEST-DOC: Test Broker WebSocket traffic. +# +# @TEST-EXEC: zeek -b -r $TRACES/websocket/broker-websocket.pcap %INPUT +# +# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut + +# @TEST-EXEC: btest-diff conn.log.cut +# @TEST-EXEC: btest-diff websocket.log +# @TEST-EXEC: test ! -f analyzer.log +# @TEST-EXEC: test ! -f weird.log + +@load base/protocols/conn +@load base/protocols/websocket diff --git a/testing/btest/scripts/base/protocols/websocket/coalesced-reply-ping.zeek b/testing/btest/scripts/base/protocols/websocket/coalesced-reply-ping.zeek new file mode 100644 index 0000000000..509a44624e --- /dev/null +++ b/testing/btest/scripts/base/protocols/websocket/coalesced-reply-ping.zeek @@ -0,0 +1,33 @@ +# @TEST-DOC: The reply-ping-coalesced pcap contains a WebSocket ping message right after the HTTP reply, in the same packet. + +# @TEST-EXEC: zeek -b -r $TRACES/websocket/reply-ping-separate.pcap %INPUT >>out-separate +# @TEST-EXEC: test ! -f weird.log +# +# @TEST-EXEC: zeek -b -r $TRACES/websocket/reply-ping-coalesced.pcap %INPUT >>out-coalesced +# @TEST-EXEC: btest-diff out-separate +# @TEST-EXEC: btest-diff out-coalesced +# @TEST-EXEC: btest-diff weird.log +# @TEST-EXEC: diff out-separate out-coalesced +# @TEST-EXEC: test ! -f analyzer.log + +@load base/protocols/websocket + +event websocket_established(c: connection, aid: count) + { + print "websocket_established", c$uid, aid; + } + +event websocket_frame(c: connection, is_orig: bool, fin: bool, rsv: count, opcode: count, payload_len: count) + { + print "websocket_frame", c$uid, is_orig, "fin", fin, "rsv", rsv, "opcode", WebSocket::opcodes[opcode], "payload_len", payload_len; + } + +event websocket_frame_data(c: connection, is_orig: bool, data: string) + { + print "websocket_frame_data", c$uid, is_orig, "len", |data|, "data", data[:120]; + } + +event websocket_close(c: connection, is_orig: bool, status: count, reason: string) + { + print "websocket_close", c$uid, is_orig, "status", status, "reason", reason; + } diff --git a/testing/btest/scripts/base/protocols/websocket/events.zeek b/testing/btest/scripts/base/protocols/websocket/events.zeek new file mode 100644 index 0000000000..5c4c1fd2cf --- /dev/null +++ b/testing/btest/scripts/base/protocols/websocket/events.zeek @@ -0,0 +1,42 @@ +# @TEST-DOC: Test WebSocket events. +# +# @TEST-EXEC: echo "jupyter-websocket.pcap" >>out +# @TEST-EXEC: zeek -b -r $TRACES/websocket/jupyter-websocket.pcap %INPUT >>out +# @TEST-EXEC: echo "wstunnel-http.pcap" >>out +# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-http.pcap %INPUT >>out +# @TEST-EXEC: echo "broker-websocket.pcap" >>out +# @TEST-EXEC: zeek -b -r $TRACES//websocket/broker-websocket.pcap %INPUT >>out +# @TEST-EXEC: echo "message-too-big-status.pcap" >>out +# @TEST-EXEC: zeek -b -r $TRACES//websocket/message-too-big-status.pcap %INPUT >>out +# @TEST-EXEC: echo "two-binary-fragments.pcap" >>out +# @TEST-EXEC: zeek -b -r $TRACES//websocket/two-binary-fragments.pcap %INPUT >>out +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: test ! -f analyzer.log +# @TEST-EXEC: test ! -f weird.log + +@load base/protocols/websocket + +event websocket_established(c: connection, aid: count) + { + print "websocket_established", c$uid, aid, c$websocket; + } + +event websocket_message(c: connection, is_orig: bool, opcode: count) + { + print "websocket_message", c$uid, is_orig, "opcode", WebSocket::opcodes[opcode]; + } + +event websocket_frame(c: connection, is_orig: bool, fin: bool, rsv: count, opcode: count, payload_len: count) + { + print "websocket_frame", c$uid, is_orig, "fin", fin, "rsv", rsv, "opcode", WebSocket::opcodes[opcode], "payload_len", payload_len; + } + +event websocket_frame_data(c: connection, is_orig: bool, data: string) + { + print "websocket_frame_data", c$uid, is_orig, "len", |data|, "data", data[:120]; + } + +event websocket_close(c: connection, is_orig: bool, status: count, reason: string) + { + print "websocket_close", c$uid, is_orig, "status", status, "reason", reason; + } diff --git a/testing/btest/scripts/base/protocols/websocket/jupyter-websocket.zeek b/testing/btest/scripts/base/protocols/websocket/jupyter-websocket.zeek new file mode 100644 index 0000000000..d7a62476ae --- /dev/null +++ b/testing/btest/scripts/base/protocols/websocket/jupyter-websocket.zeek @@ -0,0 +1,13 @@ +# @TEST-DOC: Testing Jupyter WebSocket traffic. +# +# @TEST-EXEC: zeek -b -r $TRACES/websocket/jupyter-websocket.pcap %INPUT +# +# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut +# +# @TEST-EXEC: btest-diff conn.log.cut +# @TEST-EXEC: btest-diff websocket.log +# @TEST-EXEC: test ! -f analyzer.log +# @TEST-EXEC: test ! -f weird.log + +@load base/protocols/conn +@load base/protocols/websocket diff --git a/testing/btest/scripts/base/protocols/websocket/key-accept-wrong.zeek b/testing/btest/scripts/base/protocols/websocket/key-accept-wrong.zeek new file mode 100644 index 0000000000..17aceb0ba7 --- /dev/null +++ b/testing/btest/scripts/base/protocols/websocket/key-accept-wrong.zeek @@ -0,0 +1,7 @@ +# @TEST-DOC: Test weird generation when the Sec-WebSocket-Accept socket isn't as expected. +# +# @TEST-EXEC: zeek -b -r $TRACES/websocket/wrong-accept-header.pcap %INPUT +# @TEST-EXEC: btest-diff websocket.log +# @TEST-EXEC: btest-diff weird.log + +@load base/protocols/websocket diff --git a/testing/btest/scripts/base/protocols/websocket/wstunnel-http.zeek b/testing/btest/scripts/base/protocols/websocket/wstunnel-http.zeek new file mode 100644 index 0000000000..5d676868a0 --- /dev/null +++ b/testing/btest/scripts/base/protocols/websocket/wstunnel-http.zeek @@ -0,0 +1,16 @@ +# @TEST-DOC: Test HTTP connection tunneled within WebSocket using wstunnel. Seems something in the HTTP scripts gets confused :-/ +# +# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-http.pcap %INPUT +# +# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut +# @TEST-EXEC: zeek-cut -m ts uid host uri status_code user_agent < http.log > http.log.cut + +# @TEST-EXEC: btest-diff conn.log.cut +# @TEST-EXEC: btest-diff http.log.cut +# @TEST-EXEC: btest-diff websocket.log +# @TEST-EXEC: test ! -f analyzer.log +# @TEST-EXEC: test ! -f weird.log + +@load base/protocols/conn +@load base/protocols/ssh +@load base/protocols/websocket diff --git a/testing/btest/scripts/base/protocols/websocket/wstunnel-https.zeek b/testing/btest/scripts/base/protocols/websocket/wstunnel-https.zeek new file mode 100644 index 0000000000..3212023b87 --- /dev/null +++ b/testing/btest/scripts/base/protocols/websocket/wstunnel-https.zeek @@ -0,0 +1,16 @@ +# @TEST-DOC: Test SSH connection tunneled within WebSocket using wstunnel. +# +# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-https.pcap %INPUT +# +# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut +# @TEST-EXEC: zeek-cut -m ts uid version server_name ssl_history < ssl.log > ssl.log.cut + +# @TEST-EXEC: btest-diff conn.log.cut +# @TEST-EXEC: btest-diff ssl.log.cut +# @TEST-EXEC: btest-diff websocket.log +# @TEST-EXEC: test ! -f analyzer.log +# @TEST-EXEC: test ! -f weird.log + +@load base/protocols/conn +@load base/protocols/ssl +@load base/protocols/websocket diff --git a/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh-configure-break.zeek b/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh-configure-break.zeek new file mode 100644 index 0000000000..9a9354f01d --- /dev/null +++ b/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh-configure-break.zeek @@ -0,0 +1,33 @@ +# @TEST-DOC: Test that breaking from configure_analyzer() removes the attached analyzer. +# +# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-ssh.pcap %INPUT >out 2>&1 +# +# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut + +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: btest-diff conn.log.cut +# @TEST-EXEC: btest-diff websocket.log +# @TEST-EXEC: test ! -f ssh.log +# @TEST-EXEC: test ! -f analyzer.log + +@load base/protocols/conn +@load base/protocols/http +@load base/protocols/ssh +@load base/protocols/websocket + +hook WebSocket::configure_analyzer(c: connection, aid: count, config: WebSocket::AnalyzerConfig) + { + print "WebSocket::configure_analyzer", c$uid, aid; + break; + } + +# These should never be raised +event websocket_message(c: connection, is_orig: bool, opcode: count) + { + print "ERROR: websocket_message", c$uid, is_orig, "opcode", WebSocket::opcodes[opcode]; + } + +hook Analyzer::disabling_analyzer(c: connection, atype: AllAnalyzers::Tag, aid: count) + { + print "disabling_analyzer", c$uid, atype, aid; + } diff --git a/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh-configure-wrong.zeek b/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh-configure-wrong.zeek new file mode 100644 index 0000000000..bbcba7683a --- /dev/null +++ b/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh-configure-wrong.zeek @@ -0,0 +1,21 @@ +# @TEST-DOC: Test SSH connection tunneled within WebSocket using wstunnel, attaches HTTP analyzer instead of SSH. +# +# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-ssh.pcap %INPUT +# +# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut + +# @TEST-EXEC: btest-diff conn.log.cut +# @TEST-EXEC: btest-diff websocket.log +# @TEST-EXEC: test ! -f ssh.log +# @TEST-EXEC: test ! -f analyzer.log + +@load base/protocols/conn +@load base/protocols/http +@load base/protocols/ssh +@load base/protocols/websocket + +hook WebSocket::configure_analyzer(c: connection, aid: count, config: WebSocket::AnalyzerConfig) + { + print "WebSocket::configure_analyzer", c$uid, aid; + config$analyzer = Analyzer::ANALYZER_HTTP; # this is obviously wrong :-) + } diff --git a/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh-configure.zeek b/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh-configure.zeek new file mode 100644 index 0000000000..560e9694a8 --- /dev/null +++ b/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh-configure.zeek @@ -0,0 +1,22 @@ +# @TEST-DOC: Test SSH connection tunneled within WebSocket using wstunnel, configure SSH analyzer via hook explicitly. +# +# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-ssh.pcap %INPUT +# +# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut +# @TEST-EXEC: zeek-cut -m ts uid client server auth_success auth_attempts kex_alg host_key_alg < ssh.log > ssh.log.cut + +# @TEST-EXEC: btest-diff conn.log.cut +# @TEST-EXEC: btest-diff ssh.log.cut +# @TEST-EXEC: btest-diff websocket.log +# @TEST-EXEC: test ! -f analyzer.log +# @TEST-EXEC: test ! -f weird.log + +@load base/protocols/conn +@load base/protocols/ssh +@load base/protocols/websocket + +hook WebSocket::configure_analyzer(c: connection, aid: count, config: WebSocket::AnalyzerConfig) + { + print "WebSocket::configure_analyzer", c$uid, aid; + config$analyzer = Analyzer::ANALYZER_SSH; + } diff --git a/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh-disabled.zeek b/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh-disabled.zeek new file mode 100644 index 0000000000..73759666bf --- /dev/null +++ b/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh-disabled.zeek @@ -0,0 +1,19 @@ +# @TEST-DOC: Test no analysis of tunneled WebSocket when the analyzer is globally disabled. +# +# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-ssh.pcap %INPUT +# +# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut + +# @TEST-EXEC: btest-diff conn.log.cut +# @TEST-EXEC: test ! -f websocket.log +# @TEST-EXEC: test ! -f ssh.log +# @TEST-EXEC: test ! -f analyzer.log +# @TEST-EXEC: test ! -f weird.log + +@load base/protocols/conn +@load base/protocols/ssh +@load base/protocols/websocket + +redef Analyzer::disabled_analyzers += { + Analyzer::ANALYZER_WEBSOCKET, +}; diff --git a/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh.zeek b/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh.zeek new file mode 100644 index 0000000000..02f445ed6c --- /dev/null +++ b/testing/btest/scripts/base/protocols/websocket/wstunnel-ssh.zeek @@ -0,0 +1,16 @@ +# @TEST-DOC: Test SSH connection tunneled within WebSocket using wstunnel. +# +# @TEST-EXEC: zeek -b -r $TRACES/websocket/wstunnel-ssh.pcap %INPUT +# +# @TEST-EXEC: zeek-cut -m ts uid history service < conn.log > conn.log.cut +# @TEST-EXEC: zeek-cut -m ts uid client server auth_success auth_attempts kex_alg host_key_alg < ssh.log > ssh.log.cut + +# @TEST-EXEC: btest-diff conn.log.cut +# @TEST-EXEC: btest-diff ssh.log.cut +# @TEST-EXEC: btest-diff websocket.log +# @TEST-EXEC: test ! -f analyzer.log +# @TEST-EXEC: test ! -f weird.log + +@load base/protocols/conn +@load base/protocols/ssh +@load base/protocols/websocket