]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2126 in SNORT/snort3 from ~KATHARVE/snort3:connect_pt1 to master
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Tue, 7 Apr 2020 20:54:41 +0000 (20:54 +0000)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Tue, 7 Apr 2020 20:54:41 +0000 (20:54 +0000)
Squashed commit of the following:

commit e76efdd1ed2708467d1ffe895f238e986d5414b9
Author: Katura Harvey <katharve@cisco.com>
Date:   Mon Mar 30 14:58:36 2020 -0400

    http_inspect: enhance processing of connect messages

src/service_inspectors/http_inspect/http_enum.h
src/service_inspectors/http_inspect/http_flow_data.h
src/service_inspectors/http_inspect/http_msg_header.cc
src/service_inspectors/http_inspect/http_msg_request.cc
src/service_inspectors/http_inspect/http_stream_splitter_scan.cc
src/service_inspectors/http_inspect/http_tables.cc

index 3fc8a0106eda25c701b585da58ce4d539b121496..56b6df7b88a64a8823d73cf5a1273a729f59f8a3 100644 (file)
@@ -230,6 +230,11 @@ enum Infraction
     INF_H2_NON_IDENTITY_TE,
     INF_H2_DATA_OVERRUNS_CL,
     INF_H2_DATA_UNDERRUNS_CL,
+    INF_CONNECT_REQUEST_BODY,
+    INF_EARLY_C2S_TRAFFIC_AFTER_CONNECT,
+    INF_200_CONNECT_RESP_WITH_CL,
+    INF_200_CONNECT_RESP_WITH_TE,
+    INF_100_CONNECT_RESP,
     INF__MAX_VALUE
 };
 
@@ -346,11 +351,16 @@ enum EventSid
     EVENT_206_WITHOUT_RANGE,
     EVENT_VERSION_NOT_UPPERCASE,
     EVENT_BAD_HEADER_WHITESPACE,
-    EVENT_GZIP_EARLY_END,                  // 248
+    EVENT_GZIP_EARLY_END,
     EVENT_EXCESS_REPEAT_PARAMS,
-    EVENT_H2_NON_IDENTITY_TE,
+    EVENT_H2_NON_IDENTITY_TE,              // 250
     EVENT_H2_DATA_OVERRUNS_CL,
     EVENT_H2_DATA_UNDERRUNS_CL,
+    EVENT_CONNECT_REQUEST_BODY,
+    EVENT_EARLY_C2S_TRAFFIC_AFTER_CONNECT,
+    EVENT_200_CONNECT_RESP_WITH_CL,
+    EVENT_200_CONNECT_RESP_WITH_TE,
+    EVENT_100_CONNECT_RESP,                // 257
     EVENT__MAX_VALUE
 };
 
index e0068cb997b6bcf9206c440c4a3e662bd36c0cbc..7846ba1bd486621741370eedb1219e65062984b5 100644 (file)
@@ -113,6 +113,7 @@ private:
     int32_t num_head_lines[2] = { HttpCommon::STAT_NOT_PRESENT, HttpCommon::STAT_NOT_PRESENT };
     bool tcp_close[2] = { false, false };
     bool partial_flush[2] = { false, false };
+    uint64_t last_connect_trans_w_early_traffic = 0;
 
     HttpInfractions* infractions[2] = { new HttpInfractions, new HttpInfractions };
     HttpEventGen* events[2] = { new HttpEventGen, new HttpEventGen };
@@ -126,6 +127,7 @@ private:
 
     // *** Inspector => StreamSplitter (facts about the message section that is coming next)
     HttpEnums::SectionType type_expected[2] = { HttpEnums::SEC_REQUEST, HttpEnums::SEC_STATUS };
+    uint64_t last_request_was_connect = false;
     // length of the data from Content-Length field
     z_stream* compress_stream[2] = { nullptr, nullptr };
     uint64_t zero_nine_expected = 0;
index 6a558715890de502273df2e4d3d2419e2c280983..e8f0def5c0a90f99266ec9f0c93e407f74c3c15c 100644 (file)
@@ -165,6 +165,38 @@ void HttpMsgHeader::update_flow()
         return;
     }
 
