HTTP: Recognize and skip upgrade/websocket connections.

This adds a slight patch to the HTTP analyzer, which recognizez when a connection is
upgraded to a different protocol (using a 101 reply with a few specific headers being
set).

In this case, the analyzer stops further processing of the connection (which will
result in DPD errors) and raises a new event:

event http_connection_upgrade(c: connection, protocol: string);

Protocol contains the name of the protocol that is being upgraded to, as specified in
one of the header values.
This commit is contained in:
Johanna Amann 2017-08-04 07:04:28 -07:00
parent dbac2b1abb
commit eab80c8834
8 changed files with 122 additions and 42 deletions

View file

@ -822,6 +822,9 @@ HTTP_Analyzer::HTTP_Analyzer(Connection* conn)
connect_request = false;
pia = 0;
upgraded = false;
upgrade_connection = false;
upgrade_protocol.clear();
content_line_orig = new tcp::ContentLine_Analyzer(conn, true);
AddSupportAnalyzer(content_line_orig);
@ -879,6 +882,9 @@ void HTTP_Analyzer::DeliverStream(int len, const u_char* data, bool is_orig)
if ( TCP() && TCP()->IsPartial() )
return;
if ( upgraded )
return;
if ( pia )
{
// There will be a PIA instance if this connection has been identified
@ -1468,15 +1474,35 @@ void HTTP_Analyzer::ReplyMade(const int interrupted, const char* msg)
unanswered_requests.pop();
}
reply_code = 0;
if ( reply_reason_phrase )
{
Unref(reply_reason_phrase);
reply_reason_phrase = 0;
}
if ( interrupted )
// 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 )
{
val_list* vl = new val_list();
vl->append(BuildConnVal());
vl->append(new StringVal(upgrade_protocol));
ConnectionEvent(http_connection_upgrade, vl);
}
}
reply_code = 0;
upgrade_connection = false;
upgrade_protocol.clear();
if ( interrupted || upgraded )
reply_state = EXPECT_REPLY_NOTHING;
else
reply_state = EXPECT_REPLY_LINE;
@ -1611,11 +1637,17 @@ void HTTP_Analyzer::HTTP_Header(int is_orig, mime::MIME_Header* h)
if ( ! is_orig &&
mime::strcasecmp_n(h->get_name(), "connection") == 0 )
{
{
if ( mime::strcasecmp_n(h->get_value_token(), "close") == 0 )
connection_close = 1;
connection_close = 1;
else if ( mime::strcasecmp_n(h->get_value_token(), "upgrade") == 0 )
upgrade_connection = true;
}
if ( ! is_orig &&
mime::strcasecmp_n(h->get_name(), "upgrade") == 0 )
upgrade_protocol.assign(h->get_value_token().data, h->get_value_token().length);
if ( http_header )
{
Rule::PatternType rule =