mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
HTTP: Add mechanism to instantiate Upgrade analyzer
When a HTTP upgrade request/reply is detected, lookup an analyzer tag from HTTP::upgrade_analyzers, or if nothing is found, attach PIA_TCP.
This commit is contained in:
parent
b5f9e5a3b1
commit
8ebd054abc
3 changed files with 59 additions and 15 deletions
|
@ -423,7 +423,6 @@ export {
|
||||||
## The full list of TCP Option fields parsed from a TCP header.
|
## The full list of TCP Option fields parsed from a TCP header.
|
||||||
type OptionList: vector of Option;
|
type OptionList: vector of Option;
|
||||||
}
|
}
|
||||||
module GLOBAL;
|
|
||||||
|
|
||||||
module Tunnel;
|
module Tunnel;
|
||||||
export {
|
export {
|
||||||
|
@ -449,6 +448,16 @@ export {
|
||||||
const max_changes_per_connection: count = 5 &redef;
|
const max_changes_per_connection: count = 5 &redef;
|
||||||
|
|
||||||
} # end export
|
} # 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 GLOBAL;
|
module GLOBAL;
|
||||||
|
|
||||||
## A type alias for a vector of encapsulating "connections", i.e. for when
|
## A type alias for a vector of encapsulating "connections", i.e. for when
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "zeek/Event.h"
|
#include "zeek/Event.h"
|
||||||
#include "zeek/NetVar.h"
|
#include "zeek/NetVar.h"
|
||||||
|
#include "zeek/analyzer/Manager.h"
|
||||||
#include "zeek/analyzer/protocol/http/events.bif.h"
|
#include "zeek/analyzer/protocol/http/events.bif.h"
|
||||||
#include "zeek/analyzer/protocol/mime/MIME.h"
|
#include "zeek/analyzer/protocol/mime/MIME.h"
|
||||||
#include "zeek/file_analysis/Manager.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() )
|
if ( TCP() && TCP()->IsPartial() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( upgraded )
|
if ( upgraded || pia ) {
|
||||||
return;
|
|
||||||
|
|
||||||
if ( pia ) {
|
|
||||||
// There will be a PIA instance if this connection has been identified
|
// 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);
|
ForwardStream(len, data, is_orig);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1311,15 +1309,8 @@ void HTTP_Analyzer::ReplyMade(bool interrupted, const char* msg) {
|
||||||
reply_reason_phrase = nullptr;
|
reply_reason_phrase = nullptr;
|
||||||
|
|
||||||
// unanswered requests = 1 because there is no pop after 101.
|
// unanswered requests = 1 because there is no pop after 101.
|
||||||
if ( reply_code == 101 && unanswered_requests.size() == 1 && upgrade_connection && upgrade_protocol.size() ) {
|
if ( reply_code == 101 && unanswered_requests.size() == 1 && upgrade_connection && upgrade_protocol.size() )
|
||||||
// Upgraded connection that switches immediately - e.g. websocket.
|
HTTP_Upgrade();
|
||||||
upgraded = true;
|
|
||||||
RemoveSupportAnalyzer(content_line_orig);
|
|
||||||
RemoveSupportAnalyzer(content_line_resp);
|
|
||||||
|
|
||||||
if ( http_connection_upgrade )
|
|
||||||
EnqueueConnEvent(http_connection_upgrade, ConnVal(), make_intrusive<StringVal>(upgrade_protocol));
|
|
||||||
}
|
|
||||||
|
|
||||||
reply_code = 0;
|
reply_code = 0;
|
||||||
upgrade_connection = false;
|
upgrade_connection = false;
|
||||||
|
@ -1331,6 +1322,49 @@ void HTTP_Analyzer::ReplyMade(bool interrupted, const char* msg) {
|
||||||
reply_state = EXPECT_REPLY_LINE;
|
reply_state = EXPECT_REPLY_LINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTTP_Analyzer::HTTP_Upgrade() {
|
||||||
|
// Upgraded connection that switches immediately - e.g. websocket.
|
||||||
|
|
||||||
|
// Lookup an analyzer tag in the HTTP::upgrade_analyzer table.
|
||||||
|
static const auto& upgrade_analyzers = id::find_val<TableVal>("HTTP::upgrade_analyzers");
|
||||||
|
|
||||||
|
auto upgrade_protocol_val = make_intrusive<StringVal>(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<StringVal>(lower_upgrade_protocol);
|
||||||
|
v = upgrade_analyzers->Find(upgrade_protocol_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( v ) {
|
||||||
|
auto analyzer_tag_val = cast_intrusive<EnumVal>(v);
|
||||||
|
DBG_LOG(DBG_ANALYZER, "Found %s in HTTP::upgrade_analyzers for %s",
|
||||||
|
analyzer_tag_val->GetType<EnumType>()->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);
|
||||||
|
}
|
||||||
|
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<StringVal>(upgrade_protocol));
|
||||||
|
}
|
||||||
|
|
||||||
void HTTP_Analyzer::RequestClash(Val* /* clash_val */) {
|
void HTTP_Analyzer::RequestClash(Val* /* clash_val */) {
|
||||||
Weird("multiple_HTTP_request_elements");
|
Weird("multiple_HTTP_request_elements");
|
||||||
|
|
||||||
|
|
|
@ -220,6 +220,7 @@ protected:
|
||||||
|
|
||||||
void HTTP_Request();
|
void HTTP_Request();
|
||||||
void HTTP_Reply();
|
void HTTP_Reply();
|
||||||
|
void HTTP_Upgrade();
|
||||||
|
|
||||||
void RequestMade(bool interrupted, const char* msg);
|
void RequestMade(bool interrupted, const char* msg);
|
||||||
void ReplyMade(bool interrupted, const char* msg);
|
void ReplyMade(bool interrupted, const char* msg);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue