if (status != INJECTION_SUCCESS)
return status;
- const uint32_t body_len = control.http_page_len - body_offset;
- // FIXIT-E support larger body size
- if (body_len > 1<<14)
- return ERR_HTTP2_BODY_SIZE;
-
- payload_len = 2*FRAME_HEADER_LENGTH + hdr_len + body_len;
+ uint32_t body_len = control.http_page_len - body_offset;
+ uint32_t num_data_frames = body_len / (1<<14);
+ if (body_len % (1<<14) != 0)
+ num_data_frames++;
+ payload_len = FRAME_HEADER_LENGTH*(num_data_frames + 1) + hdr_len + body_len;
http2_payload = (uint8_t*)snort_alloc(payload_len);
uint8_t* http2_payload_cur = http2_payload;
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;
- write_frame_hdr(http2_payload_cur, body_len, FT_DATA, END_STREAM, control.stream_id);
- memcpy(http2_payload_cur, control.http_page + body_offset, body_len);
-
+ const uint8_t* http_body_cur = control.http_page + body_offset;
+ while (body_len)
+ {
+ const uint32_t cur_len = (body_len > 1<<14) ? 1<<14 : body_len;
+ body_len -= cur_len;
+ const uint8_t flags = (body_len == 0) ? END_STREAM : 0;
+ write_frame_hdr(http2_payload_cur, cur_len, FT_DATA, flags, control.stream_id);
+ memcpy(http2_payload_cur, http_body_cur, cur_len);
+ http2_payload_cur += cur_len;
+ http_body_cur += cur_len;
+ }
+ assert((http2_payload_cur - http2_payload) == payload_len);
return INJECTION_SUCCESS;
}
delete flow.gadget;
}
+TEST(payload_injector_test, flow_is_null)
+{
+ mod.set_configured(true);
+ Packet p(false);
+ p.packet_flags = PKT_STREAM_EST;
+ InjectionReturnStatus status = mod.inject_http_payload(&p, control);
+ CHECK(counts->http_injects == 0);
+ CHECK(status == ERR_UNIDENTIFIED_PROTOCOL);
+ const char* err_string = mod.get_err_string(status);
+ CHECK(strcmp(err_string, "Unidentified protocol") == 0);
+}
+
TEST_GROUP(payload_injector_translate_err_test)
{
PayloadInjectorModule mod;
"HTTP/2 translated header size is bigger than expected. Update max size.") == 0);
}
-TEST(payload_injector_translate_err_test, http2_body_size)
-{
- Packet p(false);
- p.packet_flags = PKT_STREAM_EST;
- p.flow = &flow;
- translation_status = ERR_HTTP2_BODY_SIZE;
- status = mod.inject_http_payload(&p, control);
- const char* err_string = mod.get_err_string(status);
- CHECK(strcmp(err_string, "HTTP/2 body is > 16k. Currently not supported.") == 0);
-}
-
int main(int argc, char** argv)
{
return CommandLineTestRunner::RunAllTests(argc, argv);
CHECK(status == ERR_TRANSLATED_HDRS_SIZE);
}
-TEST(payload_injector_translate_test, payload_body_larger_than_max)
+TEST(payload_injector_translate_test, payload_body_is_exactly_1_data_frame)
{
- static const uint32_t size = (1<<14) + 1 + strlen("HTTP/1.1 403 Forbidden\r\n\r\n");
+ static const uint32_t size = (1<<14) + strlen("HTTP/1.1 200 OK\r\n\r\n");
uint8_t http_page[size];
memset(http_page,'a',size);
- memcpy(http_page,"HTTP/1.1 403 Forbidden\r\n\r\n", strlen("HTTP/1.1 403 Forbidden\r\n\r\n"));
+ memcpy(http_page,"HTTP/1.1 200 OK\r\n\r\n", strlen("HTTP/1.1 200 OK\r\n\r\n"));
InjectionControl control;
control.stream_id = 1;
control.http_page = http_page;
control.http_page_len = size;
status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len);
- CHECK(status == ERR_HTTP2_BODY_SIZE);
+ 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 };
+ CHECK(memcmp(http2_payload, out, sizeof(out))==0);
+ // Data frame == http body
+ CHECK(memcmp(http2_payload + sizeof(out), http_page + strlen("HTTP/1.1 200 OK\r\n\r\n"),
+ 1<<14)==0);
+ snort_free(http2_payload);
+}
+
+TEST(payload_injector_translate_test, payload_body_is_data_frame_plus_1)
+{
+ static const uint32_t size = (1<<14) + 1 + strlen("HTTP/1.1 200 OK\r\n\r\n");
+ uint8_t http_page[size];
+ memset(http_page,'a',size);
+ memcpy(http_page,"HTTP/1.1 200 OK\r\n\r\n", strlen("HTTP/1.1 200 OK\r\n\r\n"));
+
+ InjectionControl control;
+ control.stream_id = 1;
+ control.http_page = http_page;
+ control.http_page_len = size;
+ status = PayloadInjectorModule::get_http2_payload(control, http2_payload, payload_len);
+ 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 };
+ CHECK(memcmp(http2_payload, out, sizeof(out))==0);
+ // First data frame
+ CHECK(memcmp(http2_payload + sizeof(out), http_page + strlen("HTTP/1.1 200 OK\r\n\r\n"),
+ 1<<14)==0);
+ // Second data frame header + 1 last byte of body
+ uint8_t out2[] = { 0, 0, 1, 0, 1, 0, 0, 0, 1, 'a' };
+ CHECK(memcmp(http2_payload + sizeof(out) + (1<<14), out2, sizeof(out2))==0);
+ snort_free(http2_payload);
}
TEST(payload_injector_translate_test, http_page_is_nullptr)
TEST(payload_injector_translate_test, 7_bit_int_min_max)
{
- uint8_t out[6];
- uint32_t out_free_space = sizeof(out);
-
- // Translate 0
- uint8_t* cur = out;
- InjectionReturnStatus status = write_7_bit_prefix_int(0, cur, out_free_space);
- uint8_t expected_out[] = {0};
- CHECK(status == INJECTION_SUCCESS);
- CHECK(out_free_space == 5);
- CHECK(memcmp(out, expected_out, 1) == 0);
-
- // Translate max uint_32
- cur = out;
- out_free_space = sizeof(out);
- status = write_7_bit_prefix_int(UINT32_MAX, cur, out_free_space);
- uint8_t expected_out2[] = {0x7f, 0x80, 0xff, 0xff, 0xff, 0xf};
- CHECK(status == INJECTION_SUCCESS);
- CHECK(out_free_space == 0);
- CHECK(memcmp(out, expected_out2, 6) == 0);
-}
+ uint8_t out[6];
+ uint32_t out_free_space = sizeof(out);
+ // Translate 0
+ uint8_t* cur = out;
+ InjectionReturnStatus status = write_7_bit_prefix_int(0, cur, out_free_space);
+ uint8_t expected_out[] = { 0 };
+ CHECK(status == INJECTION_SUCCESS);
+ CHECK(out_free_space == 5);
+ CHECK(memcmp(out, expected_out, 1) == 0);
+
+ // Translate max uint_32
+ cur = out;
+ out_free_space = sizeof(out);
+ status = write_7_bit_prefix_int(UINT32_MAX, cur, out_free_space);
+ uint8_t expected_out2[] = { 0x7f, 0x80, 0xff, 0xff, 0xff, 0xf };
+ CHECK(status == INJECTION_SUCCESS);
+ CHECK(out_free_space == 0);
+ CHECK(memcmp(out, expected_out2, 6) == 0);
+}
int main(int argc, char** argv)
{