nhttp_flow_data.h
nhttp_transaction.cc
nhttp_transaction.h
- nhttp_scratch_pad.h
nhttp_test_manager.cc
nhttp_test_manager.h
nhttp_enum.h
nhttp_transaction.cc nhttp_transaction.h \
nhttp_stream_splitter.cc nhttp_stream_splitter.h \
nhttp_cutter.cc nhttp_cutter.h \
-nhttp_scratch_pad.h \
nhttp_enum.h \
nhttp_test_manager.cc nhttp_test_manager.h \
nhttp_field.cc nhttp_field.h \
// Field status codes for when no valid value is present in length or integer value. Positive
// values are actual length or field value.
enum StatusCode { STAT_NO_SOURCE=-16, STAT_NOT_CONFIGURED=-15, STAT_NOT_COMPUTE=-14,
- STAT_INSUF_MEMORY=-13, STAT_PROBLEMATIC=-12, STAT_NOT_PRESENT=-11, STAT_EMPTY_STRING=0,
- STAT_OTHER=1 };
+ STAT_PROBLEMATIC=-12, STAT_NOT_PRESENT=-11, STAT_EMPTY_STRING=0, STAT_OTHER=1 };
// Message originator--client or server
enum SourceId { SRC__NOT_COMPUTE=-14, SRC_CLIENT=0, SRC_SERVER=1 };
VERS__NOT_PRESENT=-11, VERS__OTHER=1, VERS_1_0, VERS_1_1, VERS_2_0 };
// Every request method we have ever heard of
-enum MethodId { METH__NO_SOURCE=-16, METH__NOT_COMPUTE=-14, METH__INSUF_MEMORY=-13,
- METH__PROBLEMATIC=-12, METH__NOT_PRESENT=-11, METH__OTHER=1, METH_OPTIONS, METH_GET, METH_HEAD,
- METH_POST, METH_PUT, METH_DELETE, METH_TRACE, METH_CONNECT, METH_PROPFIND, METH_PROPPATCH,
- METH_MKCOL, METH_COPY, METH_MOVE, METH_LOCK, METH_UNLOCK, METH_VERSION_CONTROL, METH_REPORT,
- METH_CHECKOUT, METH_CHECKIN, METH_UNCHECKOUT, METH_MKWORKSPACE, METH_UPDATE, METH_LABEL,
- METH_MERGE, METH_BASELINE_CONTROL, METH_MKACTIVITY, METH_ORDERPATCH, METH_ACL, METH_PATCH,
- METH_SEARCH, METH_BCOPY, METH_BDELETE, METH_BMOVE, METH_BPROPFIND, METH_BPROPPATCH,
- METH_NOTIFY, METH_POLL, METH_SUBSCRIBE, METH_UNSUBSCRIBE, METH_X_MS_ENUMATTS, METH_BIND,
- METH_LINK, METH_MKCALENDAR, METH_MKREDIRECTREF, METH_REBIND, METH_UNBIND, METH_UNLINK,
- METH_UPDATEREDIRECTREF };
+enum MethodId { METH__NO_SOURCE=-16, METH__NOT_COMPUTE=-14, METH__PROBLEMATIC=-12,
+ METH__NOT_PRESENT=-11, METH__OTHER=1, METH_OPTIONS, METH_GET, METH_HEAD, METH_POST, METH_PUT,
+ METH_DELETE, METH_TRACE, METH_CONNECT, METH_PROPFIND, METH_PROPPATCH, METH_MKCOL, METH_COPY,
+ METH_MOVE, METH_LOCK, METH_UNLOCK, METH_VERSION_CONTROL, METH_REPORT, METH_CHECKOUT,
+ METH_CHECKIN, METH_UNCHECKOUT, METH_MKWORKSPACE, METH_UPDATE, METH_LABEL, METH_MERGE,
+ METH_BASELINE_CONTROL, METH_MKACTIVITY, METH_ORDERPATCH, METH_ACL, METH_PATCH, METH_SEARCH,
+ METH_BCOPY, METH_BDELETE, METH_BMOVE, METH_BPROPFIND, METH_BPROPPATCH, METH_NOTIFY, METH_POLL,
+ METH_SUBSCRIBE, METH_UNSUBSCRIBE, METH_X_MS_ENUMATTS, METH_BIND, METH_LINK, METH_MKCALENDAR,
+ METH_MKREDIRECTREF, METH_REBIND, METH_UNBIND, METH_UNLINK, METH_UPDATEREDIRECTREF };
// URI formats
enum UriType { URI__NOT_COMPUTE=-14, URI__PROBLEMATIC=-12, URI_ASTERISK = 2, URI_AUTHORITY,
enum UriComponent { UC_SCHEME = 1, UC_HOST, UC_PORT, UC_PATH, UC_QUERY, UC_FRAGMENT };
// Every header we have ever heard of
-enum HeaderId { HEAD__NOT_COMPUTE=-14, HEAD__INSUF_MEMORY=-13, HEAD__PROBLEMATIC=-12,
- HEAD__NOT_PRESENT=-11, HEAD__OTHER=1, HEAD_CACHE_CONTROL, HEAD_CONNECTION, HEAD_DATE,
- HEAD_PRAGMA, HEAD_TRAILER, HEAD_COOKIE, HEAD_SET_COOKIE, HEAD_TRANSFER_ENCODING, HEAD_UPGRADE,
- HEAD_VIA, HEAD_WARNING, HEAD_ACCEPT, HEAD_ACCEPT_CHARSET, HEAD_ACCEPT_ENCODING,
- HEAD_ACCEPT_LANGUAGE, HEAD_AUTHORIZATION, HEAD_EXPECT, HEAD_FROM, HEAD_HOST, HEAD_IF_MATCH,
- HEAD_IF_MODIFIED_SINCE, HEAD_IF_NONE_MATCH, HEAD_IF_RANGE, HEAD_IF_UNMODIFIED_SINCE,
- HEAD_MAX_FORWARDS, HEAD_PROXY_AUTHORIZATION, HEAD_RANGE, HEAD_REFERER, HEAD_TE,
- HEAD_USER_AGENT, HEAD_ACCEPT_RANGES, HEAD_AGE, HEAD_ETAG, HEAD_LOCATION,
- HEAD_PROXY_AUTHENTICATE, HEAD_RETRY_AFTER, HEAD_SERVER, HEAD_VARY, HEAD_WWW_AUTHENTICATE,
- HEAD_ALLOW, HEAD_CONTENT_ENCODING, HEAD_CONTENT_LANGUAGE, HEAD_CONTENT_LENGTH,
- HEAD_CONTENT_LOCATION, HEAD_CONTENT_MD5, HEAD_CONTENT_RANGE, HEAD_CONTENT_TYPE, HEAD_EXPIRES,
- HEAD_LAST_MODIFIED, HEAD_X_FORWARDED_FOR, HEAD_TRUE_CLIENT_IP, HEAD__MAX_VALUE };
+enum HeaderId { HEAD__NOT_COMPUTE=-14, HEAD__PROBLEMATIC=-12, HEAD__NOT_PRESENT=-11, HEAD__OTHER=1,
+ HEAD_CACHE_CONTROL, HEAD_CONNECTION, HEAD_DATE, HEAD_PRAGMA, HEAD_TRAILER, HEAD_COOKIE,
+ HEAD_SET_COOKIE, HEAD_TRANSFER_ENCODING, HEAD_UPGRADE, HEAD_VIA, HEAD_WARNING, HEAD_ACCEPT,
+ HEAD_ACCEPT_CHARSET, HEAD_ACCEPT_ENCODING, HEAD_ACCEPT_LANGUAGE, HEAD_AUTHORIZATION,
+ HEAD_EXPECT, HEAD_FROM, HEAD_HOST, HEAD_IF_MATCH, HEAD_IF_MODIFIED_SINCE, HEAD_IF_NONE_MATCH,
+ HEAD_IF_RANGE, HEAD_IF_UNMODIFIED_SINCE, HEAD_MAX_FORWARDS, HEAD_PROXY_AUTHORIZATION,
+ HEAD_RANGE, HEAD_REFERER, HEAD_TE, HEAD_USER_AGENT, HEAD_ACCEPT_RANGES, HEAD_AGE, HEAD_ETAG,
+ HEAD_LOCATION, HEAD_PROXY_AUTHENTICATE, HEAD_RETRY_AFTER, HEAD_SERVER, HEAD_VARY,
+ HEAD_WWW_AUTHENTICATE, HEAD_ALLOW, HEAD_CONTENT_ENCODING, HEAD_CONTENT_LANGUAGE,
+ HEAD_CONTENT_LENGTH, HEAD_CONTENT_LOCATION, HEAD_CONTENT_MD5, HEAD_CONTENT_RANGE,
+ HEAD_CONTENT_TYPE, HEAD_EXPIRES, HEAD_LAST_MODIFIED, HEAD_X_FORWARDED_FOR, HEAD_TRUE_CLIENT_IP,
+ HEAD__MAX_VALUE };
// All the infractions we might find while parsing and analyzing a message
enum Infraction
INF_BAD_STAT_CODE,
INF_UNKNOWN_VERSION,
INF_BAD_VERSION,
- INF_NO_SCRATCH,
- INF_BAD_HEADER_REPS,
+ INF_NOT_USED_4,
+ INF_NOT_USED_5,
INF_BAD_HEADER_DATA,
INF_PIPELINE_OVERFLOW,
INF_BAD_CHUNK_SIZE,
INF_BAD_PHRASE,
INF_BAD_URI,
- INF_UNUSED,
- INF_UNUSED2,
+ INF_NOT_USED_2,
+ INF_NOT_USED_3,
INF_URI_PERCENT_NORMAL,
INF_URI_PERCENT_ASCII,
INF_URI_PERCENT_UTF8,
assert(start == nullptr);
assert(start_ != nullptr);
assert(length_ >= 0);
+ assert(length_ <= MAX_OCTETS);
start = start_;
length = length_;
}
+void Field::set(StatusCode stat_code)
+{
+ assert(length == STAT_NOT_COMPUTE);
+ assert(start == nullptr);
+ assert(stat_code <= 0);
+ start = nullptr;
+ length = stat_code;
+}
+
+
#ifdef REG_TEST
void Field::print(FILE* output, const char* name) const
{
explicit Field(int32_t length_) : length(length_) { assert(length<=0); }
Field() = default;
void set(int32_t length_, const uint8_t* start_);
+ void set(NHttpEnums::StatusCode stat_code);
+ void set(int32_t length) { set(static_cast<NHttpEnums::StatusCode>(length)); }
#ifdef REG_TEST
void print(FILE* output, const char* name) const;
}
// This method normalizes the header field value for headId.
-void HeaderNormalizer::normalize(const HeaderId head_id, const int count, ScratchPad& scratch_pad,
+void HeaderNormalizer::normalize(const HeaderId head_id, const int count,
NHttpInfractions& infractions, NHttpEventGen& events, const HeaderId header_name_id[],
const Field header_value[], const int32_t num_headers, Field& result_field) const
{
(concatenate_repeats && (num_matches == count)));
buffer_length += num_matches - 1; // allow space for concatenation commas
- // We are allocating twice as much memory as we need to store the normalized field value. The
- // raw field value will be copied into one half of the buffer. Concatenation and white space
- // normalization happen during this step. Next a series of normalization functions will
- // transform the value into final form. Each normalization copies the value from one half of
- // the buffer to the other. Based on whether the number of normalization functions is odd or
- // even, the initial placement in the buffer is chosen so that the final normalization leaves
- // the field value at the front of the buffer. The buffer space actually used is locked down in
- // the scratch_pad. The remainder of the first half and all of the second half are returned to
- // the scratch_pad for future use.
+ // We are allocating two buffers to store the normalized field value. The raw field value will
+ // be copied into one of them. Concatenation and white space normalization happen during this
+ // step. Next a series of normalization functions will transform the value into final form.
+ // Each normalization copies the value from one buffer to the other. Based on whether the
+ // number of normalization functions is odd or even, the initial buffer is chosen so that the
+ // final normalization leaves the normalized header value in norm_value.
- // Round up to multiple of eight so that both halves are 64-bit aligned. 200 is a "way too big"
- // fudge factor to allow for modest expansion of field size during normalization.
- buffer_length += (8-buffer_length%8)%8 + 200;
- uint8_t* const scratch = scratch_pad.request(2*buffer_length);
- if (scratch == nullptr)
- {
- result_field.length = STAT_INSUF_MEMORY;
- return;
- }
-
- uint8_t* const front_half = scratch;
- uint8_t* const back_half = scratch + buffer_length;
- uint8_t* working = (num_normalizers%2 == 0) ? front_half : back_half;
+ uint8_t* const norm_value = new uint8_t[buffer_length];
+ uint8_t* const temp_space = new uint8_t[buffer_length];
+ uint8_t* working = (num_normalizers%2 == 0) ? norm_value : temp_space;
int32_t data_length = 0;
for (int j=0; j < num_matches; j++)
{
{
if (i%2 != num_normalizers%2)
{
- data_length = normalizer[i](back_half, data_length, front_half, infractions, events);
+ data_length = normalizer[i](temp_space, data_length, norm_value, infractions, events);
}
else
{
- data_length = normalizer[i](front_half, data_length, back_half, infractions, events);
- }
- if (data_length <= 0)
- {
- result_field.length = data_length;
- return;
+ data_length = normalizer[i](norm_value, data_length, temp_space, infractions, events);
}
}
- result_field.start = scratch;
- result_field.length = data_length;
- scratch_pad.commit(data_length);
+ delete[] temp_space;
+ result_field.set(data_length, norm_value);
return;
}
#ifndef NHTTP_HEAD_NORM_H
#define NHTTP_HEAD_NORM_H
-#include "nhttp_scratch_pad.h"
#include "nhttp_field.h"
#include "nhttp_infractions.h"
#include "nhttp_normalizers.h"
num_normalizers((f1 != nullptr) + (f1 != nullptr)*(f2 != nullptr) + (f1 != nullptr)*(f2 !=
nullptr)*(f3 != nullptr)) { }
- void normalize(const NHttpEnums::HeaderId head_id, const int count, ScratchPad& scratch_pad,
+ void normalize(const NHttpEnums::HeaderId head_id, const int count,
NHttpInfractions& infractions, NHttpEventGen& events,
const NHttpEnums::HeaderId header_name_id[], const Field header_value[],
const int32_t num_headers, Field& result_field) const;
{
NormalizedHeader* temp_ptr = list_ptr;
list_ptr = list_ptr->next;
+ if (temp_ptr->norm.length >= 0)
+ delete[] temp_ptr->norm.start;
delete temp_ptr;
}
}
{
parse_header_block();
parse_header_lines();
+ create_norm_head_list();
+}
+
+void NHttpMsgHeadShared::create_norm_head_list()
+{
+ // This function does not do the actual JIT normalization of header values. It converts the
+ // header names into numeric IDs and creates a linked list of all the different headers that
+ // are present in the message along with the number of times each one appears.
for (int j=0; j < num_headers; j++)
{
derive_header_name_id(j);
{
infractions += INF_BAD_HEADER;
events.create_event(EVENT_BAD_HEADER);
+ header_name[k].set(STAT_PROBLEMATIC);
+ header_value[k].set(STAT_PROBLEMATIC);
}
}
}
const int32_t& length = header_name[index].length;
const uint8_t*& buffer = header_name[index].start;
- // Normalize header field name to lower case and remove LWS for matching purposes
- int32_t lower_length = 0;
- uint8_t* lower_name;
- if ((lower_name = scratch_pad.request(length)) == nullptr)
+ if (length <= 0)
{
- infractions += INF_NO_SCRATCH;
- header_name_id[index] = HEAD__INSUF_MEMORY;
+ header_name_id[index] = HEAD__PROBLEMATIC;
return;
}
+
+ // Normalize header field name to lower case and remove LWS for matching purposes
+ int32_t lower_length = 0;
+ uint8_t* lower_name = new uint8_t[length];
for (int32_t k=0; k < length; k++)
{
if (!is_sp_tab[buffer[k]])
}
}
header_name_id[index] = (HeaderId)str_to_code(lower_name, lower_length, header_list);
+ delete[] lower_name;
}
NHttpMsgHeadShared::NormalizedHeader* NHttpMsgHeadShared::get_header_node(HeaderId header_id) const
NormalizedHeader* node = get_header_node(header_id);
if (node == nullptr)
return Field::FIELD_NULL;
- header_norms[header_id]->normalize(header_id, node->count, scratch_pad, infractions, events,
- header_name_id, header_value, num_headers, node->norm);
+ header_norms[header_id]->normalize(header_id, node->count, infractions, events, header_name_id,
+ header_value, num_headers, node->norm);
return node->norm;
}
void parse_header_block();
uint32_t find_header_end(const uint8_t* buffer, int32_t length, int& num_seps);
void parse_header_lines();
+ void create_norm_head_list();
void derive_header_name_id(int index);
// All of these are indexed by the relative position of the header field in the message
params(params_),
transaction(NHttpTransaction::attach_my_transaction(session_data, source_id)),
tcp_close(session_data->tcp_close[source_id]),
- scratch_pad(2*buf_size+500),
infractions(session_data->infractions[source_id]),
events(session_data->events[source_id]),
version_id(session_data->version_id[source_id]),
#include "stream/stream_api.h"
#include "detection/detection_util.h"
-#include "nhttp_scratch_pad.h"
#include "nhttp_field.h"
#include "nhttp_module.h"
#include "nhttp_flow_data.h"
const NHttpParaList* const params;
NHttpTransaction* const transaction;
const bool tcp_close;
- ScratchPad scratch_pad;
NHttpInfractions infractions;
NHttpEventGen events;
#include "nhttp_field.h"
#include "nhttp_str_to_code.h"
+// There are currently no normalization functions that make header values bigger. Changes are
+// required to HeaderNormalizer::normalize() to allocate more space before you can introduce a
+// normalizer that may expand a header value.
+//
+// Normalization functions must return an output buffer with nonnegative length. Status codes are
+// not acceptable.
typedef int32_t (NormFunc)(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, NHttpEventGen&);
-
NormFunc norm_to_lower;
NormFunc norm_remove_lws;
+// Other normalization-related utilities
int64_t norm_decimal_integer(const Field& input);
int32_t norm_last_token_code(const Field& input, const StrCode table[]);
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2015 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.
-//--------------------------------------------------------------------------
-// nhttp_scratch_pad.h author Tom Peters <thopeter@cisco.com>
-
-#ifndef NHTTP_SCRATCH_PAD_H
-#define NHTTP_SCRATCH_PAD_H
-
-//-------------------------------------------------------------------------
-// ScratchPad class
-// Storage management class
-//-------------------------------------------------------------------------
-
-// Working space and storage for all the derived fields
-// Return value of request is 64-bit aligned and may be freely cast to uint64_t*
-// 1. request the maximum number of bytes you might need
-// 2. use what you need
-// 3. commit() what you actually used if you want to keep it
-// Anything you do not commit will be reused by the next request.
-
-class ScratchPad
-{
-public:
- ScratchPad(uint32_t _capacity) : capacity(_capacity), buffer(new uint64_t[_capacity/8+1]) { }
- ~ScratchPad() { delete[] buffer; }
- uint8_t* request(uint32_t needed) const
- {
- return (needed <= capacity-used) ?
- ((uint8_t*)buffer)+used : nullptr;
- }
- // round up to multiple of 8 for alignment
- void commit(uint32_t taken) { used += taken + (8-(taken%8))%8; }
-
-private:
- const uint32_t capacity;
- uint64_t* const buffer;
- uint32_t used = 0;
-};
-
-#endif
-
};
const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_BASIC
-{ false, nullptr, nullptr, nullptr };
+ { false, nullptr, nullptr, nullptr };
const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_NUMBER
-{ false, norm_remove_lws, nullptr, nullptr };
+ { false, norm_remove_lws, nullptr, nullptr };
const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_TOKEN_LIST
-{ true, norm_remove_lws, norm_to_lower, nullptr };
+ { true, norm_remove_lws, norm_to_lower, nullptr };
const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_CAT
-{ true, norm_remove_lws, nullptr, nullptr };
+ { true, norm_remove_lws, nullptr, nullptr };
const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_COOKIE
-{ true, nullptr, nullptr, nullptr };
+ { true, nullptr, nullptr, nullptr };
#if defined(__clang__)
// Designated initializers are not supported in C++11. However we're going to play compilation