http2_hpack.h
http2_hpack_int_decode.cc
http2_hpack_int_decode.h
+ http2_hpack_table.cc
+ http2_hpack_table.h
http2_hpack_string_decode.cc
http2_hpack_string_decode.h
http2_huffman_state_machine.cc
EVENT_UNEXPECTED_CONTINUATION = 5,
EVENT_MISFORMATTED_HTTP2 = 6,
EVENT_PREFACE_MATCH_FAILURE = 7,
+ EVENT_HPACK_INDEX_DECODE_FAILURE = 8,
EVENT__MAX_VALUE
};
INF_HUFFMAN_INCOMPLETE_CODE_PADDING = 9,
INF_MISSING_CONTINUATION = 10,
INF_UNEXPECTED_CONTINUATION = 11,
+ INF_STATIC_TABLE_LOOKUP_ERROR = 12,
INF__MAX_VALUE
};
delete events[k];
}
}
+
+void Http2FlowData::clear_frame_data(HttpCommon::SourceId source_id)
+{
+ delete[] frame_header[source_id];
+ frame_header[source_id] = nullptr;
+ delete[] frame_data[source_id];
+ frame_data[source_id] = nullptr;
+ frame_in_detection = false;
+ delete[] http2_decoded_header[source_id];
+ http2_decoded_header[source_id] = nullptr;
+ continuation_expected[source_id] = false;
+ frames_aggregated[source_id] = 0;
+ header_octets_seen[source_id] = 0;
+}
Http2Infractions* infractions[2] = { new Http2Infractions, new Http2Infractions };
Http2EventGen* events[2] = { new Http2EventGen, new Http2EventGen };
+ void clear_frame_data(HttpCommon::SourceId source_id);
+
#ifdef REG_TEST
static uint64_t instance_count;
uint64_t seq_num;
Http2HpackIntDecode Http2Hpack::decode_int5(5);
Http2HpackIntDecode Http2Hpack::decode_int4(4);
Http2HpackStringDecode Http2Hpack::decode_string;
+Http2HpackTable Http2Hpack::table;
bool Http2Hpack::write_decoded_headers(Http2FlowData* session_data, HttpCommon::SourceId source_id,
const uint8_t* in_buffer, const uint32_t in_length,
return true;
}
+bool Http2Hpack::decode_static_table_index(Http2FlowData* session_data,
+ HttpCommon::SourceId source_id, const uint64_t index, const bool decode_full_line,
+ uint8_t* decoded_header_buffer, const uint32_t decoded_header_length,
+ uint32_t& bytes_written)
+{
+ uint32_t local_bytes_written = 0;
+ const Http2HpackTable::TableEntry* const entry = table.lookup(index);
+ bytes_written = 0;
+
+ // FIXIT-H check if header is part of start-line, if so pass to start-line generating
+ // object and don't write to decoded header buffer
+
+ // Write header name + ': ' to decoded headers
+ // FIXIT-H For now pseudo-headers are also copied. Need to be converted to start-line
+ if (!write_decoded_headers(session_data, source_id, (const uint8_t*) entry->name,
+ strlen(entry->name), decoded_header_buffer, decoded_header_length,
+ local_bytes_written))
+ return false;
+ bytes_written += local_bytes_written;
+ if (!write_decoded_headers(session_data, source_id, (const uint8_t*)": ", 2,
+ decoded_header_buffer + bytes_written, decoded_header_length - bytes_written,
+ local_bytes_written))
+ return false;
+ bytes_written += local_bytes_written;
+
+ if (decode_full_line)
+ {
+ if (strlen(entry->value) == 0)
+ {
+ *session_data->infractions[source_id] += INF_STATIC_TABLE_LOOKUP_ERROR;
+ session_data->events[source_id]->create_event(EVENT_HPACK_INDEX_DECODE_FAILURE);
+ return false;
+ }
+ if (!write_decoded_headers(session_data, source_id, (const uint8_t*)entry->value,
+ strlen(entry->value), decoded_header_buffer + bytes_written,
+ decoded_header_length - bytes_written, local_bytes_written))
+ return false;
+ bytes_written += local_bytes_written;
+ if (!write_decoded_headers(session_data, source_id, (const uint8_t*)"\r\n", 2,
+ decoded_header_buffer + bytes_written, decoded_header_length -
+ bytes_written, local_bytes_written))
+ return false;
+ bytes_written += local_bytes_written;
+ }
+
+ return true;
+}
+
+
// FIXIT-H Will be incrementally updated to actually decode indexes. For now just copies encoded
// index directly to decoded_header_buffer
bool Http2Hpack::decode_index(Http2FlowData* session_data, HttpCommon::SourceId source_id,
const uint8_t* encoded_header_buffer, const uint32_t encoded_header_length,
- const Http2HpackIntDecode &decode_int, uint32_t &bytes_consumed,
- uint8_t* decoded_header_buffer, const uint32_t decoded_header_length,
- uint32_t &bytes_written)
+ const Http2HpackIntDecode &decode_int, const bool decode_full_line, uint32_t &bytes_consumed,
+ uint8_t* decoded_header_buffer, const uint32_t decoded_header_length, uint32_t &bytes_written)
{
uint64_t index;
bytes_written = 0;
}
if (index <= STATIC_TABLE_MAX_INDEX)
- decode_static_table_index();
+ return decode_static_table_index(session_data, source_id, index, decode_full_line,
+ decoded_header_buffer, decoded_header_length, bytes_written);
else
- decode_dynamic_table_index();
-
- if (!Http2Hpack::write_decoded_headers(session_data, source_id, encoded_header_buffer,
- bytes_consumed, decoded_header_buffer, decoded_header_length, bytes_written))
- return false;
-
- return true;
+ return Http2Hpack::write_decoded_headers(session_data, source_id, encoded_header_buffer,
+ bytes_consumed, decoded_header_buffer, decoded_header_length, bytes_written);
}
bool Http2Hpack::decode_literal_header_line(Http2FlowData* session_data,
if (encoded_header_buffer[0] & name_index_mask)
{
if (!Http2Hpack::decode_index(session_data, source_id, encoded_header_buffer,
- encoded_header_length, decode_int, partial_bytes_consumed,
+ encoded_header_length, decode_int, false, partial_bytes_consumed,
decoded_header_buffer, decoded_header_length, partial_bytes_written))
return false;
}
// indexed header representation
if (encoded_header_buffer[0] & index_mask)
return Http2Hpack::decode_index(session_data, source_id, encoded_header_buffer,
- encoded_header_length, decode_int7, bytes_consumed,
+ encoded_header_length, decode_int7, true, bytes_consumed,
decoded_header_buffer, decoded_header_length, bytes_written);
// literal header representation to be added to dynamic table
#include "http2_hpack_int_decode.h"
#include "http2_hpack_string_decode.h"
+#include "http2_hpack_table.h"
class Http2FlowData;
uint32_t &bytes_written);
static bool decode_index(Http2FlowData* session_data, HttpCommon::SourceId source_id,
const uint8_t* encoded_header_buffer, const uint32_t encoded_header_length,
- const Http2HpackIntDecode &decode_int, uint32_t &bytes_consumed,
+ const Http2HpackIntDecode &decode_int,const bool decode_full_line, uint32_t &bytes_consumed,
uint8_t* decoded_header_buffer, const uint32_t decoded_header_length,
uint32_t &bytes_written);
static bool handle_dynamic_size_update(Http2FlowData* session_data,
HttpCommon::SourceId source_id, const uint8_t* encoded_header_buffer,
const uint32_t encoded_header_length, const Http2HpackIntDecode &decode_int,
uint32_t &bytes_consumed, uint32_t &bytes_written);
- static bool decode_static_table_index(void) { return false; }
- static bool decode_dynamic_table_index(void) { return false; }
+ static bool decode_static_table_index(Http2FlowData* session_data,
+ HttpCommon::SourceId source_id, const uint64_t index, const bool decode_full_line,
+ uint8_t* decoded_header_buffer, const uint32_t decoded_header_length,
+ uint32_t& bytes_written);
+ static bool decode_dynamic_table_index(void) { return true; }
static const int STATIC_TABLE_MAX_INDEX = 61;
static Http2HpackStringDecode decode_string;
// FIXIT-H Dictionary class and object go here
+ static Http2HpackTable table; //static until dynamic table is implemented
};
#endif
uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t&
bytes_written, Http2EventGen* events, Http2Infractions* infractions) const;
bool get_next_byte(const uint8_t* in_buff, const uint32_t last_byte,
- uint32_t& bytes_consumed, uint8_t& cur_bit, uint8_t match_len, uint8_t& byte,
+ uint32_t& bytes_consumed, uint8_t& cur_bit, uint8_t match_len, uint8_t& byte,
bool& another_search) const;
const Http2HpackIntDecode decode7;
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// http2_hpack_table.cc author Katura Harvey <katharve@cisco.com>
+
+#include "http2_hpack_table.h"
+
+#include <cassert>
+
+const Http2HpackTable::TableEntry Http2HpackTable::table[STATIC_MAX_INDEX + 1] =
+{
+ {"", ""},
+ {":authority", ""},
+ {":method", "GET"},
+ {":method", "POST"},
+ {":path", "/"},
+ {":path", "/index.html"},
+ {":scheme", "http"},
+ {":scheme", "https"},
+ {":status", "200"},
+ {":status", "204"},
+ {":status", "206"},
+ {":status", "304"},
+ {":status", "400"},
+ {":status", "404"},
+ {":status", "500"},
+ {"accept-charset", ""},
+ {"accept-encoding", "gzip, deflate"},
+ {"accept-language", ""},
+ {"accept-ranges", ""},
+ {"accept", ""},
+ {"access-control-allow-origin", ""},
+ {"age", ""},
+ {"allow", ""},
+ {"authorization", ""},
+ {"cache-control", ""},
+ {"content-disposition", ""},
+ {"content-encoding", ""},
+ {"content-language", ""},
+ {"content-length", ""},
+ {"content-location", ""},
+ {"content-range", ""},
+ {"content-type", ""},
+ {"cookie", ""},
+ {"date", ""},
+ {"etag", ""},
+ {"expect", ""},
+ {"expires", ""},
+ {"from", ""},
+ {"host", ""},
+ {"if-match", ""},
+ {"if-modified-since", ""},
+ {"if-none-match", ""},
+ {"if-range", ""},
+ {"if-unmodified-since", ""},
+ {"last-modified", ""},
+ {"link", ""},
+ {"location", ""},
+ {"max-forwards", ""},
+ {"proxy-authenticate", ""},
+ {"proxy-authorization", ""},
+ {"range", ""},
+ {"referer", ""},
+ {"refresh", ""},
+ {"retry-after", ""},
+ {"server", ""},
+ {"set-cookie", ""},
+ {"strict-transport-security", ""},
+ {"transfer-encoding", ""},
+ {"user-agent", ""},
+ {"vary", ""},
+ {"via", ""},
+ {"www-authenticate", ""},
+};
+
+const Http2HpackTable::TableEntry* Http2HpackTable::lookup(uint64_t index)
+{
+ assert(index <= STATIC_MAX_INDEX);
+ return &table[index];
+}
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+// http2_hpack_table.h author Katura Harvey <katharve@cisco.com>
+
+#ifndef HTTP2_HPACK_TABLE_H
+#define HTTP2_HPACK_TABLE_H
+
+#include <cstdint>
+
+#define STATIC_MAX_INDEX 61
+
+// Only static table is implemented. lookup() will be extended to support dynamic table
+// lookups once dynamic table is implemented
+class Http2HpackTable
+{
+public:
+ struct TableEntry
+ {
+ const char *name;
+ const char *value;
+ };
+
+ const static TableEntry* lookup(uint64_t index);
+
+private:
+ const static TableEntry table[STATIC_MAX_INDEX + 1];
+};
+
+#endif
{8, (char)236, HUFFMAN_MATCH}, {8, (char)237, HUFFMAN_MATCH},
{8, 0, HUFFMAN_LOOKUP_6}, {8, 0, HUFFMAN_LOOKUP_7},
{8, 0, HUFFMAN_LOOKUP_8}, {8, 0, HUFFMAN_LOOKUP_9},
- {8, 0, HUFFMAN_LOOKUP_10}, {8, 0, HUFFMAN_LOOKUP_11},
+ {8, 0, HUFFMAN_LOOKUP_10}, {8, 0, HUFFMAN_LOOKUP_11},
{8, 0, HUFFMAN_LOOKUP_12}, {8, 0, HUFFMAN_LOOKUP_13},
- {8, 0, HUFFMAN_LOOKUP_14}, {8, 0, HUFFMAN_LOOKUP_15}
+ {8, 0, HUFFMAN_LOOKUP_14}, {8, 0, HUFFMAN_LOOKUP_15}
},
{ // HUFFMAN_LOOKUP_6
// 0
{2, (char)200, HUFFMAN_MATCH}, {2, (char)200, HUFFMAN_MATCH},
{2, (char)200, HUFFMAN_MATCH}, {2, (char)200, HUFFMAN_MATCH},
{2, (char)200, HUFFMAN_MATCH}, {2, (char)200, HUFFMAN_MATCH},
- // 11
+ // 11
{2, (char)201, HUFFMAN_MATCH}, {2, (char)201, HUFFMAN_MATCH},
{2, (char)201, HUFFMAN_MATCH}, {2, (char)201, HUFFMAN_MATCH},
{2, (char)201, HUFFMAN_MATCH}, {2, (char)201, HUFFMAN_MATCH},
{2, (char)210, HUFFMAN_MATCH}, {2, (char)210, HUFFMAN_MATCH},
{2, (char)210, HUFFMAN_MATCH}, {2, (char)210, HUFFMAN_MATCH},
{2, (char)210, HUFFMAN_MATCH}, {2, (char)210, HUFFMAN_MATCH},
- // 11
+ // 11
{2, (char)213, HUFFMAN_MATCH}, {2, (char)213, HUFFMAN_MATCH},
{2, (char)213, HUFFMAN_MATCH}, {2, (char)213, HUFFMAN_MATCH},
{2, (char)213, HUFFMAN_MATCH}, {2, (char)213, HUFFMAN_MATCH},
{2, (char)238, HUFFMAN_MATCH}, {2, (char)238, HUFFMAN_MATCH},
{2, (char)238, HUFFMAN_MATCH}, {2, (char)238, HUFFMAN_MATCH},
{2, (char)238, HUFFMAN_MATCH}, {2, (char)238, HUFFMAN_MATCH},
- // 11
+ // 11
{2, (char)240, HUFFMAN_MATCH}, {2, (char)240, HUFFMAN_MATCH},
{2, (char)240, HUFFMAN_MATCH}, {2, (char)240, HUFFMAN_MATCH},
{2, (char)240, HUFFMAN_MATCH}, {2, (char)240, HUFFMAN_MATCH},
(int) session_data->frame_data_size[source_id] : HttpCommon::STAT_NOT_PRESENT,
session_data->frame_data[source_id]).print(HttpTestManager::get_output_file(),
"Frame Data");
- if (HttpTestManager::use_test_input(HttpTestManager::IN_HTTP2))
+ if (HttpTestManager::use_test_input(HttpTestManager::IN_HTTP2))
{
printf("Finished processing section from test %" PRIi64 "\n",
HttpTestManager::get_test_number());
const SourceId source_id = (p->is_from_client()) ? SRC_CLIENT : SRC_SERVER;
- delete[] session_data->frame_header[source_id];
- session_data->frame_header[source_id] = nullptr;
- delete[] session_data->frame_data[source_id];
- session_data->frame_data[source_id] = nullptr;
- session_data->frame_in_detection = false;
- delete[] session_data->http2_decoded_header[source_id];
- session_data->http2_decoded_header[source_id] = nullptr;
- session_data->continuation_expected[source_id] = false;
- session_data->frames_aggregated[source_id] = 0;
- session_data->header_octets_seen[source_id] = 0;
+ session_data->clear_frame_data(source_id);
}
// FIXIT-H This will eventually be the decoded header buffer. Under development.
if (!Http2Hpack::decode_headers(session_data, source_id,
session_data->frame_data[source_id], session_data->frame_data_size[source_id]))
+ {
+ // Since this doesn't go to detection, clear() doesn't get called, so need to
+ // clear frame data from flow data directly
+ session_data->clear_frame_data(source_id);
return frame_buf;
+ }
}
}
// Return 0-length non-null buffer to stream which signals detection required, but don't
return V_GOOD;
}
-
{ EVENT_UNEXPECTED_CONTINUATION, "unexpected continuation frame"},
{ EVENT_MISFORMATTED_HTTP2, "misformatted HTTP/2 traffic"},
{ EVENT_PREFACE_MATCH_FAILURE, "HTTP/2 connection preface does not match"},
+ { EVENT_HPACK_INDEX_DECODE_FAILURE, "error in decoding HPACK indexed field"},
{ 0, nullptr }
};
SOURCES
../http2_flow_data.cc
../http2_hpack_int_decode.cc
+ ../http2_hpack_table.cc
../http2_hpack_string_decode.cc
../http2_huffman_state_machine.cc
../http2_stream_splitter_impl.cc
#include "service_inspectors/http2_inspect/http2_enum.h"
#include "service_inspectors/http2_inspect/http2_flow_data.h"
#include "service_inspectors/http2_inspect/http2_hpack_int_decode.h"
+#include "service_inspectors/http2_inspect/http2_hpack_table.h"
#include "service_inspectors/http2_inspect/http2_hpack_string_decode.h"
#include "service_inspectors/http2_inspect/http2_stream_splitter.h"