]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2709 in SNORT/snort3 from ~MDAGON/snort3:settings to master
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Thu, 21 Jan 2021 13:40:16 +0000 (13:40 +0000)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Thu, 21 Jan 2021 13:40:16 +0000 (13:40 +0000)
Squashed commit of the following:

commit 40fdd7a388e51d4d2c8cdac04b79178989a6dea4
Author: mdagon <mdagon@cisco.com>
Date:   Tue Jan 12 16:57:13 2021 -0500

    payload_injector: inject settings frame

src/payload_injector/payload_injector.cc
src/payload_injector/payload_injector.h
src/payload_injector/payload_injector_translate_page.cc
src/payload_injector/test/payload_injector_test.cc
src/payload_injector/test/payload_injector_translate_test.cc
src/service_inspectors/http2_inspect/http2_flow_data.h
src/service_inspectors/http2_inspect/http2_settings_frame.cc

index 0afb93706937c953bfd192a3b03ca9853207453b..849a66989bdf8f2ff712b94c7e4f5096922d8acb 100644 (file)
@@ -78,7 +78,8 @@ InjectionReturnStatus PayloadInjector::inject_http2_payload(Packet* p,
         {
             uint8_t* http2_payload;
             uint32_t payload_len;
-            status = get_http2_payload(control, http2_payload, payload_len);
+            const bool send_settings = (session_data->was_server_settings_received() == false);
+            status = get_http2_payload(control, http2_payload, payload_len, send_settings);
             if (status == INJECTION_SUCCESS)
             {
                 p->active->send_data(p, df, http2_payload, payload_len);
index 009bb06620f1f179292e43aaad19ad4bf5370350..8bca77497a9f6b4979bfadab46f8e86a35f08241 100644 (file)
@@ -60,17 +60,20 @@ public:
 
 private:
     static InjectionReturnStatus inject_http2_payload(snort::Packet* p, const
-         InjectionControl& control, snort::EncodeFlags df);
+        InjectionControl& control, snort::EncodeFlags df);
 
 #ifdef UNIT_TEST
 
 public:
 #endif
-    static InjectionReturnStatus get_http2_payload(InjectionControl control, uint8_t*& http2_payload, uint32_t& payload_len);
+    static InjectionReturnStatus get_http2_payload(InjectionControl control,
+        uint8_t*& http2_payload, uint32_t& payload_len, bool send_settings);
 };
 
 #ifdef UNIT_TEST
-InjectionReturnStatus write_7_bit_prefix_int(uint32_t val, uint8_t*& out, uint32_t& out_free_space);
+InjectionReturnStatus write_7_bit_prefix_int(uint32_t val, uint8_t*& out,
+    uint32_t& out_free_space);
 #endif
 
 #endif
+
index 933a73d1cb4925002af8b5c740a9988e0b3c14ed..5c3d08d1a70c5ad0929de76b43bf263ed9cc8230 100644 (file)
@@ -52,6 +52,9 @@ static const char location[] = "Location: ";
 
 static const uint32_t max_hdr_size = 2000;
 
+// Empty settings frame
+static const uint8_t empty_settings_frame[] = { 0, 0, 0, FT_SETTINGS, 0, 0, 0, 0, 0 };
+
 static InjectionReturnStatus write_translation(uint8_t*& out, uint32_t& out_free_space,
     const uint8_t* translation, uint32_t size)
 {
@@ -245,7 +248,7 @@ static void write_frame_hdr(uint8_t*& out, uint32_t len, uint8_t type, uint8_t f
 }
 
 InjectionReturnStatus PayloadInjector::get_http2_payload(InjectionControl control,
-    uint8_t*& http2_payload, uint32_t& payload_len)
+    uint8_t*& http2_payload, uint32_t& payload_len, bool send_settings)
 {
     if (control.http_page == nullptr || control.http_page_len == 0)
         return ERR_PAGE_TRANSLATION;
@@ -263,9 +266,16 @@ InjectionReturnStatus PayloadInjector::get_http2_payload(InjectionControl contro
     if (body_len % (1<<14) != 0)
         num_data_frames++;
     payload_len = FRAME_HEADER_LENGTH*(num_data_frames + 1) + hdr_len + body_len;
+    if (send_settings)
+        payload_len += sizeof(empty_settings_frame);
     http2_payload = (uint8_t*)snort_alloc(payload_len);
 
     uint8_t* http2_payload_cur = http2_payload;
+    if (send_settings)
+    {
+        memcpy(http2_payload_cur, empty_settings_frame, sizeof(empty_settings_frame));
+        http2_payload_cur += sizeof(empty_settings_frame);
+    }
     write_frame_hdr(http2_payload_cur, hdr_len, FT_HEADERS, END_HEADERS, control.stream_id);
     memcpy(http2_payload_cur, http2_hdr, hdr_len);
     http2_payload_cur += hdr_len;
index d77efba24fdf81f121df68af9e381aaed06df193..db592eefe5c22aeedf23f9a6a23f527b5701e11a 100644 (file)
@@ -117,7 +117,7 @@ public:
 
 static InjectionReturnStatus translation_status = INJECTION_SUCCESS;
 InjectionReturnStatus PayloadInjector::get_http2_payload(InjectionControl,
-    uint8_t*& http2_payload, uint32_t& payload_len)
+    uint8_t*& http2_payload, uint32_t& payload_len, bool)
 {
     if (translation_status == INJECTION_SUCCESS)
     {
index d59eeb20d32778f8c2b35f30df39020487426d2b..b6cc1b75e995980faced297521a2b42a88a75221 100644 (file)
@@ -46,7 +46,7 @@ TEST(payload_injector_translate_test, basic_hdr_translation)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
     CHECK(status == INJECTION_SUCCESS);
 
     uint8_t out[] =
@@ -78,7 +78,7 @@ TEST(payload_injector_translate_test, basic_hdr_translation2)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == INJECTION_SUCCESS);
 
@@ -107,7 +107,7 @@ TEST(payload_injector_translate_test, basic_hdr_translation3)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == INJECTION_SUCCESS);
 
@@ -136,7 +136,7 @@ TEST(payload_injector_translate_test, mix_n_and_rn)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == INJECTION_SUCCESS);
 
@@ -164,7 +164,7 @@ TEST(payload_injector_translate_test, only_body)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_PAGE_TRANSLATION);
 }