+    if ((source_id == SRC_SERVER) && request && (request->get_method_id() == METH_CONNECT) &&
+        !session_data->for_http2)
+    {
+        // Successful CONNECT responses (2XX) switch to tunneled traffic immediately following the
+        // header. Transfer-Encoding and Content-Length headers are not allowed in successful
+        // responses by the RFC.
+        if(((session_data->last_connect_trans_w_early_traffic == 0) ||
+            (trans_num > session_data->last_connect_trans_w_early_traffic)) &&
+            ((status_code_num >= 200) && (status_code_num < 300)))
+        {
+            if ((get_header_count(HEAD_TRANSFER_ENCODING) > 0))
+            {
+                add_infraction(INF_200_CONNECT_RESP_WITH_TE);
+                create_event(EVENT_200_CONNECT_RESP_WITH_TE);
+            }
+            if (get_header_count(HEAD_CONTENT_LENGTH) > 0)
+            {
+                add_infraction(INF_200_CONNECT_RESP_WITH_CL);
+                create_event(EVENT_200_CONNECT_RESP_WITH_CL);
+            }
+            // Temporary - Further traffic on this flow is tunneled traffic, and will get sent back
+            // to the wizard to determine the appropriate inspector. For now just abort.
+            session_data->type_expected[source_id] = SEC_ABORT;
+            return;
+        }
+        if ((status_code_num >= 100) && (status_code_num < 200))
+        {
+            add_infraction(INF_100_CONNECT_RESP);
+            create_event(EVENT_100_CONNECT_RESP);
+        }
+    }
+
     if ((source_id == SRC_SERVER) &&
         ((100 <= status_code_num && status_code_num <= 199) || (status_code_num == 204) ||
         (status_code_num == 304)))
@@ -347,6 +379,13 @@ void HttpMsgHeader::prepare_body()
     if (source_id == SRC_CLIENT)
     {
         HttpModule::increment_peg_counts(PEG_REQUEST_BODY);
+
+        // Message bodies for CONNECT requests have no defined semantics
+        if ((method_id == METH_CONNECT) && !session_data->for_http2)
+        {
+            add_infraction(INF_CONNECT_REQUEST_BODY);
+            create_event(EVENT_CONNECT_REQUEST_BODY);
+        }
     }
 }
 
index c46c75d59f6a4ced51bc595deabfd84d4d342b64..63c60f70beefe183f242bdf221c7810127eab681 100644 (file)
@@ -293,6 +293,11 @@ void HttpMsgRequest::update_flow()
         return;
     }
 
+    if (method_id == METH_CONNECT)
+    {
+        session_data->last_request_was_connect = true;
+    }
+
     session_data->type_expected[source_id] = SEC_HEADER;
     session_data->version_id[source_id] = version_id;
     session_data->method_id = method_id;
index 6b1f65ed620197dd1a1e1fe4812919c1700fae33..8176e43c92c5ef4a3118613e526fa2b0a841eef1 100644 (file)
@@ -193,6 +193,31 @@ StreamSplitter::Status HttpStreamSplitter::scan(Packet* pkt, const uint8_t* data
     }
 #endif
 
+    // If the last request was a CONNECT and we have not yet seen the response, this is early C2S
+    // traffic. If there has been a pipeline overflow or underflow we cannot match requests to
+    // responses, so there is no attempt to track early C2S traffic.
+    if ((source_id == SRC_CLIENT) && (type == SEC_REQUEST) && !session_data->for_http2 &&
+        session_data->last_request_was_connect)
+    {
+        const uint64_t last_request_trans_num = session_data->expected_trans_num[SRC_CLIENT] - 1;
+        const bool server_behind_connect =
+            (session_data->expected_trans_num[SRC_SERVER] < last_request_trans_num);
+        const bool server_expecting_connect_status =
+            ((session_data->expected_trans_num[SRC_SERVER] == last_request_trans_num)
+            && (session_data->type_expected[SRC_SERVER] == SEC_STATUS));
+        const bool pipeline_valid = !session_data->pipeline_overflow &&
+            !session_data->pipeline_underflow;
+
+        if ((server_behind_connect || server_expecting_connect_status) && pipeline_valid)
+        {
+            *session_data->get_infractions(source_id) += INF_EARLY_C2S_TRAFFIC_AFTER_CONNECT;
+            session_data->events[source_id]->create_event(EVENT_EARLY_C2S_TRAFFIC_AFTER_CONNECT);
+            session_data->last_connect_trans_w_early_traffic =
+                session_data->expected_trans_num[SRC_CLIENT] - 1;
+        }
+        session_data->last_request_was_connect = false;
+    }
+
     assert(!session_data->tcp_close[source_id]);
 
     HttpModule::increment_peg_counts(PEG_SCAN);
index 815bd184249da51b1c54033b3069704793cb90d7..b48c53214a88c1e1bc3b06fbe77f2bda75716450 100644 (file)
@@ -385,6 +385,12 @@ const RuleMap HttpModule::http_events[] =
                                         "value" },
     { EVENT_H2_DATA_UNDERRUNS_CL,       "HTTP/2 message body smaller than Content-Length header "
                                         "value" },
+    { EVENT_CONNECT_REQUEST_BODY,       "HTTP CONNECT request with a message body" },
+    { EVENT_EARLY_C2S_TRAFFIC_AFTER_CONNECT, "HTTP client-to-server traffic after CONNECT request "
+                                        "but before CONNECT response" },
+    { EVENT_200_CONNECT_RESP_WITH_CL,   "HTTP CONNECT 2XX response with Content-Length header" },
+    { EVENT_200_CONNECT_RESP_WITH_TE,   "HTTP CONNECT 2XX response with Transfer-Encoding header" },
+    { EVENT_100_CONNECT_RESP,           "HTTP CONNECT response with 1XX status code" },
     { 0, nullptr }
 };