diff --git a/CHANGES b/CHANGES index d6d94d4ea6..16b30355e2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,19 @@ +6.1.0-dev.358 | 2023-09-01 11:53:55 +0200 + + * GH-1705: http: Prevent request/response de-synchronization and unbounded state growth (Arne Welzel, Corelight) + + When http_reply events are received before http_request events, either + through faking traffic or possible re-ordering, it is possible to trigger + unbounded state growth due to later http_requests never being matched + again with responses. + + Prevent this by synchronizing request/response counters when late + requests come in. + + Also forcefully flush pending requests when http_replies are never + observed either due to the analyzer having been disabled or because + half-duplex traffic. + 6.1.0-dev.356 | 2023-08-30 11:24:51 +0200 * testing/external: Exclude telemetry.log from baselines (Arne Welzel, Corelight) diff --git a/NEWS b/NEWS index 4b92775fe1..6d01ded839 100644 --- a/NEWS +++ b/NEWS @@ -82,6 +82,11 @@ Changed Functionality anymore. Previously, broadcast packets originating from a likely server port resulted in 255.255.255.255 being the originator in ``conn.log``. +- When too many HTTP requests are pending, Zeek will now log them at once and + reset request/response correlation instead of running into unbounded state + growth. This behavior is configurable via a new option ``HTTP::max_pending_requests``. + The default is ``100``. + Removed Functionality --------------------- diff --git a/VERSION b/VERSION index 7172f4cd70..4c1fd50ab9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.1.0-dev.356 +6.1.0-dev.358 diff --git a/scripts/base/frameworks/notice/weird.zeek b/scripts/base/frameworks/notice/weird.zeek index 0511fc1e22..54527a2232 100644 --- a/scripts/base/frameworks/notice/weird.zeek +++ b/scripts/base/frameworks/notice/weird.zeek @@ -144,7 +144,9 @@ export { ["FTP_password_too_long"] = ACTION_LOG_PER_CONN, ["HTTP_bad_chunk_size"] = ACTION_LOG, ["HTTP_chunked_transfer_for_multipart_message"] = ACTION_LOG, + ["HTTP_excessive_pipelining"] = ACTION_LOG, ["HTTP_overlapping_messages"] = ACTION_LOG, + ["HTTP_response_before_request"] = ACTION_LOG, ["unknown_HTTP_method"] = ACTION_LOG, ["HTTP_version_mismatch"] = ACTION_LOG, ["ident_request_addendum"] = ACTION_LOG, diff --git a/scripts/base/protocols/http/main.zeek b/scripts/base/protocols/http/main.zeek index e0f0cdc0a0..0f65c6b984 100644 --- a/scripts/base/protocols/http/main.zeek +++ b/scripts/base/protocols/http/main.zeek @@ -133,6 +133,12 @@ export { ## HTTP finalization hook. Remaining HTTP info may get logged when it's called. global finalize_http: Conn::RemovalHook; + + ## Only allow that many pending requests on a single connection. + ## If this number is exceeded, all pending requests are flushed + ## out and request/response tracking reset to prevent unbounded + ## state growth. + option max_pending_requests = 100; } # Add the http state tracking fields to the connection record. @@ -205,6 +211,47 @@ event http_request(c: connection, method: string, original_URI: string, Conn::register_removal_hook(c, finalize_http); } + # Request/response tracking exists to account for HTTP pipelining. + # It fails if more responses have been seen than requests. If that + # happens, just fast-forward current_request such that the next + # response matches the in-flight request. + if ( c$http_state$current_request < c$http_state$current_response ) + { + Reporter::conn_weird("HTTP_response_before_request", c); + c$http_state$current_request = c$http_state$current_response; + } + + # Too many requests are pending for which we have not yet observed a + # reply. This might be due to excessive HTTP pipelining, one-sided + # traffic capture, or the responder side of the HTTP analyzer having + # been disabled. In any case, we simply log out all pending requests + # to make room for a new one. Any matching of pipelined requests and + # responses is most likely totally off anyhow. + if ( max_pending_requests > 0 && |c$http_state$pending| > max_pending_requests ) + { + Reporter::conn_weird("HTTP_excessive_pipelining", c); + + if ( c$http_state$current_response == 0 ) + ++c$http_state$current_response; + + while ( c$http_state$current_response < c$http_state$current_request ) + { + local cr = c$http_state$current_response; + if ( cr in c$http_state$pending ) + { + Log::write(HTTP::LOG, c$http_state$pending[cr]); + delete c$http_state$pending[cr]; + } + else + { + # The above should have been true... + # Reporter::error(fmt("Expected pending request at %d", cr)); + } + + ++c$http_state$current_response; + } + } + ++c$http_state$current_request; set_state(c, T); diff --git a/testing/btest/Baseline/plugins.hooks/output b/testing/btest/Baseline/plugins.hooks/output index 1acce5b4a1..ee21bb2757 100644 --- a/testing/btest/Baseline/plugins.hooks/output +++ b/testing/btest/Baseline/plugins.hooks/output @@ -559,6 +559,7 @@ 0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (HTTP::http_methods, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> 0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (HTTP::max_files_orig, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> 0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (HTTP::max_files_resp, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> +0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (HTTP::max_pending_requests, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> 0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (HTTP::proxy_headers, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> 0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (Input::default_mode, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> 0.000000 MetaHookPost CallFunction(Option::set_change_handler, , (Input::default_reader, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) -> @@ -2185,6 +2186,7 @@ 0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (HTTP::http_methods, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) 0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (HTTP::max_files_orig, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) 0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (HTTP::max_files_resp, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) +0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (HTTP::max_pending_requests, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) 0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (HTTP::proxy_headers, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) 0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (Input::default_mode, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) 0.000000 MetaHookPre CallFunction(Option::set_change_handler, , (Input::default_reader, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100)) @@ -3810,6 +3812,7 @@ 0.000000 | HookCallFunction Option::set_change_handler(HTTP::http_methods, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) 0.000000 | HookCallFunction Option::set_change_handler(HTTP::max_files_orig, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) 0.000000 | HookCallFunction Option::set_change_handler(HTTP::max_files_resp, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) +0.000000 | HookCallFunction Option::set_change_handler(HTTP::max_pending_requests, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) 0.000000 | HookCallFunction Option::set_change_handler(HTTP::proxy_headers, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) 0.000000 | HookCallFunction Option::set_change_handler(Input::default_mode, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) 0.000000 | HookCallFunction Option::set_change_handler(Input::default_reader, Config::config_option_changed{ if ( == Config::location) return (Config::new_value)Config::log = Config::Info($ts=network_time(), $id=Config::ID, $old_value=Config::format_value(lookup_ID(Config::ID)), $new_value=Config::format_value(Config::new_value))if ( != Config::location) Config::log$location = Config::locationLog::write(Config::LOG, to_any_coerceConfig::log)return (Config::new_value)}, -100) diff --git a/testing/btest/Baseline/scripts.base.protocols.http.http-09-content-length-confusion/http.log b/testing/btest/Baseline/scripts.base.protocols.http.http-09-content-length-confusion/http.log index 9bca082c7f..36fce1ce54 100644 --- a/testing/btest/Baseline/scripts.base.protocols.http.http-09-content-length-confusion/http.log +++ b/testing/btest/Baseline/scripts.base.protocols.http.http-09-content-length-confusion/http.log @@ -7,6 +7,6 @@ #open XXXX-XX-XX-XX-XX-XX #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p trans_depth method host uri referrer version user_agent origin request_body_len response_body_len status_code status_msg info_code info_msg tags username password proxied orig_fuids orig_filenames orig_mime_types resp_fuids resp_filenames resp_mime_types #types time string addr port addr port count string string string string string string string count count count string count string set[enum] string string set[string] vector[string] vector[string] vector[string] vector[string] vector[string] vector[string] -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46982 127.0.0.1 80 1 GET - / - 1.1 - - 0 0 200 OK - - (empty) - - - - - - - - - -XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46982 127.0.0.1 80 2 - - - - 0.9 - - 0 19 0 - - (empty) - - - - - - F7s8014qOBt9Gyy3w7 - text/plain +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46982 127.0.0.1 80 1 - - - - 1.1 - - 0 0 200 OK - - (empty) - - - - - - - - - +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46982 127.0.0.1 80 2 GET - / - 0.9 - - 0 19 0 - - (empty) - - - - - - F7s8014qOBt9Gyy3w7 - text/plain #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.http.http-09-content-length-confusion/weird.log b/testing/btest/Baseline/scripts.base.protocols.http.http-09-content-length-confusion/weird.log index b6c643871a..1e04819b2a 100644 --- a/testing/btest/Baseline/scripts.base.protocols.http.http-09-content-length-confusion/weird.log +++ b/testing/btest/Baseline/scripts.base.protocols.http.http-09-content-length-confusion/weird.log @@ -8,5 +8,6 @@ #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 46982 127.0.0.1 80 http_09_reply_before_request - F zeek HTTP +XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46982 127.0.0.1 80 HTTP_response_before_request - F zeek - XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 127.0.0.1 46982 127.0.0.1 80 HTTP_version_mismatch - F zeek HTTP #close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.http.http-desynched/http.log b/testing/btest/Baseline/scripts.base.protocols.http.http-desynched/http.log new file mode 100644 index 0000000000..c60072ec1d --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.http.http-desynched/http.log @@ -0,0 +1,17 @@ +### 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 http +#open XXXX-XX-XX-XX-XX-XX +#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p trans_depth method host uri referrer version user_agent origin request_body_len response_body_len status_code status_msg info_code info_msg tags username password proxied orig_fuids orig_filenames orig_mime_types resp_fuids resp_filenames resp_mime_types +#types time string addr port addr port count string string string string string string string count count count string count string set[enum] string string set[string] vector[string] vector[string] vector[string] vector[string] vector[string] vector[string] +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 50170 127.0.0.1 8080 1 GET localhost:8080 / - 1.1 python-requests/2.31.0 - 0 19 200 OK - - (empty) - - - - - - FlUDto3MxYxQV9pVnf - text/html +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 50170 127.0.0.1 8080 2 - - - - 1.1 - - 0 19 200 OK - - (empty) - - - - - - F7ynSw2U0QnJcw9Qth - text/html +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 50170 127.0.0.1 8080 3 - - - - 1.1 - - 0 19 200 OK - - (empty) - - - - - - FeY8eU1T8QwTaI0456 - text/html +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 50170 127.0.0.1 8080 4 GET localhost:8080 / - 1.1 python-requests/2.31.0 - 0 19 200 OK - - (empty) - - - - - - FfzjgM2OnUfAX9LnAd - text/html +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 50170 127.0.0.1 8080 5 GET localhost:8080 / - 1.1 python-requests/2.31.0 - 0 19 200 OK - - (empty) - - - - - - FtPJJF1xSxzd8blV4g - text/html +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 50170 127.0.0.1 8080 6 GET localhost:8080 / - 1.1 python-requests/2.31.0 - 0 19 200 OK - - (empty) - - - - - - FkCd8G2tsvSm17YOj6 - text/html +XXXXXXXXXX.XXXXXX ClEkJM2Vm5giqnMf4h 127.0.0.1 50170 127.0.0.1 8080 7 GET localhost:8080 / - 1.1 python-requests/2.31.0 - 0 19 200 OK - - (empty) - - - - - - FSa22J3bRk1Qv0hkE1 - text/html +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Baseline/scripts.base.protocols.http.http-pending-state-growth/out b/testing/btest/Baseline/scripts.base.protocols.http.http-pending-state-growth/out new file mode 100644 index 0000000000..c3e974e1b2 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.http.http-pending-state-growth/out @@ -0,0 +1,4 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +http_state pending, 100 +total http.log lines +1000 diff --git a/testing/btest/Baseline/scripts.base.protocols.http.http-pending-state-growth/weird.log b/testing/btest/Baseline/scripts.base.protocols.http.http-pending-state-growth/weird.log new file mode 100644 index 0000000000..0bdb746ff0 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.http.http-pending-state-growth/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 ::1 44730 ::1 80 HTTP_excessive_pipelining - F zeek - +#close XXXX-XX-XX-XX-XX-XX diff --git a/testing/btest/Traces/http/1000-requests-one-dropped-response.pcap.gz b/testing/btest/Traces/http/1000-requests-one-dropped-response.pcap.gz new file mode 100644 index 0000000000..6acd83b874 Binary files /dev/null and b/testing/btest/Traces/http/1000-requests-one-dropped-response.pcap.gz differ diff --git a/testing/btest/Traces/http/http-desync-request-response-5.pcap b/testing/btest/Traces/http/http-desync-request-response-5.pcap new file mode 100644 index 0000000000..5ff7821af2 Binary files /dev/null and b/testing/btest/Traces/http/http-desync-request-response-5.pcap differ diff --git a/testing/btest/scripts/base/protocols/http/http-desynched.zeek b/testing/btest/scripts/base/protocols/http/http-desynched.zeek new file mode 100644 index 0000000000..3661ed5085 --- /dev/null +++ b/testing/btest/scripts/base/protocols/http/http-desynched.zeek @@ -0,0 +1,13 @@ +# @TEST-DOC: 5 HTTP requests, the first one is responded to with 3 HTTP responses. +# +# @TEST-EXEC: zeek -b -r $TRACES/http/http-desync-request-response-5.pcap %INPUT +# @TEST-EXEC: btest-diff http.log + +@load base/protocols/http + +# mime type is irrelevant to this test, so filter it out +event zeek_init() + { + Log::remove_default_filter(HTTP::LOG); + Log::add_filter(HTTP::LOG, [$name="less-mime-types", $exclude=set("mime_type")]); + } diff --git a/testing/btest/scripts/base/protocols/http/http-pending-state-growth.zeek b/testing/btest/scripts/base/protocols/http/http-pending-state-growth.zeek new file mode 100644 index 0000000000..50afba1136 --- /dev/null +++ b/testing/btest/scripts/base/protocols/http/http-pending-state-growth.zeek @@ -0,0 +1,15 @@ +# @TEST-DOC: Pcap has a gap for the server side. This previously caused unbounded state growth in c$http_state$pending. +# +# @TEST-EXEC: zcat <$TRACES/http/1000-requests-one-dropped-response.pcap.gz | zeek -C -b -r - %INPUT >out +# @TEST-EXEC: echo "total http.log lines" >>out +# @TEST-EXEC: grep -v '^#' http.log | wc -l | sed 's/ //g' >>out +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: btest-diff weird.log + +@load base/protocols/http + +event connection_state_remove(c: connection) + { + if ( c?$http_state ) + print "http_state pending", |c$http_state$pending|; + }