@@ -178,7 +178,7 @@ TEST(payload_injector_translate_test, no_body)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_PAGE_TRANSLATION);
 }
@@ -192,7 +192,7 @@ TEST(payload_injector_translate_test, missing_last_rn)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_PAGE_TRANSLATION);
 }
@@ -206,7 +206,7 @@ TEST(payload_injector_translate_test, missing_space_after_colon)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_PAGE_TRANSLATION);
 }
@@ -220,7 +220,7 @@ TEST(payload_injector_translate_test, extra_space_before_colon)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_PAGE_TRANSLATION);
 }
@@ -234,7 +234,7 @@ TEST(payload_injector_translate_test, unsupported_status)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_PAGE_TRANSLATION);
 }
@@ -248,7 +248,7 @@ TEST(payload_injector_translate_test, unsupported_hdr)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_PAGE_TRANSLATION);
 }
@@ -261,7 +261,7 @@ TEST(payload_injector_translate_test, hdr_ends_wo_value)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_PAGE_TRANSLATION);
 }
@@ -274,7 +274,7 @@ TEST(payload_injector_translate_test, missing_value)
     control.stream_id = 1;
     control.http_page = (uint8_t*)http_page;
     control.http_page_len = strlen(http_page);
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_PAGE_TRANSLATION);
 }
@@ -292,7 +292,7 @@ TEST(payload_injector_translate_test, val_len1)
     control.stream_id = 1;
     control.http_page = http_page;
     control.http_page_len = size;
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == INJECTION_SUCCESS);
 
@@ -329,7 +329,7 @@ TEST(payload_injector_translate_test, val_len2)
     control.stream_id = 1;
     control.http_page = http_page;
     control.http_page_len = size;
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == INJECTION_SUCCESS);
     uint8_t out[] =
@@ -364,7 +364,7 @@ TEST(payload_injector_translate_test, val_len3)
     control.stream_id = 1;
     control.http_page = http_page;
     control.http_page_len = size;
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == INJECTION_SUCCESS);
 
@@ -440,7 +440,7 @@ TEST(payload_injector_translate_test, http2_hdr_is_max)
     control.http_page = http_page;
     control.http_page_len = size;
     control.stream_id = 0xf000;
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == INJECTION_SUCCESS);
     CHECK(payload_len == 2019);
@@ -472,7 +472,7 @@ TEST(payload_injector_translate_test, http2_hdr_too_big)
     control.stream_id = 1;
     control.http_page = http_page;
     control.http_page_len = size;
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_TRANSLATED_HDRS_SIZE);
 }
@@ -499,7 +499,7 @@ TEST(payload_injector_translate_test, http2_hdr_too_big3)
     control.stream_id = 1;
     control.http_page = http_page;
     control.http_page_len = size;
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_TRANSLATED_HDRS_SIZE);
 }
@@ -527,7 +527,7 @@ TEST(payload_injector_translate_test, http2_hdr_too_big4)
     control.stream_id = 1;
     control.http_page = http_page;
     control.http_page_len = size;
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_TRANSLATED_HDRS_SIZE);
 }
@@ -554,7 +554,7 @@ TEST(payload_injector_translate_test, http2_hdr_too_big5)
     control.stream_id = 1;
     control.http_page = http_page;
     control.http_page_len = size;
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
 
     CHECK(status == ERR_TRANSLATED_HDRS_SIZE);
 }
@@ -570,7 +570,7 @@ TEST(payload_injector_translate_test, payload_body_is_exactly_1_data_frame)
     control.stream_id = 1;
     control.http_page = http_page;
     control.http_page_len = size;
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
     CHECK(status == INJECTION_SUCCESS);
     // Headers frame header + status ok + data frame header
     uint8_t out[] = { 0, 0, 1, 1, 4, 0, 0, 0, 1, 0x88, 0, 0x40, 0, 0, 1, 0, 0, 0, 1 };
@@ -592,7 +592,7 @@ TEST(payload_injector_translate_test, payload_body_is_data_frame_plus_1)
     control.stream_id = 1;
     control.http_page = http_page;
     control.http_page_len = size;
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
     CHECK(status == INJECTION_SUCCESS);
     // Headers frame header + status ok + data frame header
     uint8_t out[] = { 0, 0, 1, 1, 4, 0, 0, 0, 1, 0x88, 0, 0x40, 0, 0, 0, 0, 0, 0, 1 };
@@ -611,7 +611,7 @@ TEST(payload_injector_translate_test, http_page_is_nullptr)
     InjectionControl control;
     control.http_page = nullptr;
     control.http_page_len = 1;
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
     CHECK(status == ERR_PAGE_TRANSLATION);
 }
 
@@ -622,7 +622,7 @@ TEST(payload_injector_translate_test, http_page_is_0_length)
     InjectionControl control;
     control.http_page = http_page;
     control.http_page_len = 0;
-    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len);
+    status = PayloadInjector::get_http2_payload(control, http2_payload, payload_len, false);
     CHECK(status == ERR_PAGE_TRANSLATION);
 }
 
index 932dcf2ac086b73c468236dc0485cd0c4a6636c9..a7e9c7baaa69f35cbd654b13fab960824e5c0d4e 100644 (file)
@@ -113,6 +113,14 @@ public:
     // frame into the S2C direction of an HTTP/2 flow.
     bool is_mid_frame() const;
 
+    // Used by payload injection to determine whether we should inject S2C settings frame 
+    // before injecting payload
+    bool was_server_settings_received() const
+    { return server_settings_frame_received; }
+
+    void set_server_settings_received()
+    { server_settings_frame_received = true; }
+
 #ifdef UNIT_TEST
     void set_mid_frame(bool); // Not implemented outside of unit tests
 #endif
@@ -140,6 +148,7 @@ protected:
     // them is the stream that http_inspect is actually processing at the moment.
     uint32_t stream_in_hi = Http2Enums::NO_STREAM_ID;
     HttpMsgSection* hi_msg_section = nullptr;
+    bool server_settings_frame_received = false;
 
     // Reassemble() data to eval()
     uint8_t lead_frame_header[2][Http2Enums::FRAME_HEADER_LENGTH];
index 9447131fac9c3ba4217a0eb68fd4c55b39fcd005..da0b0842731653c204c644bdba1644fa2b8c2e70 100644 (file)
@@ -61,6 +61,9 @@ Http2SettingsFrame::Http2SettingsFrame(const uint8_t* header_buffer, const uint3
     if (ACK & get_flags())
         return;
 
+    if (src_id == HttpCommon::SRC_SERVER && !ssn_data->was_server_settings_received())
+        ssn_data->set_server_settings_received();
+
     parse_settings_frame();
 }
 
@@ -94,9 +97,7 @@ bool Http2SettingsFrame::sanity_check()
     // FIXIT-E this next check should possibly be moved to valid_sequence()
     if (get_stream_id() != 0)
         bad_frame = true;
-    else if (!ack and ((data.length() <= 0) or ((data.length() % 6) != 0)))
-        bad_frame = true;
-    else if (ack and data.length() > 0)
+    else if (((data.length() % 6) != 0) or (ack and data.length() != 0))
         bad_frame = true;
 
     return !(bad_frame);