#include "nhttp_inspect.h"
#include "nhttp_api.h"
-const char* NHttpApi::nhttp_myName = "nhttp_inspect";
+const char* NHttpApi::nhttp_my_name = "nhttp_inspect";
void NHttpApi::nhttp_init()
{
{
{
PT_INSPECTOR,
- NHttpApi::nhttp_myName,
+ NHttpApi::nhttp_my_name,
INSAPI_PLUGIN_V0,
0,
NHttpApi::nhttp_mod_ctor,
NHttpApi() = delete;
static Module* nhttp_mod_ctor() { return new NHttpModule; };
static void nhttp_mod_dtor(Module* m) { delete m; };
- static const char* nhttp_myName;
+ static const char* nhttp_my_name;
static void nhttp_init();
static void nhttp_term() {};
static Inspector* nhttp_ctor(Module* mod);
static const uint32_t NHTTP_GID = 119;
-// Field status codes for when no valid value is present in length or integer value. Positive values are actual length or field value.
-typedef enum { STAT_NOSOURCE=-6, STAT_NOTCONFIGURED=-5, STAT_NOTCOMPUTE=-4, STAT_INSUFMEMORY=-3, STAT_PROBLEMATIC=-2, STAT_NOTPRESENT=-1, STAT_EMPTYSTRING=0, STAT_OTHER=1 } StatusCode;
+// Field status codes for when no valid value is present in length or integer value. Positive values are actual length
+// or field value.
+typedef enum { STAT_NOSOURCE=-6, STAT_NOTCONFIGURED=-5, STAT_NOTCOMPUTE=-4, STAT_INSUFMEMORY=-3, STAT_PROBLEMATIC=-2,
+ STAT_NOTPRESENT=-1, STAT_EMPTYSTRING=0, STAT_OTHER=1 } StatusCode;
// Message originator--client or server
typedef enum { SRC__NOTCOMPUTE=-4, SRC_CLIENT=0, SRC_SERVER=1 } SourceId;
// Type of message section
-typedef enum { SEC__NOTCOMPUTE=-4, SEC__NOTPRESENT=-1, SEC_REQUEST = 2, SEC_STATUS, SEC_HEADER, SEC_BODY, SEC_CHUNKHEAD, SEC_CHUNKBODY, SEC_TRAILER, SEC_DISCARD,
- SEC_CLOSED, SEC_ABORT } SectionType;
+typedef enum { SEC__NOTCOMPUTE=-4, SEC__NOTPRESENT=-1, SEC_REQUEST = 2, SEC_STATUS, SEC_HEADER, SEC_BODY, SEC_CHUNKHEAD,
+ SEC_CHUNKBODY, SEC_TRAILER, SEC_DISCARD, SEC_CLOSED, SEC_ABORT } SectionType;
-// List of possible HTTP versions. Version 0.9 omitted because 0.9 predates creation of the HTTP/X.Y token. There would never be a message with "HTTP/0.9"
-typedef enum { VERS__NOSOURCE=-6, VERS__NOTCOMPUTE=-4, VERS__PROBLEMATIC=-2, VERS__NOTPRESENT=-1, VERS__OTHER=1, VERS_1_0, VERS_1_1, VERS_2_0 } VersionId;
+// List of possible HTTP versions. Version 0.9 omitted because 0.9 predates creation of the HTTP/X.Y token. There would
+// never be a message with "HTTP/0.9"
+typedef enum { VERS__NOSOURCE=-6, VERS__NOTCOMPUTE=-4, VERS__PROBLEMATIC=-2, VERS__NOTPRESENT=-1, VERS__OTHER=1, VERS_1_0,
+ VERS_1_1, VERS_2_0 } VersionId;
// Every request method we have ever heard of
-typedef enum { METH__NOSOURCE=-6, METH__NOTCOMPUTE=-4, METH__INSUFMEMORY=-3, METH__PROBLEMATIC=-2, METH__NOTPRESENT=-1, 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 } MethodId;
+typedef enum { METH__NOSOURCE=-6, METH__NOTCOMPUTE=-4, METH__INSUFMEMORY=-3, METH__PROBLEMATIC=-2, METH__NOTPRESENT=-1,
+ 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 } MethodId;
// URI formats
-typedef enum { URI__NOSOURCE=-6, URI__NOTCOMPUTE=-4, URI__PROBLEMATIC=-2, URI_ASTERISK = 2, URI_AUTHORITY, URI_ABSPATH, URI_ABSOLUTE } UriType;
+typedef enum { URI__NOSOURCE=-6, URI__NOTCOMPUTE=-4, URI__PROBLEMATIC=-2, URI_ASTERISK = 2, URI_AUTHORITY, URI_ABSPATH,
+ URI_ABSOLUTE } UriType;
// URI schemes
-typedef enum { SCH__NOSOURCE=-6, SCH__NOTCOMPUTE=-4, SCH__INSUFMEMORY=-3, SCH__NOTPRESENT=-1, SCH_OTHER = 1, SCH_HTTP, SCH_HTTPS, SCH_FTP, SCH_GOPHER, SCH_FILE } SchemeId;
+typedef enum { SCH__NOSOURCE=-6, SCH__NOTCOMPUTE=-4, SCH__INSUFMEMORY=-3, SCH__NOTPRESENT=-1, SCH_OTHER = 1, SCH_HTTP,
+ SCH_HTTPS, SCH_FTP, SCH_GOPHER, SCH_FILE } SchemeId;
// Every header we have ever heard of
-typedef enum { HEAD__NOTCOMPUTE=-4, HEAD__INSUFMEMORY=-3, HEAD__PROBLEMATIC=-2, HEAD__NOTPRESENT=-1, 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__MAXVALUE } HeaderId;
+typedef enum { HEAD__NOTCOMPUTE=-4, HEAD__INSUFMEMORY=-3, HEAD__PROBLEMATIC=-2, HEAD__NOTPRESENT=-1, 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__MAXVALUE } HeaderId;
// All the infractions we might find while parsing and analyzing a message
typedef enum {
typedef enum { CHAR_NORMAL=2, CHAR_PERCENT, CHAR_PATH, CHAR_INVALID, CHAR_EIGHTBIT } CharAction;
// Transfer codings
-typedef enum { TRANSCODE__OTHER=1, TRANSCODE_CHUNKED, TRANSCODE_IDENTITY, TRANSCODE_GZIP, TRANSCODE_COMPRESS, TRANSCODE_DEFLATE } Transcoding;
+typedef enum { TRANSCODE__OTHER=1, TRANSCODE_CHUNKED, TRANSCODE_IDENTITY, TRANSCODE_GZIP, TRANSCODE_COMPRESS,
+ TRANSCODE_DEFLATE } Transcoding;
typedef enum
{
-
-
-
-
-
-
-
-
-
-
const Field Field::FIELD_NULL { STAT_NOSOURCE };
-void Field::print(FILE *output, const char* name, bool intVals) const {
- if ((length == STAT_NOTPRESENT) || (length == STAT_NOTCOMPUTE) || (length == STAT_NOSOURCE)) return;
- int outCount = fprintf(output, "%s, length = %d, ", name, length);
+void Field::print(FILE *output, const char* name, bool int_vals) const {
+ if ((length == STAT_NOTPRESENT) || (length == STAT_NOTCOMPUTE) || (length == STAT_NOSOURCE)) {
+ return;
+ }
+ int out_count = fprintf(output, "%s, length = %d, ", name, length);
if (length <= 0) {
fprintf(output, "\n");
return;
}
- int32_t printLength = (length <= 1000) ? length : 1000; // Limit the amount of data printed
- for (int k=0; k < printLength; k++) {
+ int32_t print_length = (length <= 1000) ? length : 1000; // Limit the amount of data printed
+ for (int k=0; k < print_length; k++) {
if ((start[k] >= 0x20) && (start[k] <= 0x7E)) fprintf(output, "%c", (char)start[k]);
else if (start[k] == 0xD) fprintf(output, "~");
else if (start[k] == 0xA) fprintf(output, "^");
else fprintf(output, "*");
- if ((k%120 == (119 - outCount)) && (k+1 < printLength)) fprintf(output, "\n");
+ if ((k%120 == (119 - out_count)) && (k+1 < print_length)) {
+ fprintf(output, "\n");
+ }
}
- if (intVals && (printLength%8 == 0)) {
+ if (int_vals && (print_length%8 == 0)) {
fprintf(output, "\nInteger values =");
- for (int j=0; j < printLength; j+=8) {
+ for (int j=0; j < print_length; j+=8) {
fprintf(output, " %" PRIu64 , *((const uint64_t*)(start+j)));
}
}
#include <stdio.h>
#include <assert.h>
-// Individual pieces of the message found during parsing
+// Individual pieces of the message found during parsing.
// Length values <= 0 are StatusCode values and imply that the start pointer is meaningless.
// Never use the start pointer without verifying that length > 0.
class Field {
Field(int32_t length_, const uint8_t* start_) : length(length_), start(start_) {};
explicit Field(int32_t length_) : length(length_) { assert(length<=0); };
Field() = default;
- void print(FILE *output, const char* name, bool intVals = false) const;
+ void print(FILE *output, const char* name, bool int_vals = false) const;
};
#endif
NHttpFlowData::NHttpFlowData() : FlowData(nhttp_flow_id) {}
NHttpFlowData::~NHttpFlowData() {
- delete requestLine;
- delete statusLine;
+ delete request_line;
+ delete status_line;
for(int k=0; k <= 1; k++) {
delete headers[k];
- delete latestOther[k];
+ delete latest_other[k];
}
}
-void NHttpFlowData::halfReset(SourceId sourceId) {
- assert((sourceId == SRC_CLIENT) || (sourceId == SRC_SERVER));
- octetsExpected[sourceId] = STAT_NOTPRESENT;
+void NHttpFlowData::half_reset(SourceId source_id) {
+ assert((source_id == SRC_CLIENT) || (source_id == SRC_SERVER));
+ octets_expected[source_id] = STAT_NOTPRESENT;
- versionId[sourceId] = VERS__NOTPRESENT;
- methodId[sourceId] = METH__NOTPRESENT;
- statusCodeNum[sourceId] = STAT_NOTPRESENT;
+ version_id[source_id] = VERS__NOTPRESENT;
+ method_id[source_id] = METH__NOTPRESENT;
+ status_code_num[source_id] = STAT_NOTPRESENT;
- dataLength[sourceId] = STAT_NOTPRESENT;
- bodySections[sourceId] = STAT_NOTPRESENT;
- bodyOctets[sourceId] = STAT_NOTPRESENT;
- numChunks[sourceId] = STAT_NOTPRESENT;
- chunkSections[sourceId] = STAT_NOTPRESENT;
- chunkOctets[sourceId] = STAT_NOTPRESENT;
+ data_length[source_id] = STAT_NOTPRESENT;
+ body_sections[source_id] = STAT_NOTPRESENT;
+ body_octets[source_id] = STAT_NOTPRESENT;
+ num_chunks[source_id] = STAT_NOTPRESENT;
+ chunk_sections[source_id] = STAT_NOTPRESENT;
+ chunk_octets[source_id] = STAT_NOTPRESENT;
}
friend class NHttpMsgTrailer;
friend class NHttpStreamSplitter;
private:
- void halfReset(NHttpEnums::SourceId sourceId);
+ void half_reset(NHttpEnums::SourceId source_id);
// StreamSplitter internal data
- int64_t octetsSeen[2] = { 0, 0 };
- int numCrlf[2] = { 0, 0 };
+ int64_t octets_seen[2] = { 0, 0 };
+ int num_crlf[2] = { 0, 0 };
// StreamSplitter => Inspector (facts about the most recent message section)
// 0 element refers to client request, 1 element refers to server response
- NHttpEnums::SectionType sectionType[2] = { NHttpEnums::SEC__NOTCOMPUTE, NHttpEnums::SEC__NOTCOMPUTE };
- bool tcpClose[2] = { false, false };
+ NHttpEnums::SectionType section_type[2] = { NHttpEnums::SEC__NOTCOMPUTE, NHttpEnums::SEC__NOTCOMPUTE };
+ bool tcp_close[2] = { false, false };
uint64_t infractions[2] = { 0, 0 };
// Inspector => StreamSplitter (facts about the message section that is coming next)
- NHttpEnums::SectionType typeExpected[2] = { NHttpEnums::SEC_REQUEST, NHttpEnums::SEC_STATUS };
- int64_t octetsExpected[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // expected size of the upcoming body or chunk body section
+ NHttpEnums::SectionType type_expected[2] = { NHttpEnums::SEC_REQUEST, NHttpEnums::SEC_STATUS };
+ int64_t octets_expected[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // expected size of the upcoming body or chunk body section
// Inspector's internal data about the current message
- // Some items don't apply in both directions. Have two copies anyway just to simplify code and minimize hard-to-find bugs
- NHttpEnums::VersionId versionId[2] = { NHttpEnums::VERS__NOTPRESENT, NHttpEnums::VERS__NOTPRESENT };
- NHttpEnums::MethodId methodId[2] = { NHttpEnums::METH__NOTPRESENT, NHttpEnums::METH__NOTPRESENT };
- int32_t statusCodeNum[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT };
-
- int64_t dataLength[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // length of the data from Content-Length field or chunk header.
- int64_t bodySections[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // number of body sections seen so far including chunk headers
- int64_t bodyOctets[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // number of user data octets seen so far (either regular body or chunks)
- int64_t numChunks[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // number of chunks seen so far
- int64_t chunkSections[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // number of sections seen so far in the current chunk
- int64_t chunkOctets[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // number of user data octets seen so far in the current chunk including terminating CRLF
+ // Some items don't apply in both directions. Have two copies anyway just to simplify code and minimize
+ // hard-to-find bugs
+ NHttpEnums::VersionId version_id[2] = { NHttpEnums::VERS__NOTPRESENT, NHttpEnums::VERS__NOTPRESENT };
+ NHttpEnums::MethodId method_id[2] = { NHttpEnums::METH__NOTPRESENT, NHttpEnums::METH__NOTPRESENT };
+ int32_t status_code_num[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT };
+
+ int64_t data_length[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // length of the data from Content-Length field or chunk header.
+ int64_t body_sections[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // number of body sections seen so far including chunk headers
+ int64_t body_octets[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // number of user data octets seen so far (either regular body or chunks)
+ int64_t num_chunks[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // number of chunks seen so far
+ int64_t chunk_sections[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // number of sections seen so far in the current chunk
+ int64_t chunk_octets[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // number of user data octets seen so far in the current chunk including terminating CRLF
// Stored message sections from this session
// You must reset to nullptr after deleting a section
// Never put one section in two places. latestOther is only for things not otherwise listed
- class NHttpMsgRequest* requestLine = nullptr;
- class NHttpMsgStatus* statusLine = nullptr;
+ class NHttpMsgRequest* request_line = nullptr;
+ class NHttpMsgStatus* status_line = nullptr;
class NHttpMsgHeader* headers[2] = { nullptr, nullptr };
- class NHttpMsgSection* latestOther[2] = { nullptr, nullptr };
+ class NHttpMsgSection* latest_other[2] = { nullptr, nullptr };
};
#endif
using namespace NHttpEnums;
-// This derivation removes embedded CRLFs (wrapping), omits leading and trailing linear white space, and replaces internal strings of <SP> and <LF> with a single <SP>
-int32_t HeaderNormalizer::deriveHeaderContent(const uint8_t *value, int32_t length, uint8_t *buffer) {
- int32_t outLength = 0;
- bool lastWhite = true;
+// This derivation removes embedded CRLFs (wrapping), omits leading and trailing linear white space, and replaces
+// internal strings of <SP> and <LF> with a single <SP>
+int32_t HeaderNormalizer::derive_header_content(const uint8_t *value, int32_t length, uint8_t *buffer) {
+ int32_t out_length = 0;
+ bool last_white = true;
for (int32_t k=0; k < length; k++) {
if ((value[k] == '\r') && (k+1 < length) && (value[k+1] == '\n')) k++;
else if ((value[k] != ' ') && (value[k] != '\t')) {
- lastWhite = false;
- buffer[outLength++] = value[k];
+ last_white = false;
+ buffer[out_length++] = value[k];
}
- else if (!lastWhite) {
- lastWhite = true;
- buffer[outLength++] = ' ';
+ else if (!last_white) {
+ last_white = true;
+ buffer[out_length++] = ' ';
}
}
- if ((outLength > 0) && (buffer[outLength - 1] == ' ')) outLength--;
- return outLength;
+ if ((out_length > 0) && (buffer[out_length - 1] == ' ')) {
+ out_length--;
+ }
+ return out_length;
}
// This method normalizes the header field value for headId.
-int32_t HeaderNormalizer::normalize(const HeaderId headId, const int count, ScratchPad &scratchPad, uint64_t &infractions,
- const HeaderId headerNameId[], const Field headerValue[], const int32_t numHeaders, Field &resultField) const {
- if (resultField.length != STAT_NOTCOMPUTE) return resultField.length;
- if (format == NORM_NULL) return resultField.length = STAT_NOTCONFIGURED;
- if (count == 0) return resultField.length = STAT_NOSOURCE;
+int32_t HeaderNormalizer::normalize(const HeaderId head_id, const int count, ScratchPad &scratch_pad, uint64_t &infractions,
+ const HeaderId header_name_id[], const Field header_value[], const int32_t num_headers, Field &result_field) const {
+ if (result_field.length != STAT_NOTCOMPUTE) {
+ return result_field.length;
+ }
+ if (format == NORM_NULL) {
+ return result_field.length = STAT_NOTCONFIGURED;
+ }
+ if (count == 0) {
+ return result_field.length = STAT_NOSOURCE;
+ }
- // Search Header IDs from all the headers in this message. concatenateRepeats means the header can properly be
+ // Search Header IDs from all the headers in this message. concatenate_repeats means the header can properly be
// present more than once. The standard normalization is to concatenate all the repeated field values into a
// comma-separated list. Otherwise only the first value will be normalized and the rest will be ignored.
- int numMatches = 0;
- int32_t bufferLength = 0;
- int currMatch;
- for (int k=0; k < numHeaders; k++) {
- if (headerNameId[k] == headId) {
- if (++numMatches == 1) currMatch = k; // remembering location of the first matching header
- bufferLength += headerValue[k].length;
- if (!concatenateRepeats || (numMatches >= count)) break;
+ int num_matches = 0;
+ int32_t buffer_length = 0;
+ int curr_match;
+ for (int k=0; k < num_headers; k++) {
+ if (header_name_id[k] == head_id) {
+ if (++num_matches == 1) curr_match = k; // remembering location of the first matching header
+ buffer_length += header_value[k].length;
+ if (!concatenate_repeats || (num_matches >= count)) break;
}
}
- assert((!concatenateRepeats && (numMatches == 1)) || (concatenateRepeats && (numMatches == count)));
- bufferLength += numMatches - 1; // allow space for concatenation commas
+ assert((!concatenate_repeats && (num_matches == 1)) || (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 scratchPad. The remainder of the first half
- // and all of the second half are returned to the scratchPad for future use.
+ // 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.
// 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.
- bufferLength += (8-bufferLength%8)%8 + 200;
- uint8_t* const scratch = scratchPad.request(2*bufferLength);
- if (scratch == nullptr) return resultField.length = STAT_INSUFMEMORY;
-
- uint8_t* const frontHalf = scratch;
- uint8_t* const backHalf = scratch + bufferLength;
- uint8_t* working = (numNormalizers%2 == 0) ? frontHalf : backHalf;
- int32_t dataLength = 0;
- for (int j=0; j < numMatches; j++) {
+ buffer_length += (8-buffer_length%8)%8 + 200;
+ uint8_t* const scratch = scratch_pad.request(2*buffer_length);
+ if (scratch == nullptr) {
+ return result_field.length = STAT_INSUFMEMORY;
+ }
+
+ 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;
+ int32_t data_length = 0;
+ for (int j=0; j < num_matches; j++) {
if (j >= 1) {
*working++ = ',';
- dataLength++;
- while (headerNameId[++currMatch] != headId);
+ data_length++;
+ while (header_name_id[++curr_match] != head_id);
}
- int32_t growth = deriveHeaderContent(headerValue[currMatch].start, headerValue[currMatch].length, working);
+ int32_t growth = derive_header_content(header_value[curr_match].start, header_value[curr_match].length, working);
working += growth;
- dataLength += growth;
+ data_length += growth;
}
- for (int i=0; i < numNormalizers; i++) {
- if (i%2 != numNormalizers%2) dataLength = normalizer[i](backHalf, dataLength, frontHalf, infractions, normArg[i]);
- else dataLength = normalizer[i](frontHalf, dataLength, backHalf, infractions, normArg[i]);
- if (dataLength <= 0) return resultField.length = dataLength;
+ for (int i=0; i < num_normalizers; i++) {
+ if (i%2 != num_normalizers%2) {
+ data_length = normalizer[i](back_half, data_length, front_half, infractions, norm_arg[i]);
+ }
+ else {
+ data_length = normalizer[i](front_half, data_length, back_half, infractions, norm_arg[i]);
+ }
+ if (data_length <= 0) {
+ return result_field.length = data_length;
+ }
}
- resultField.start = scratch;
- resultField.length = dataLength;
- scratchPad.commit(dataLength);
- return resultField.length;
+ result_field.start = scratch;
+ result_field.length = data_length;
+ scratch_pad.commit(data_length);
+ return result_field.length;
}
// Strategies for normalizing HTTP header field values
//-------------------------------------------------------------------------
-// Three normalization functions per HeaderNormalizer seems likely to be enough. Nothing subtle will break if you choose to expand it to four or more. Just a whole bunch of
-// signatures and initializers to update.
-// When defining a HeaderNormalizer don't leave holes in the normalizer list. E.g. if you have two normalizers they must be first and second. If you do first and third
-// instead it won't explode but the third one won't be used either.
+// Three normalization functions per HeaderNormalizer seems likely to be enough. Nothing subtle will break if you choose
+// to expand it to four or more. Just a whole bunch of signatures and initializers to update.
+// When defining a HeaderNormalizer don't leave holes in the normalizer list. E.g. if you have two normalizers they must
+// be first and second. If you do first and third instead it won't explode but the third one won't be used either.
class HeaderNormalizer {
public:
- constexpr HeaderNormalizer(NHttpEnums::NormFormat _format, bool _concatenateRepeats, int32_t (*f1)(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*),
- const void *f1Arg, int32_t (*f2)(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*), const void *f2Arg, int32_t (*f3)(const uint8_t*, int32_t, uint8_t*, uint64_t&,
- const void*), const void *f3Arg) :
- format(_format),
- concatenateRepeats(_concatenateRepeats),
- normalizer { f1, f2, f3 },
- normArg { f1Arg, f2Arg, f3Arg },
- numNormalizers((f1 != nullptr) + (f1 != nullptr)*(f2 != nullptr) + (f1 != nullptr)*(f2 != nullptr)*(f3 != nullptr)) {};
- int32_t normalize(const NHttpEnums::HeaderId headId, const int count, ScratchPad &scratchPad, uint64_t &infractions,
- const NHttpEnums::HeaderId headerNameId[], const Field headerValue[], const int32_t numHeaders, Field &resultField) const;
- NHttpEnums::NormFormat getFormat() const {return format;};
+ constexpr HeaderNormalizer(
+ NHttpEnums::NormFormat _format,
+ bool _concatenate_repeats,
+ int32_t (*f1)(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*),
+ const void *f1_arg,
+ int32_t (*f2)(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*),
+ const void *f2_arg,
+ int32_t (*f3)(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*),
+ const void *f3_arg)
+ : format(_format), concatenate_repeats(_concatenate_repeats), normalizer { f1, f2, f3 },
+ norm_arg { f1_arg, f2_arg, f3_arg },
+ num_normalizers((f1 != nullptr) + (f1 != nullptr)*(f2 != nullptr) + (f1 != nullptr)*(f2 != nullptr)*(f3 != nullptr))
+ {};
+ int32_t normalize(const NHttpEnums::HeaderId head_id, const int count, ScratchPad &scratch_pad, uint64_t &infractions,
+ const NHttpEnums::HeaderId header_name_id[], const Field header_value[], const int32_t num_headers,
+ Field &result_field) const;
+ NHttpEnums::NormFormat get_format() const { return format; };
private:
- static int32_t deriveHeaderContent(const uint8_t *value, int32_t length, uint8_t *buffer);
+ static int32_t derive_header_content(const uint8_t *value, int32_t length, uint8_t *buffer);
const NHttpEnums::NormFormat format;
- const bool concatenateRepeats;
+ const bool concatenate_repeats;
int32_t (* const normalizer[3])(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*);
- const void * normArg[3];
- const int numNormalizers;
+ const void * norm_arg[3];
+ const int num_normalizers;
};
#endif
using namespace NHttpEnums;
-NHttpInspect::NHttpInspect(bool test_input, bool _test_output) : test_output(_test_output)
+NHttpInspect::NHttpInspect(bool test_input_, bool test_output_) : test_output(test_output_)
{
- NHttpTestInput::test_input = test_input;
+ NHttpTestInput::test_input = test_input_;
if (NHttpTestInput::test_input) {
- NHttpTestInput::testInput = new NHttpTestInput(testInputFile);
+ NHttpTestInput::test_input_source = new NHttpTestInput(test_input_file);
}
}
NHttpInspect::~NHttpInspect ()
{
if (NHttpTestInput::test_input) {
- delete NHttpTestInput::testInput;
- if (testOut) fclose(testOut);
+ delete NHttpTestInput::test_input_source;
+ if (test_out) {
+ fclose(test_out);
+ }
}
}
int NHttpInspect::verify(SnortConfig*)
{
- return 0; // 0 = good, -1 = bad
-}
-
-void NHttpInspect::tinit()
-{
-}
-
-void NHttpInspect::tterm()
-{
+ return 0;
}
void NHttpInspect::show(SnortConfig*)
LogMessage("NHttpInspect\n");
}
-void NHttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const flow, SourceId sourceId)
+void NHttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const flow, SourceId source_id)
{
- NHttpFlowData* sessionData = (NHttpFlowData*)flow->get_application_data(NHttpFlowData::nhttp_flow_id);
- assert(sessionData);
-
- NHttpMsgSection *msgSection = nullptr;
-
- switch (sessionData->sectionType[sourceId]) {
- case SEC_REQUEST: msgSection = new NHttpMsgRequest(data, dsize, sessionData, sourceId); break;
- case SEC_STATUS: msgSection = new NHttpMsgStatus(data, dsize, sessionData, sourceId); break;
- case SEC_HEADER: msgSection = new NHttpMsgHeader(data, dsize, sessionData, sourceId); break;
- case SEC_BODY: msgSection = new NHttpMsgBody(data, dsize, sessionData, sourceId); break;
- case SEC_CHUNKHEAD: msgSection = new NHttpMsgChunkHead(data, dsize, sessionData, sourceId); break;
- case SEC_CHUNKBODY: msgSection = new NHttpMsgChunkBody(data, dsize, sessionData, sourceId); break;
- case SEC_TRAILER: msgSection = new NHttpMsgTrailer(data, dsize, sessionData, sourceId); break;
+ NHttpFlowData* session_data = (NHttpFlowData*)flow->get_application_data(NHttpFlowData::nhttp_flow_id);
+ assert(session_data);
+
+ NHttpMsgSection *msg_section = nullptr;
+
+ switch (session_data->section_type[source_id]) {
+ case SEC_REQUEST: msg_section = new NHttpMsgRequest(data, dsize, session_data, source_id); break;
+ case SEC_STATUS: msg_section = new NHttpMsgStatus(data, dsize, session_data, source_id); break;
+ case SEC_HEADER: msg_section = new NHttpMsgHeader(data, dsize, session_data, source_id); break;
+ case SEC_BODY: msg_section = new NHttpMsgBody(data, dsize, session_data, source_id); break;
+ case SEC_CHUNKHEAD: msg_section = new NHttpMsgChunkHead(data, dsize, session_data, source_id); break;
+ case SEC_CHUNKBODY: msg_section = new NHttpMsgChunkBody(data, dsize, session_data, source_id); break;
+ case SEC_TRAILER: msg_section = new NHttpMsgTrailer(data, dsize, session_data, source_id); break;
case SEC_DISCARD: delete[] data; return;
default: assert(0); delete[] data; return;
}
- msgSection->analyze();
- msgSection->updateFlow();
- msgSection->genEvents();
- msgSection->legacyClients();
+ msg_section->analyze();
+ msg_section->update_flow();
+ msg_section->gen_events();
+ msg_section->legacy_clients();
if (test_output) {
- if (!NHttpTestInput::test_input) msgSection->printSection(stdout);
+ if (!NHttpTestInput::test_input) msg_section->print_section(stdout);
else {
- if (NHttpTestInput::testInput->getTestNumber() != fileTestNumber) {
- if (testOut) fclose (testOut);
- fileTestNumber = NHttpTestInput::testInput->getTestNumber();
- char fileName[100];
- snprintf(fileName, sizeof(fileName), "%s%" PRIi64 ".txt", testOutputPrefix, fileTestNumber);
- if ((testOut = fopen(fileName, "w+")) == nullptr) throw std::runtime_error("Cannot open test output file");
+ if (NHttpTestInput::test_input_source->get_test_number() != file_test_number) {
+ if (test_out) fclose (test_out);
+ file_test_number = NHttpTestInput::test_input_source->get_test_number();
+ char file_name[100];
+ snprintf(file_name, sizeof(file_name), "%s%" PRIi64 ".txt", test_output_prefix, file_test_number);
+ if ((test_out = fopen(file_name, "w+")) == nullptr) throw std::runtime_error("Cannot open test output file");
}
- msgSection->printSection(testOut);
- printf("Finished processing section from test %" PRIi64 "\n", fileTestNumber);
+ msg_section->print_section(test_out);
+ printf("Finished processing section from test %" PRIi64 "\n", file_test_number);
}
}
}
class NHttpInspect : public Inspector {
public:
- NHttpInspect(bool test_input, bool _test_output);
+ NHttpInspect(bool test_input_, bool _test_output_);
~NHttpInspect();
bool get_buf(InspectionBuffer::Type, Packet*, InspectionBuffer&);
void show(SnortConfig*);
void eval(Packet*) { return; };
bool enabled();
- void tinit();
- void tterm();
- NHttpStreamSplitter* get_splitter(bool isClientToServer) { return new NHttpStreamSplitter(isClientToServer, this); };
+ void tinit() {};
+ void tterm() {};
+ NHttpStreamSplitter* get_splitter(bool is_client_to_server) { return new
+ NHttpStreamSplitter(is_client_to_server, this); };
private:
friend NHttpApi;
friend NHttpStreamSplitter;
- void process(const uint8_t* data, const uint16_t dsize, Flow* const flow, NHttpEnums::SourceId sourceId_);
+ void process(const uint8_t* data, const uint16_t dsize, Flow* const flow, NHttpEnums::SourceId source_id_);
// Test mode
bool test_output;
- const char *testInputFile = "nhttp_test_msgs.txt";
- const char *testOutputPrefix = "nhttpresults/testcase";
- FILE *testOut = nullptr;
- int64_t fileTestNumber = -1;
+ const char *test_input_file = "nhttp_test_msgs.txt";
+ const char *test_output_prefix = "nhttpresults/testcase";
+ FILE *test_out = nullptr;
+ int64_t file_test_number = -1;
};
#endif
#include "nhttp_enum.h"
#include "nhttp_module.h"
-NHttpModule::NHttpModule() : Module("nhttp_inspect", nhttpParams)
-{ }
-
-const RuleMap* NHttpModule::get_rules() const
-{ return nhttpEvents; }
-
-const Parameter NHttpModule::nhttpParams[] =
+const Parameter NHttpModule::nhttp_params[] =
{{ "test_input", Parameter::PT_BOOL, nullptr, "false", "read HTTP messages from text file" },
{ "test_output", Parameter::PT_BOOL, nullptr, "false", "print out HTTP section data" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }};
return true;
}
-bool NHttpModule::end(const char*, int, SnortConfig*) {
- return true;
-}
-
bool NHttpModule::set(const char*, Value &val, SnortConfig*) {
- if (val.is("test_input")) test_input = val.get_bool();
- else if (val.is("test_output")) test_output = val.get_bool();
- else return false;
+ if (val.is("test_input")) {
+ test_input = val.get_bool();
+ }
+ else if (val.is("test_output")) {
+ test_output = val.get_bool();
+ }
+ else {
+ return false;
+ }
return true;
}
-unsigned NHttpModule::get_gid() const {
- return NHttpEnums::NHTTP_GID;
-}
class NHttpModule : public Module
{
public:
- NHttpModule();
+ NHttpModule() : Module("nhttp_inspect", nhttp_params) {};
bool begin(const char*, int, SnortConfig*);
- bool end(const char*, int, SnortConfig*);
+ bool end(const char*, int, SnortConfig*) { return true; };
bool set(const char*, Value&, SnortConfig*);
- unsigned get_gid() const;
- const RuleMap* get_rules() const;
+ unsigned get_gid() const { return NHttpEnums::NHTTP_GID; };
+ const RuleMap* get_rules() const { return nhttp_events; };
bool get_test_input() const { return test_input; };
bool get_test_output() const { return test_output; };
private:
- static const Parameter nhttpParams[];
- static const RuleMap nhttpEvents[];
+ static const Parameter nhttp_params[];
+ static const RuleMap nhttp_events[];
bool test_input = false;
bool test_output = false;
};
using namespace NHttpEnums;
-NHttpMsgBody::NHttpMsgBody(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, SourceId sourceId_) :
- NHttpMsgSection(buffer, bufSize, sessionData_, sourceId_), dataLength(sessionData->dataLength[sourceId]),
- bodySections(sessionData->bodySections[sourceId]), bodyOctets(sessionData->bodyOctets[sourceId]) {
- delete sessionData->latestOther[sourceId];
- sessionData->latestOther[sourceId] = this;
+NHttpMsgBody::NHttpMsgBody(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, SourceId source_id_) :
+ NHttpMsgSection(buffer, buf_size, session_data_, source_id_), data_length(session_data->data_length[source_id]),
+ body_sections(session_data->body_sections[source_id]), body_octets(session_data->body_octets[source_id]) {
+ delete session_data->latest_other[source_id];
+ session_data->latest_other[source_id] = this;
}
void NHttpMsgBody::analyze() {
- bodySections++;
- bodyOctets += msgText.length;
- data.start = msgText.start;
- data.length = msgText.length;
+ body_sections++;
+ body_octets += msg_text.length;
+ data.start = msg_text.start;
+ data.length = msg_text.length;
// The following statement tests for the case where streams underfulfilled flush due to a TCP connection close
- if ((msgText.length < 16384) && (bodyOctets < dataLength)) tcpClose = true;
- if (tcpClose && (bodyOctets < dataLength)) infractions |= INF_TRUNCATED;
+ if ((msg_text.length < 16384) && (body_octets < data_length)) tcp_close = true;
+ if (tcp_close && (body_octets < data_length)) infractions |= INF_TRUNCATED;
}
-void NHttpMsgBody::genEvents() {
+void NHttpMsgBody::gen_events() {
}
-void NHttpMsgBody::printSection(FILE *output) {
- NHttpMsgSection::printMessageTitle(output, "body");
- fprintf(output, "Expected data length %" PRIi64 ", sections seen %" PRIi64 ", octets seen %" PRIi64 "\n", dataLength, bodySections, bodyOctets);
+void NHttpMsgBody::print_section(FILE *output) {
+ NHttpMsgSection::print_message_title(output, "body");
+ fprintf(output, "Expected data length %" PRIi64 ", sections seen %" PRIi64 ", octets seen %" PRIi64 "\n", data_length, body_sections, body_octets);
data.print(output, "Data");
- NHttpMsgSection::printMessageWrapup(output);
+ NHttpMsgSection::print_message_wrapup(output);
}
-void NHttpMsgBody::updateFlow() {
- if (tcpClose) {
- sessionData->typeExpected[sourceId] = SEC_CLOSED;
- sessionData->halfReset(sourceId);
+void NHttpMsgBody::update_flow() {
+ if (tcp_close) {
+ session_data->type_expected[source_id] = SEC_CLOSED;
+ session_data->half_reset(source_id);
}
- else if (bodyOctets < dataLength) {
+ else if (body_octets < data_length) {
// More body coming
- sessionData->bodySections[sourceId] = bodySections;
- sessionData->bodyOctets[sourceId] = bodyOctets;
+ session_data->body_sections[source_id] = body_sections;
+ session_data->body_octets[source_id] = body_octets;
}
else {
// End of message
- sessionData->typeExpected[sourceId] = (sourceId == SRC_CLIENT) ? SEC_REQUEST : SEC_STATUS;
- sessionData->halfReset(sourceId);
+ session_data->type_expected[source_id] = (source_id == SRC_CLIENT) ? SEC_REQUEST : SEC_STATUS;
+ session_data->half_reset(source_id);
}
}
// Legacy support function. Puts message fields into the buffers used by old Snort.
-void NHttpMsgBody::legacyClients() {
+void NHttpMsgBody::legacy_clients() {
ClearHttpBuffers();
if (data.length > 0) SetHttpBuffer(HTTP_BUFFER_CLIENT_BODY, data.start, (unsigned)data.length);
}
class NHttpMsgBody : public NHttpMsgSection {
public:
- NHttpMsgBody(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_);
+ NHttpMsgBody(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, NHttpEnums::SourceId source_id_);
void analyze();
- void printSection(FILE *output);
- void genEvents();
- void updateFlow();
- void legacyClients();
+ void print_section(FILE *output);
+ void gen_events();
+ void update_flow();
+ void legacy_clients();
protected:
- int64_t dataLength;
- int64_t bodySections;
- int64_t bodyOctets;
+ int64_t data_length;
+ int64_t body_sections;
+ int64_t body_octets;
Field data;
};
using namespace NHttpEnums;
-NHttpMsgChunkBody::NHttpMsgChunkBody(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, SourceId sourceId_) :
- NHttpMsgBody(buffer, bufSize, sessionData_, sourceId_), /* numChunks(sessionData->numChunks[sourceId]), &&& */
- chunkSections(sessionData->chunkSections[sourceId]), chunkOctets(sessionData->chunkOctets[sourceId]) {}
+NHttpMsgChunkBody::NHttpMsgChunkBody(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, SourceId source_id_) :
+ NHttpMsgBody(buffer, buf_size, session_data_, source_id_), /* num_chunks(session_data->num_chunks[source_id]), &&& */
+ chunk_sections(session_data->chunk_sections[source_id]), chunk_octets(session_data->chunk_octets[source_id]) {}
void NHttpMsgChunkBody::analyze() {
- bodySections++;
- chunkOctets += msgText.length;
- bodyOctets += msgText.length;
- int termCrlfBytes = 0;
- if (chunkOctets > dataLength) {
+ body_sections++;
+ chunk_octets += msg_text.length;
+ body_octets += msg_text.length;
+ int term_crlf_bytes = 0;
+ if (chunk_octets > data_length) {
// Final <CR><LF> are not data and do not belong in octet total or data field
- termCrlfBytes = chunkOctets - dataLength;
- assert(termCrlfBytes <= 2);
- bodyOctets -= termCrlfBytes;
+ term_crlf_bytes = chunk_octets - data_length;
+ assert(term_crlf_bytes <= 2);
+ body_octets -= term_crlf_bytes;
// Check for correct CRLF termination. Beware the section might break just before chunk end.
- if ( ! ( ((termCrlfBytes == 2) && (msgText.length >= 2) && (msgText.start[msgText.length-2] == '\r') && (msgText.start[msgText.length-1] == '\n')) ||
- ((termCrlfBytes == 2) && (msgText.length == 1) && (msgText.start[msgText.length-1] == '\n')) ||
- ((termCrlfBytes == 1) && (msgText.start[msgText.length-1] == '\r')) ) ) {
+ if ( ! ( ((term_crlf_bytes == 2) && (msg_text.length >= 2) && (msg_text.start[msg_text.length-2] == '\r') && (msg_text.start[msg_text.length-1] == '\n')) ||
+ ((term_crlf_bytes == 2) && (msg_text.length == 1) && (msg_text.start[msg_text.length-1] == '\n')) ||
+ ((term_crlf_bytes == 1) && (msg_text.start[msg_text.length-1] == '\r')) ) ) {
infractions |= INF_BROKENCHUNK;
}
}
- data.start = msgText.start;
- data.length = msgText.length - termCrlfBytes;
+ data.start = msg_text.start;
+ data.length = msg_text.length - term_crlf_bytes;
- chunkSections++;
+ chunk_sections++;
// The following statement tests for the case where streams underfulfilled flush due to a TCP connection close
- if ((msgText.length < 16384) && (bodyOctets + termCrlfBytes < dataLength + 2)) tcpClose = true;
- if (tcpClose) infractions |= INF_TRUNCATED;
+ if ((msg_text.length < 16384) && (body_octets + term_crlf_bytes < data_length + 2)) tcp_close = true;
+ if (tcp_close) infractions |= INF_TRUNCATED;
}
-void NHttpMsgChunkBody::genEvents() {}
+void NHttpMsgChunkBody::gen_events() {}
-void NHttpMsgChunkBody::printSection(FILE *output) {
- NHttpMsgSection::printMessageTitle(output, "chunk body");
- fprintf(output, "Expected chunk length %" PRIi64 ", cumulative sections %" PRIi64 ", cumulative octets %" PRIi64 "\n", dataLength, bodySections, bodyOctets);
- fprintf(output, "cumulative chunk sections %" PRIi64 ", cumulative chunk octets %" PRIi64 "\n", chunkSections, chunkOctets);
+void NHttpMsgChunkBody::print_section(FILE *output) {
+ NHttpMsgSection::print_message_title(output, "chunk body");
+ fprintf(output, "Expected chunk length %" PRIi64 ", cumulative sections %" PRIi64 ", cumulative octets %" PRIi64 "\n", data_length, body_sections, body_octets);
+ fprintf(output, "cumulative chunk sections %" PRIi64 ", cumulative chunk octets %" PRIi64 "\n", chunk_sections, chunk_octets);
data.print(output, "Data");
- NHttpMsgSection::printMessageWrapup(output);
+ NHttpMsgSection::print_message_wrapup(output);
}
-void NHttpMsgChunkBody::updateFlow() {
- if (tcpClose) {
- sessionData->typeExpected[sourceId] = SEC_CLOSED;
- sessionData->halfReset(sourceId);
+void NHttpMsgChunkBody::update_flow() {
+ if (tcp_close) {
+ session_data->type_expected[source_id] = SEC_CLOSED;
+ session_data->half_reset(source_id);
}
- else if (chunkOctets < dataLength + 2) {
- sessionData->bodySections[sourceId] = bodySections;
- sessionData->bodyOctets[sourceId] = bodyOctets;
- sessionData->chunkSections[sourceId] = chunkSections;
- sessionData->chunkOctets[sourceId] = chunkOctets;
+ else if (chunk_octets < data_length + 2) {
+ session_data->body_sections[source_id] = body_sections;
+ session_data->body_octets[source_id] = body_octets;
+ session_data->chunk_sections[source_id] = chunk_sections;
+ session_data->chunk_octets[source_id] = chunk_octets;
}
else {
- sessionData->typeExpected[sourceId] = SEC_CHUNKHEAD;
- sessionData->octetsExpected[sourceId] = STAT_NOTPRESENT;
- sessionData->dataLength[sourceId] = STAT_NOTPRESENT;
- sessionData->bodySections[sourceId] = bodySections;
- sessionData->bodyOctets[sourceId] = bodyOctets;
- sessionData->chunkSections[sourceId] = STAT_NOTPRESENT;
- sessionData->chunkOctets[sourceId] = STAT_NOTPRESENT;
+ session_data->type_expected[source_id] = SEC_CHUNKHEAD;
+ session_data->octets_expected[source_id] = STAT_NOTPRESENT;
+ session_data->data_length[source_id] = STAT_NOTPRESENT;
+ session_data->body_sections[source_id] = body_sections;
+ session_data->body_octets[source_id] = body_octets;
+ session_data->chunk_sections[source_id] = STAT_NOTPRESENT;
+ session_data->chunk_octets[source_id] = STAT_NOTPRESENT;
}
}
class NHttpMsgChunkBody : public NHttpMsgBody {
public:
- NHttpMsgChunkBody(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_);
+ NHttpMsgChunkBody(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, NHttpEnums::SourceId source_id_);
void analyze();
- void printSection(FILE *output);
- void genEvents();
- void updateFlow();
+ void print_section(FILE *output);
+ void gen_events();
+ void update_flow();
private:
- // int64_t numChunks; // will be needed in future commented out to please compiler &&&
- int64_t chunkSections;
- int64_t chunkOctets;
+ // int64_t num_chunks; // will be needed in future commented out to please compiler &&&
+ int64_t chunk_sections;
+ int64_t chunk_octets;
};
#endif
using namespace NHttpEnums;
-NHttpMsgChunkHead::NHttpMsgChunkHead(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, SourceId sourceId_) :
- NHttpMsgSection(buffer, bufSize, sessionData_, sourceId_), bodySections(sessionData->bodySections[sourceId]),
- numChunks(sessionData->numChunks[sourceId]) {
- delete sessionData->latestOther[sourceId];
- sessionData->latestOther[sourceId] = this;
+NHttpMsgChunkHead::NHttpMsgChunkHead(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, SourceId source_id_) :
+ NHttpMsgSection(buffer, buf_size, session_data_, source_id_), body_sections(session_data->body_sections[source_id]),
+ num_chunks(session_data->num_chunks[source_id]) {
+ delete session_data->latest_other[source_id];
+ session_data->latest_other[source_id] = this;
}
// Convert the hexadecimal chunk length.
// RFC says that zero may be written with multiple digits "000000".
// Arbitrary limit of 15 hex digits not including leading zeros ensures in a simple way against 64-bit overflow and should be
// vastly bigger than any legitimate chunk.
-void NHttpMsgChunkHead::deriveChunkLength() {
- if (chunkSize.length <= 0) {
- dataLength = STAT_NOSOURCE;
+void NHttpMsgChunkHead::derive_chunk_length() {
+ if (chunk_size.length <= 0) {
+ data_length = STAT_NOSOURCE;
infractions |= INF_BADCHUNKSIZE;
return;
}
- dataLength = 0;
- int nonLeadingZeros = 0;
- for (int k=0; k < chunkSize.length; k++) {
- if (nonLeadingZeros || (chunkSize.start[k] != '0')) nonLeadingZeros++;
- if (nonLeadingZeros > 15) {
- dataLength = STAT_PROBLEMATIC;
+ data_length = 0;
+ int non_leading_zeros = 0;
+ for (int k=0; k < chunk_size.length; k++) {
+ if (non_leading_zeros || (chunk_size.start[k] != '0')) non_leading_zeros++;
+ if (non_leading_zeros > 15) {
+ data_length = STAT_PROBLEMATIC;
infractions |= INF_BADCHUNKSIZE;
return;
}
- dataLength *= 16;
- if ((chunkSize.start[k] >= '0') && (chunkSize.start[k] <= '9')) dataLength += chunkSize.start[k] - '0';
- else if ((chunkSize.start[k] >= 'A') && (chunkSize.start[k] <= 'F')) dataLength += chunkSize.start[k] - 'A' + 10;
- else if ((chunkSize.start[k] >= 'a') && (chunkSize.start[k] <= 'f')) dataLength += chunkSize.start[k] - 'a' + 10;
+ data_length *= 16;
+ if ((chunk_size.start[k] >= '0') && (chunk_size.start[k] <= '9')) data_length += chunk_size.start[k] - '0';
+ else if ((chunk_size.start[k] >= 'A') && (chunk_size.start[k] <= 'F')) data_length += chunk_size.start[k] - 'A' + 10;
+ else if ((chunk_size.start[k] >= 'a') && (chunk_size.start[k] <= 'f')) data_length += chunk_size.start[k] - 'a' + 10;
else {
- dataLength = STAT_PROBLEMATIC;
+ data_length = STAT_PROBLEMATIC;
infractions |= INF_BADCHUNKSIZE;
return;
}
}
void NHttpMsgChunkHead::analyze() {
- bodySections++;
+ body_sections++;
// First section in a new chunk is just the start line.
- numChunks++;
- startLine.start = msgText.start;
- if (!tcpClose) startLine.length = msgText.length - 2;
- else startLine.length = findCrlf(startLine.start, msgText.length, false);
- chunkSize.start = msgText.start;
+ num_chunks++;
+ start_line.start = msg_text.start;
+ if (!tcp_close) {
+ start_line.length = msg_text.length - 2;
+ }
+ else {
+ start_line.length = find_crlf(start_line.start, msg_text.length, false);
+ }
+ chunk_size.start = msg_text.start;
// Start line format is chunk size in hex followed by optional semicolon and extensions field
- for (chunkSize.length = 0; (chunkSize.length < startLine.length) && (startLine.start[chunkSize.length] != ';'); chunkSize.length++);
- if (chunkSize.length == startLine.length) {
- chunkExtensions.length = STAT_NOTPRESENT;
+ for (chunk_size.length = 0; (chunk_size.length < start_line.length) && (start_line.start[chunk_size.length] != ';'); chunk_size.length++);
+ if (chunk_size.length == start_line.length) {
+ chunk_extensions.length = STAT_NOTPRESENT;
}
- else if (chunkSize.length == startLine.length - 1) {
- chunkExtensions.length = STAT_EMPTYSTRING;
+ else if (chunk_size.length == start_line.length - 1) {
+ chunk_extensions.length = STAT_EMPTYSTRING;
}
else {
- chunkExtensions.start = msgText.start + chunkSize.length + 1;
- chunkExtensions.length = startLine.length - chunkSize.length - 1;
+ chunk_extensions.start = msg_text.start + chunk_size.length + 1;
+ chunk_extensions.length = start_line.length - chunk_size.length - 1;
}
- deriveChunkLength();
- if (tcpClose) infractions |= INF_TRUNCATED;
+ derive_chunk_length();
+ if (tcp_close) infractions |= INF_TRUNCATED;
}
-void NHttpMsgChunkHead::genEvents() {}
+void NHttpMsgChunkHead::gen_events() {}
-void NHttpMsgChunkHead::printSection(FILE *output) {
- NHttpMsgSection::printMessageTitle(output, "chunk header");
- fprintf(output, "Chunk size: %" PRIi64 "\n", dataLength);
- chunkExtensions.print(output, "Chunk extensions");
- NHttpMsgSection::printMessageWrapup(output);
+void NHttpMsgChunkHead::print_section(FILE *output) {
+ NHttpMsgSection::print_message_title(output, "chunk header");
+ fprintf(output, "Chunk size: %" PRIi64 "\n", data_length);
+ chunk_extensions.print(output, "Chunk extensions");
+ NHttpMsgSection::print_message_wrapup(output);
}
-void NHttpMsgChunkHead::updateFlow() {
- if (tcpClose) {
- sessionData->typeExpected[sourceId] = SEC_CLOSED;
- sessionData->halfReset(sourceId);
+void NHttpMsgChunkHead::update_flow() {
+ if (tcp_close) {
+ session_data->type_expected[source_id] = SEC_CLOSED;
+ session_data->half_reset(source_id);
}
- else if (dataLength > 0) {
- sessionData->typeExpected[sourceId] = SEC_CHUNKBODY;
- sessionData->octetsExpected[sourceId] = dataLength+2;
- sessionData->bodySections[sourceId] = bodySections;
- sessionData->numChunks[sourceId] = numChunks;
- sessionData->dataLength[sourceId] = dataLength;
- sessionData->chunkSections[sourceId] = 0;
- sessionData->chunkOctets[sourceId] = 0;
+ else if (data_length > 0) {
+ session_data->type_expected[source_id] = SEC_CHUNKBODY;
+ session_data->octets_expected[source_id] = data_length+2;
+ session_data->body_sections[source_id] = body_sections;
+ session_data->num_chunks[source_id] = num_chunks;
+ session_data->data_length[source_id] = data_length;
+ session_data->chunk_sections[source_id] = 0;
+ session_data->chunk_octets[source_id] = 0;
}
else {
// This was zero-length last chunk, trailer comes next
- sessionData->typeExpected[sourceId] = SEC_TRAILER;
- sessionData->halfReset(sourceId);
+ session_data->type_expected[source_id] = SEC_TRAILER;
+ session_data->half_reset(source_id);
}
}
// Legacy support function. Puts message fields into the buffers used by old Snort.
-void NHttpMsgChunkHead::legacyClients() {
+void NHttpMsgChunkHead::legacy_clients() {
ClearHttpBuffers();
- if (startLine.length > 0) SetHttpBuffer(HTTP_BUFFER_CLIENT_BODY, startLine.start, (unsigned)startLine.length);
+ if (start_line.length > 0) SetHttpBuffer(HTTP_BUFFER_CLIENT_BODY, start_line.start, (unsigned)start_line.length);
}
class NHttpMsgChunkHead : public NHttpMsgSection {
public:
- NHttpMsgChunkHead(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_);
+ NHttpMsgChunkHead(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, NHttpEnums::SourceId source_id_);
void analyze();
- void printSection(FILE *output);
- void genEvents();
- void updateFlow();
- void legacyClients();
+ void print_section(FILE *output);
+ void gen_events();
+ void update_flow();
+ void legacy_clients();
private:
- void deriveChunkLength();
+ void derive_chunk_length();
- Field startLine;
- Field chunkSize;
- Field chunkExtensions;
+ Field start_line;
+ Field chunk_size;
+ Field chunk_extensions;
- int64_t dataLength = NHttpEnums::STAT_NOTCOMPUTE;
- int64_t bodySections;
- int64_t numChunks;
+ int64_t data_length = NHttpEnums::STAT_NOTCOMPUTE;
+ int64_t body_sections;
+ int64_t num_chunks;
};
#endif
// All the header processing that is done for every message (i.e. not just-in-time) is done here.
void NHttpMsgHeadShared::analyze() {
- parseWhole();
- parseHeaderBlock();
- parseHeaderLines();
- for (int j=0; j < numHeaders; j++) {
- deriveHeaderNameId(j);
- if (headerNameId[j] > 0) headerCount[headerNameId[j]]++;
+ parse_whole();
+ parse_header_block();
+ parse_header_lines();
+ for (int j=0; j < num_headers; j++) {
+ derive_header_name_id(j);
+ if (header_name_id[j] > 0) header_count[header_name_id[j]]++;
}
}
-void NHttpMsgHeadShared::parseWhole() {
+void NHttpMsgHeadShared::parse_whole() {
// Normal case with header fields
- if (!tcpClose && (msgText.length >= 5)) {
- headers.start = msgText.start;
- headers.length = msgText.length - 4;
- assert(!memcmp(msgText.start+msgText.length-4, "\r\n\r\n", 4));
+ if (!tcp_close && (msg_text.length >= 5)) {
+ headers.start = msg_text.start;
+ headers.length = msg_text.length - 4;
+ assert(!memcmp(msg_text.start+msg_text.length-4, "\r\n\r\n", 4));
}
// Normal case no header fields
- else if (!tcpClose) {
+ else if (!tcp_close) {
headers.length = STAT_NOTPRESENT;
- assert((msgText.length == 2) && !memcmp(msgText.start, "\r\n", 2));
+ assert((msg_text.length == 2) && !memcmp(msg_text.start, "\r\n", 2));
}
// Normal case with header fields and TCP connection close
- else if ((msgText.length >= 5) && !memcmp(msgText.start+msgText.length-4, "\r\n\r\n", 4)) {
- headers.start = msgText.start;
- headers.length = msgText.length - 4;
+ else if ((msg_text.length >= 5) && !memcmp(msg_text.start+msg_text.length-4, "\r\n\r\n", 4)) {
+ headers.start = msg_text.start;
+ headers.length = msg_text.length - 4;
}
// Normal case no header fields and TCP connection close
- else if ((msgText.length == 2) && !memcmp(msgText.start, "\r\n", 2)) {
+ else if ((msg_text.length == 2) && !memcmp(msg_text.start, "\r\n", 2)) {
headers.length = STAT_NOTPRESENT;
}
// Abnormal cases truncated by TCP connection close
else {
infractions |= INF_TRUNCATED;
// Lone <CR>
- if ((msgText.length == 1) && (msgText.start[0] == '\r')) {
+ if ((msg_text.length == 1) && (msg_text.start[0] == '\r')) {
headers.length = STAT_NOTPRESENT;
}
// Truncation occurred somewhere in the header fields
else {
- headers.start = msgText.start;
- headers.length = msgText.length;
+ headers.start = msg_text.start;
+ headers.length = msg_text.length;
// When present, remove partial <CR><LF><CR><LF> sequence from the end
- if ((msgText.length >= 4) && !memcmp(msgText.start+msgText.length-3, "\r\n\r", 3)) headers.length -= 3;
- else if ((msgText.length >= 3) && !memcmp(msgText.start+msgText.length-2, "\r\n", 2)) headers.length -= 2;
- else if ((msgText.length >= 2) && (msgText.start[msgText.length-1] == '\r')) headers.length -= 1;
+ if ((msg_text.length >= 4) && !memcmp(msg_text.start+msg_text.length-3, "\r\n\r", 3)) headers.length -= 3;
+ else if ((msg_text.length >= 3) && !memcmp(msg_text.start+msg_text.length-2, "\r\n", 2)) headers.length -= 2;
+ else if ((msg_text.length >= 2) && (msg_text.start[msg_text.length-1] == '\r')) headers.length -= 1;
}
}
}
// Divide up the block of header fields into individual header field lines.
-void NHttpMsgHeadShared::parseHeaderBlock() {
+void NHttpMsgHeadShared::parse_header_block() {
if (headers.length < 0) {
- numHeaders = STAT_NOSOURCE;
+ num_headers = STAT_NOSOURCE;
return;
}
- int32_t bytesUsed = 0;
- numHeaders = 0;
- while (bytesUsed < headers.length) {
- headerLine[numHeaders].start = headers.start + bytesUsed;
- headerLine[numHeaders].length = findCrlf(headerLine[numHeaders].start, headers.length - bytesUsed, true);
- bytesUsed += headerLine[numHeaders++].length + 2;
- if (numHeaders >= MAXHEADERS) {
+ int32_t bytes_used = 0;
+ num_headers = 0;
+ while (bytes_used < headers.length) {
+ header_line[num_headers].start = headers.start + bytes_used;
+ header_line[num_headers].length = find_crlf(header_line[num_headers].start, headers.length - bytes_used, true);
+ bytes_used += header_line[num_headers++].length + 2;
+ if (num_headers >= MAXHEADERS) {
break;
}
}
- if (bytesUsed < headers.length) {
+ if (bytes_used < headers.length) {
infractions |= INF_TOOMANYHEADERS;
}
}
// Divide header field lines into field name and field value
-void NHttpMsgHeadShared::parseHeaderLines() {
+void NHttpMsgHeadShared::parse_header_lines() {
int colon;
- for (int k=0; k < numHeaders; k++) {
- for (colon=0; colon < headerLine[k].length; colon++) {
- if (headerLine[k].start[colon] == ':') break;
+ for (int k=0; k < num_headers; k++) {
+ for (colon=0; colon < header_line[k].length; colon++) {
+ if (header_line[k].start[colon] == ':') break;
}
- if (colon < headerLine[k].length) {
- headerName[k].start = headerLine[k].start;
- headerName[k].length = colon;
- headerValue[k].start = headerLine[k].start + colon + 1;
- headerValue[k].length = headerLine[k].length - colon - 1;
+ if (colon < header_line[k].length) {
+ header_name[k].start = header_line[k].start;
+ header_name[k].length = colon;
+ header_value[k].start = header_line[k].start + colon + 1;
+ header_value[k].length = header_line[k].length - colon - 1;
}
else {
infractions |= INF_BADHEADER;
}
}
-void NHttpMsgHeadShared::deriveHeaderNameId(int index) {
+void NHttpMsgHeadShared::derive_header_name_id(int index) {
// Normalize header field name to lower case for matching purposes
- uint8_t *lowerName;
- if ((lowerName = scratchPad.request(headerName[index].length)) == nullptr) {
+ uint8_t *lower_name;
+ if ((lower_name = scratch_pad.request(header_name[index].length)) == nullptr) {
infractions |= INF_NOSCRATCH;
- headerNameId[index] = HEAD__INSUFMEMORY;
+ header_name_id[index] = HEAD__INSUFMEMORY;
return;
}
- norm2Lower(headerName[index].start, headerName[index].length, lowerName, infractions, nullptr);
- headerNameId[index] = (HeaderId) strToCode(lowerName, headerName[index].length, headerList);
+ norm_to_lower(header_name[index].start, header_name[index].length, lower_name, infractions, nullptr);
+ header_name_id[index] = (HeaderId) str_to_code(lower_name, header_name[index].length, header_list);
}
-void NHttpMsgHeadShared::genEvents() {
- if (infractions & INF_TOOMANYHEADERS) createEvent(EVENT_MAX_HEADERS);
+void NHttpMsgHeadShared::gen_events() {
+ if (infractions & INF_TOOMANYHEADERS) create_event(EVENT_MAX_HEADERS);
}
// Legacy support function. Puts message fields into the buffers used by old Snort.
-void NHttpMsgHeadShared::legacyClients() {
+void NHttpMsgHeadShared::legacy_clients() {
ClearHttpBuffers();
if (headers.length > 0) SetHttpBuffer(HTTP_BUFFER_RAW_HEADER, headers.start, (unsigned)headers.length);
if (headers.length > 0) SetHttpBuffer(HTTP_BUFFER_HEADER, headers.start, (unsigned)headers.length);
- for (int k=0; k < numHeaders; k++) {
- if (((headerNameId[k] == HEAD_COOKIE) && (sourceId == SRC_CLIENT)) || ((headerNameId[k] == HEAD_SET_COOKIE) && (sourceId == SRC_SERVER))) {
- if (headerValue[k].length > 0) SetHttpBuffer(HTTP_BUFFER_RAW_COOKIE, headerValue[k].start, (unsigned)headerValue[k].length);
+ for (int k=0; k < num_headers; k++) {
+ if (((header_name_id[k] == HEAD_COOKIE) && (source_id == SRC_CLIENT)) || ((header_name_id[k] == HEAD_SET_COOKIE) && (source_id == SRC_SERVER))) {
+ if (header_value[k].length > 0) SetHttpBuffer(HTTP_BUFFER_RAW_COOKIE, header_value[k].start, (unsigned)header_value[k].length);
break;
}
}
- if (sourceId == SRC_CLIENT) {
- if (headerNorms[HEAD_COOKIE]->normalize(HEAD_COOKIE, headerCount[HEAD_COOKIE], scratchPad, infractions,
- headerNameId, headerValue, numHeaders, headerValueNorm[HEAD_COOKIE]) > 0) {
- SetHttpBuffer(HTTP_BUFFER_COOKIE, headerValueNorm[HEAD_COOKIE].start, (unsigned)headerValueNorm[HEAD_COOKIE].length);
+ if (source_id == SRC_CLIENT) {
+ if (header_norms[HEAD_COOKIE]->normalize(HEAD_COOKIE, header_count[HEAD_COOKIE], scratch_pad, infractions,
+ header_name_id, header_value, num_headers, header_value_norm[HEAD_COOKIE]) > 0) {
+ SetHttpBuffer(HTTP_BUFFER_COOKIE, header_value_norm[HEAD_COOKIE].start, (unsigned)header_value_norm[HEAD_COOKIE].length);
}
}
else {
- if (headerNorms[HEAD_SET_COOKIE]->normalize(HEAD_SET_COOKIE, headerCount[HEAD_SET_COOKIE], scratchPad, infractions,
- headerNameId, headerValue, numHeaders, headerValueNorm[HEAD_SET_COOKIE]) > 0) {
- SetHttpBuffer(HTTP_BUFFER_COOKIE, headerValueNorm[HEAD_SET_COOKIE].start, (unsigned)headerValueNorm[HEAD_SET_COOKIE].length);
+ if (header_norms[HEAD_SET_COOKIE]->normalize(HEAD_SET_COOKIE, header_count[HEAD_SET_COOKIE], scratch_pad, infractions,
+ header_name_id, header_value, num_headers, header_value_norm[HEAD_SET_COOKIE]) > 0) {
+ SetHttpBuffer(HTTP_BUFFER_COOKIE, header_value_norm[HEAD_SET_COOKIE].start, (unsigned)header_value_norm[HEAD_SET_COOKIE].length);
}
}
}
-void NHttpMsgHeadShared::printHeaders(FILE *output) {
- char titleBuf[100];
- if (numHeaders != STAT_NOSOURCE) fprintf(output, "Number of headers: %d\n", numHeaders);
- for (int j=0; j < numHeaders; j++) {
- snprintf(titleBuf, sizeof(titleBuf), "Header ID %d", headerNameId[j]);
- headerValue[j].print(output, titleBuf);
- }
- for (int k=1; k <= numNorms; k++) {
- if (headerNorms[k]->normalize((HeaderId)k, headerCount[k], scratchPad, infractions, headerNameId, headerValue, numHeaders, headerValueNorm[k]) != STAT_NOSOURCE) {
- snprintf(titleBuf, sizeof(titleBuf), "Normalized header %d", k);
- headerValueNorm[k].print(output, titleBuf, true);
+void NHttpMsgHeadShared::print_headers(FILE *output) {
+ char title_buf[100];
+ if (num_headers != STAT_NOSOURCE) fprintf(output, "Number of headers: %d\n", num_headers);
+ for (int j=0; j < num_headers; j++) {
+ snprintf(title_buf, sizeof(title_buf), "Header ID %d", header_name_id[j]);
+ header_value[j].print(output, title_buf);
+ }
+ for (int k=1; k <= num_norms; k++) {
+ if (header_norms[k]->normalize((HeaderId)k, header_count[k], scratch_pad, infractions, header_name_id, header_value, num_headers, header_value_norm[k]) != STAT_NOSOURCE) {
+ snprintf(title_buf, sizeof(title_buf), "Normalized header %d", k);
+ header_value_norm[k].print(output, title_buf, true);
}
}
}
class NHttpMsgHeadShared: public NHttpMsgSection {
public:
void analyze();
- void genEvents();
- void legacyClients();
+ void gen_events();
+ void legacy_clients();
protected:
- NHttpMsgHeadShared(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_) :
- NHttpMsgSection(buffer, bufSize, sessionData_, sourceId_) {};
+ NHttpMsgHeadShared(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_,
+ NHttpEnums::SourceId source_id_) : NHttpMsgSection(buffer, buf_size, session_data_, source_id_) {};
- // Header normalization strategies. There should be one of these for every different way we can process a header field value.
+ // Header normalization strategies. There should be one of these for every different way we can process
+ // a header field value.
static const HeaderNormalizer NORMALIZER_NIL;
static const HeaderNormalizer NORMALIZER_BASIC;
static const HeaderNormalizer NORMALIZER_CAT;
static const HeaderNormalizer NORMALIZER_TRANSCODE;
// Master table of known header fields and their normalization strategies.
- static const HeaderNormalizer* const headerNorms[];
- static const int32_t numNorms;
+ static const HeaderNormalizer* const header_norms[];
+ static const int32_t num_norms;
// Tables of header field names and header value names
- static const StrCode headerList[];
- static const StrCode transCodeList[];
+ static const StrCode header_list[];
+ static const StrCode trans_code_list[];
- void parseWhole();
- void parseHeaderBlock();
- void parseHeaderLines();
- void deriveHeaderNameId(int index);
+ void parse_whole();
+ void parse_header_block();
+ void parse_header_lines();
+ void derive_header_name_id(int index);
- void printHeaders(FILE *output);
+ void print_headers(FILE *output);
Field headers;
// All of these are indexed by the relative position of the header field in the message
static const int MAXHEADERS = 200; // I'm an arbitrary number. Need to revisit.
- int32_t numHeaders = NHttpEnums::STAT_NOTCOMPUTE;
- Field headerLine[MAXHEADERS];
- Field headerName[MAXHEADERS];
- NHttpEnums::HeaderId headerNameId[MAXHEADERS];
- Field headerValue[MAXHEADERS];
+ int32_t num_headers = NHttpEnums::STAT_NOTCOMPUTE;
+ Field header_line[MAXHEADERS];
+ Field header_name[MAXHEADERS];
+ NHttpEnums::HeaderId header_name_id[MAXHEADERS];
+ Field header_value[MAXHEADERS];
// Normalized values are indexed by HeaderId
- int headerCount[NHttpEnums::HEAD__MAXVALUE] = { };
- Field headerValueNorm[NHttpEnums::HEAD__MAXVALUE];
+ int header_count[NHttpEnums::HEAD__MAXVALUE] = { };
+ Field header_value_norm[NHttpEnums::HEAD__MAXVALUE];
};
#endif
using namespace NHttpEnums;
-NHttpMsgHeader::NHttpMsgHeader(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, SourceId sourceId_) :
- NHttpMsgHeadShared(buffer, bufSize, sessionData_, sourceId_) {
- sessionData->headers[sourceId] = this;
+NHttpMsgHeader::NHttpMsgHeader(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, SourceId source_id_) :
+ NHttpMsgHeadShared(buffer, buf_size, session_data_, source_id_) {
+ session_data->headers[source_id] = this;
}
-void NHttpMsgHeader::genEvents() {
- NHttpMsgHeadShared::genEvents();
- if (headerCount[HEAD_CONTENT_LENGTH] > 1) createEvent(EVENT_MULTIPLE_CONTLEN);
+void NHttpMsgHeader::gen_events() {
+ NHttpMsgHeadShared::gen_events();
+ if (header_count[HEAD_CONTENT_LENGTH] > 1) create_event(EVENT_MULTIPLE_CONTLEN);
}
-void NHttpMsgHeader::printSection(FILE *output) {
- NHttpMsgSection::printMessageTitle(output, "header");
- NHttpMsgHeadShared::printHeaders(output);
- NHttpMsgSection::printMessageWrapup(output);
+void NHttpMsgHeader::print_section(FILE *output) {
+ NHttpMsgSection::print_message_title(output, "header");
+ NHttpMsgHeadShared::print_headers(output);
+ NHttpMsgSection::print_message_wrapup(output);
}
-void NHttpMsgHeader::updateFlow() {
- const uint64_t disasterMask = 0;
+void NHttpMsgHeader::update_flow() {
+ const uint64_t disaster_mask = 0;
// The following logic to determine body type is by no means the last word on this topic.
- if (tcpClose) {
- sessionData->typeExpected[sourceId] = SEC_CLOSED;
- sessionData->halfReset(sourceId);
+ if (tcp_close) {
+ session_data->type_expected[source_id] = SEC_CLOSED;
+ session_data->half_reset(source_id);
}
- else if (infractions & disasterMask) {
- sessionData->typeExpected[sourceId] = SEC_ABORT;
- sessionData->halfReset(sourceId);
+ else if (infractions & disaster_mask) {
+ session_data->type_expected[source_id] = SEC_ABORT;
+ session_data->half_reset(source_id);
}
- else if ((sourceId == SRC_SERVER) && ((statusCodeNum <= 199) || (statusCodeNum == 204) || (statusCodeNum == 304))) {
+ else if ((source_id == SRC_SERVER) && ((status_code_num <= 199) || (status_code_num == 204) || (status_code_num == 304))) {
// No body allowed by RFC for these response codes
- sessionData->typeExpected[sourceId] = (sourceId == SRC_CLIENT) ? SEC_REQUEST : SEC_STATUS;
- sessionData->halfReset(sourceId);
+ session_data->type_expected[source_id] = (source_id == SRC_CLIENT) ? SEC_REQUEST : SEC_STATUS;
+ session_data->half_reset(source_id);
}
// If there is a Transfer-Encoding header, see if the last of the encoded values is "chunked".
- else if ( (headerNorms[HEAD_TRANSFER_ENCODING]->normalize(HEAD_TRANSFER_ENCODING, headerCount[HEAD_TRANSFER_ENCODING],
- scratchPad, infractions, headerNameId, headerValue, numHeaders, headerValueNorm[HEAD_TRANSFER_ENCODING]) > 0) &&
- ((*(int64_t *)(headerValueNorm[HEAD_TRANSFER_ENCODING].start + (headerValueNorm[HEAD_TRANSFER_ENCODING].length - 8))) == TRANSCODE_CHUNKED) ) {
+ else if ( (header_norms[HEAD_TRANSFER_ENCODING]->normalize(HEAD_TRANSFER_ENCODING, header_count[HEAD_TRANSFER_ENCODING],
+ scratch_pad, infractions, header_name_id, header_value, num_headers, header_value_norm[HEAD_TRANSFER_ENCODING]) > 0) &&
+ ((*(int64_t *)(header_value_norm[HEAD_TRANSFER_ENCODING].start + (header_value_norm[HEAD_TRANSFER_ENCODING].length - 8))) == TRANSCODE_CHUNKED) ) {
// Chunked body
- sessionData->typeExpected[sourceId] = SEC_CHUNKHEAD;
- sessionData->bodySections[sourceId] = 0;
- sessionData->bodyOctets[sourceId] = 0;
- sessionData->numChunks[sourceId] = 0;
+ session_data->type_expected[source_id] = SEC_CHUNKHEAD;
+ session_data->body_sections[source_id] = 0;
+ session_data->body_octets[source_id] = 0;
+ session_data->num_chunks[source_id] = 0;
}
- else if ((headerNorms[HEAD_CONTENT_LENGTH]->normalize(HEAD_CONTENT_LENGTH, headerCount[HEAD_CONTENT_LENGTH],
- scratchPad, infractions, headerNameId, headerValue, numHeaders, headerValueNorm[HEAD_CONTENT_LENGTH]) > 0) &&
- (*(int64_t*)headerValueNorm[HEAD_CONTENT_LENGTH].start > 0)) {
+ else if ((header_norms[HEAD_CONTENT_LENGTH]->normalize(HEAD_CONTENT_LENGTH, header_count[HEAD_CONTENT_LENGTH],
+ scratch_pad, infractions, header_name_id, header_value, num_headers, header_value_norm[HEAD_CONTENT_LENGTH]) > 0) &&
+ (*(int64_t*)header_value_norm[HEAD_CONTENT_LENGTH].start > 0)) {
// Regular body
- sessionData->typeExpected[sourceId] = SEC_BODY;
- sessionData->octetsExpected[sourceId] = *(int64_t*)headerValueNorm[HEAD_CONTENT_LENGTH].start;
- sessionData->dataLength[sourceId] = *(int64_t*)headerValueNorm[HEAD_CONTENT_LENGTH].start;
- sessionData->bodySections[sourceId] = 0;
- sessionData->bodyOctets[sourceId] = 0;
+ session_data->type_expected[source_id] = SEC_BODY;
+ session_data->octets_expected[source_id] = *(int64_t*)header_value_norm[HEAD_CONTENT_LENGTH].start;
+ session_data->data_length[source_id] = *(int64_t*)header_value_norm[HEAD_CONTENT_LENGTH].start;
+ session_data->body_sections[source_id] = 0;
+ session_data->body_octets[source_id] = 0;
}
else {
// No body
- sessionData->typeExpected[sourceId] = (sourceId == SRC_CLIENT) ? SEC_REQUEST : SEC_STATUS;
- sessionData->halfReset(sourceId);
+ session_data->type_expected[source_id] = (source_id == SRC_CLIENT) ? SEC_REQUEST : SEC_STATUS;
+ session_data->half_reset(source_id);
}
}
class NHttpMsgHeader: public NHttpMsgHeadShared {
public:
- NHttpMsgHeader(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_);
- void printSection(FILE *output);
- void genEvents();
- void updateFlow();
+ NHttpMsgHeader(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, NHttpEnums::SourceId source_id_);
+ void print_section(FILE *output);
+ void gen_events();
+ void update_flow();
};
#endif
using namespace NHttpEnums;
-NHttpMsgRequest::NHttpMsgRequest(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, SourceId sourceId_) :
- NHttpMsgStart(buffer, bufSize, sessionData_, sourceId_) {
- delete sessionData->requestLine;
- sessionData->requestLine = this;
- delete sessionData->headers[SRC_CLIENT];
- sessionData->headers[SRC_CLIENT] = nullptr;
- delete sessionData->latestOther[SRC_CLIENT];
- sessionData->latestOther[SRC_CLIENT] = nullptr;
+NHttpMsgRequest::NHttpMsgRequest(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, SourceId source_id_) :
+ NHttpMsgStart(buffer, buf_size, session_data_, source_id_) {
+ delete session_data->request_line;
+ session_data->request_line = this;
+ delete session_data->headers[SRC_CLIENT];
+ session_data->headers[SRC_CLIENT] = nullptr;
+ delete session_data->latest_other[SRC_CLIENT];
+ session_data->latest_other[SRC_CLIENT] = nullptr;
}
-void NHttpMsgRequest::parseStartLine() {
+void NHttpMsgRequest::parse_start_line() {
// There should be exactly two spaces. One following the method and one before "HTTP/".
// Additional spaces located within the URI are not allowed but we will tolerate it
// <method><SP><URI><SP>HTTP/X.Y
- if (startLine.start[startLine.length-9] != ' ') {
+ if (start_line.start[start_line.length-9] != ' ') {
// space before "HTTP" missing or in wrong place
infractions |= INF_BADREQLINE;
return;
}
int32_t space;
- for (space = 0; space < startLine.length-9; space++) {
- if (startLine.start[space] == ' ') break;
+ for (space = 0; space < start_line.length-9; space++) {
+ if (start_line.start[space] == ' ') break;
}
- if (space >= startLine.length-9) {
+ if (space >= start_line.length-9) {
// leading space or no space
infractions |= INF_BADREQLINE;
return;
}
- method.start = startLine.start;
+ method.start = start_line.start;
method.length = space;
- deriveMethodId();
- uri = new NHttpUri(startLine.start + method.length + 1, startLine.length - method.length - 10, methodId);
- version.start = startLine.start + (startLine.length - 8);
+ derive_method_id();
+ uri = new NHttpUri(start_line.start + method.length + 1, start_line.length - method.length - 10, method_id);
+ version.start = start_line.start + (start_line.length - 8);
version.length = 8;
- assert (startLine.length == method.length + uri->getUri().length + version.length + 2);
+ assert (start_line.length == method.length + uri->get_uri().length + version.length + 2);
}
-void NHttpMsgRequest::deriveMethodId() {
+void NHttpMsgRequest::derive_method_id() {
if (method.length <= 0) {
- methodId = METH__NOSOURCE;
+ method_id = METH__NOSOURCE;
return;
}
- methodId = (MethodId) strToCode(method.start, method.length, methodList);
+ method_id = (MethodId) str_to_code(method.start, method.length, method_list);
}
-const Field& NHttpMsgRequest::getUri() {
+const Field& NHttpMsgRequest::get_uri() {
if (uri != nullptr) {
- return uri->getUri();
+ return uri->get_uri();
}
return Field::FIELD_NULL;
}
-const Field& NHttpMsgRequest::getUriNormLegacy() {
+const Field& NHttpMsgRequest::get_uri_norm_legacy() {
if (uri != nullptr) {
- return uri->getNormLegacy();
+ return uri->get_norm_legacy();
}
return Field::FIELD_NULL;
}
-void NHttpMsgRequest::genEvents() {
- if (methodId == METH__OTHER) createEvent(EVENT_UNKNOWN_METHOD);
+void NHttpMsgRequest::gen_events() {
+ if (method_id == METH__OTHER) create_event(EVENT_UNKNOWN_METHOD);
// URI character encoding events
- if (uri && (uri->getUriInfractions() & INF_URIPERCENTASCII)) createEvent(EVENT_ASCII);
- if (uri && (uri->getUriInfractions() & INF_URIPERCENTUCODE)) createEvent(EVENT_U_ENCODE);
- if (uri && (uri->getUriInfractions() & INF_URI8BITCHAR)) createEvent(EVENT_BARE_BYTE);
- if (uri && (uri->getUriInfractions() & INF_URIPERCENTUTF8)) createEvent(EVENT_UTF_8);
- if (uri && (uri->getUriInfractions() & INF_URIBADCHAR)) createEvent(EVENT_NON_RFC_CHAR);
+ if (uri && (uri->get_uri_infractions() & INF_URIPERCENTASCII)) create_event(EVENT_ASCII);
+ if (uri && (uri->get_uri_infractions() & INF_URIPERCENTUCODE)) create_event(EVENT_U_ENCODE);
+ if (uri && (uri->get_uri_infractions() & INF_URI8BITCHAR)) create_event(EVENT_BARE_BYTE);
+ if (uri && (uri->get_uri_infractions() & INF_URIPERCENTUTF8)) create_event(EVENT_UTF_8);
+ if (uri && (uri->get_uri_infractions() & INF_URIBADCHAR)) create_event(EVENT_NON_RFC_CHAR);
// URI path events
- if (uri && (uri->getPathInfractions() & INF_URIMULTISLASH)) createEvent(EVENT_MULTI_SLASH);
- if (uri && (uri->getPathInfractions() & INF_URIBACKSLASH)) createEvent(EVENT_IIS_BACKSLASH);
- if (uri && (uri->getPathInfractions() & INF_URISLASHDOT)) createEvent(EVENT_SELF_DIR_TRAV);
- if (uri && (uri->getPathInfractions() & INF_URISLASHDOTDOT)) createEvent(EVENT_DIR_TRAV);
- if (uri && (uri->getPathInfractions() & INF_URIROOTTRAV)) createEvent(EVENT_WEBROOT_DIR);
+ if (uri && (uri->get_path_infractions() & INF_URIMULTISLASH)) create_event(EVENT_MULTI_SLASH);
+ if (uri && (uri->get_path_infractions() & INF_URIBACKSLASH)) create_event(EVENT_IIS_BACKSLASH);
+ if (uri && (uri->get_path_infractions() & INF_URISLASHDOT)) create_event(EVENT_SELF_DIR_TRAV);
+ if (uri && (uri->get_path_infractions() & INF_URISLASHDOTDOT)) create_event(EVENT_DIR_TRAV);
+ if (uri && (uri->get_path_infractions() & INF_URIROOTTRAV)) create_event(EVENT_WEBROOT_DIR);
}
-void NHttpMsgRequest::printSection(FILE *output) {
- NHttpMsgSection::printMessageTitle(output, "request line");
- fprintf(output, "Version Id: %d\n", versionId);
- fprintf(output, "Method Id: %d\n", methodId);
- uri->getUri().print(output, "URI");
- if (uri->getUriType() != URI__NOSOURCE) fprintf(output, "URI Type: %d\n", uri->getUriType());
- uri->getScheme().print(output, "Scheme");
- if (uri->getSchemeId() != SCH__NOSOURCE) fprintf(output, "Scheme Id: %d\n", uri->getSchemeId());
- uri->getAuthority().print(output, "Authority");
- uri->getHost().print(output, "Host Name");
- uri->getNormHost().print(output, "Normalized Host Name");
- uri->getPort().print(output, "Port");
- if (uri->getPortValue() != STAT_NOSOURCE) fprintf(output, "Port Value: %d\n", uri->getPortValue());
- uri->getAbsPath().print(output, "Absolute Path");
- uri->getPath().print(output, "Path");
- uri->getNormPath().print(output, "Normalized Path");
- uri->getQuery().print(output, "Query");
- uri->getNormQuery().print(output, "Normalized Query");
- uri->getFragment().print(output, "Fragment");
- uri->getNormFragment().print(output, "Normalized Fragment");
+void NHttpMsgRequest::print_section(FILE *output) {
+ NHttpMsgSection::print_message_title(output, "request line");
+ fprintf(output, "Version Id: %d\n", version_id);
+ fprintf(output, "Method Id: %d\n", method_id);
+ uri->get_uri().print(output, "URI");
+ if (uri->get_uri_type() != URI__NOSOURCE) fprintf(output, "URI Type: %d\n", uri->get_uri_type());
+ uri->get_scheme().print(output, "Scheme");
+ if (uri->get_scheme_id() != SCH__NOSOURCE) fprintf(output, "Scheme Id: %d\n", uri->get_scheme_id());
+ uri->get_authority().print(output, "Authority");
+ uri->get_host().print(output, "Host Name");
+ uri->get_norm_host().print(output, "Normalized Host Name");
+ uri->get_port().print(output, "Port");
+ if (uri->get_port_value() != STAT_NOSOURCE) fprintf(output, "Port Value: %d\n", uri->get_port_value());
+ uri->get_abs_path().print(output, "Absolute Path");
+ uri->get_path().print(output, "Path");
+ uri->get_norm_path().print(output, "Normalized Path");
+ uri->get_query().print(output, "Query");
+ uri->get_norm_query().print(output, "Normalized Query");
+ uri->get_fragment().print(output, "Fragment");
+ uri->get_norm_fragment().print(output, "Normalized Fragment");
fprintf(output, "URI infractions: overall %" PRIx64 ", format %" PRIx64 ", scheme %" PRIx64 ", host %" PRIx64 ", port %" PRIx64 ", path %"
PRIx64 ", query %" PRIx64 ", fragment %" PRIx64 "\n",
- uri->getUriInfractions(), uri->getFormatInfractions(), uri->getSchemeInfractions(), uri->getHostInfractions(),
- uri->getPortInfractions(), uri->getPathInfractions(), uri->getQueryInfractions(), uri->getFragmentInfractions());
- NHttpMsgSection::printMessageWrapup(output);
+ uri->get_uri_infractions(), uri->get_format_infractions(), uri->get_scheme_infractions(), uri->get_host_infractions(),
+ uri->get_port_infractions(), uri->get_path_infractions(), uri->get_query_infractions(), uri->get_fragment_infractions());
+ NHttpMsgSection::print_message_wrapup(output);
}
-void NHttpMsgRequest::updateFlow() {
- const uint64_t disasterMask = INF_BADREQLINE;
+void NHttpMsgRequest::update_flow() {
+ const uint64_t disaster_mask = INF_BADREQLINE;
// The following logic to determine body type is by no means the last word on this topic.
- if (tcpClose) {
- sessionData->typeExpected[sourceId] = SEC_CLOSED;
- sessionData->halfReset(sourceId);
+ if (tcp_close) {
+ session_data->type_expected[source_id] = SEC_CLOSED;
+ session_data->half_reset(source_id);
}
- else if (infractions & disasterMask) {
- sessionData->typeExpected[sourceId] = SEC_ABORT;
- sessionData->halfReset(sourceId);
+ else if (infractions & disaster_mask) {
+ session_data->type_expected[source_id] = SEC_ABORT;
+ session_data->half_reset(source_id);
}
else {
- sessionData->typeExpected[sourceId] = SEC_HEADER;
- sessionData->versionId[sourceId] = versionId;
- sessionData->methodId[sourceId] = methodId;
+ session_data->type_expected[source_id] = SEC_HEADER;
+ session_data->version_id[source_id] = version_id;
+ session_data->method_id[source_id] = method_id;
}
}
// Legacy support function. Puts message fields into the buffers used by old Snort.
-void NHttpMsgRequest::legacyClients() {
+void NHttpMsgRequest::legacy_clients() {
ClearHttpBuffers();
if (method.length > 0) SetHttpBuffer(HTTP_BUFFER_METHOD, method.start, (unsigned)method.length);
- if (uri->getUri().length > 0) SetHttpBuffer(HTTP_BUFFER_RAW_URI, uri->getUri().start, (unsigned)uri->getUri().length);
- if (uri->getNormLegacy().length > 0) SetHttpBuffer(HTTP_BUFFER_URI, uri->getNormLegacy().start, (unsigned)uri->getNormLegacy().length);
+ if (uri->get_uri().length > 0) SetHttpBuffer(HTTP_BUFFER_RAW_URI, uri->get_uri().start, (unsigned)uri->get_uri().length);
+ if (uri->get_norm_legacy().length > 0) SetHttpBuffer(HTTP_BUFFER_URI, uri->get_norm_legacy().start, (unsigned)uri->get_norm_legacy().length);
}
class NHttpMsgRequest: public NHttpMsgStart {
public:
- NHttpMsgRequest(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_);
+ NHttpMsgRequest(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, NHttpEnums::SourceId source_id_);
~NHttpMsgRequest() { delete uri; };
- void printSection(FILE *output);
- void genEvents();
- void updateFlow();
- void legacyClients();
- const Field& getMethod() { return method; };
- const Field& getUri();
- const Field& getUriNormLegacy();
+ void print_section(FILE *output);
+ void gen_events();
+ void update_flow();
+ void legacy_clients();
+ const Field& get_method() { return method; };
+ const Field& get_uri();
+ const Field& get_uri_norm_legacy();
private:
- static const StrCode methodList[];
+ static const StrCode method_list[];
- void parseStartLine();
- void deriveMethodId();
+ void parse_start_line();
+ void derive_method_id();
Field method;
NHttpUri* uri = nullptr;
using namespace NHttpEnums;
-NHttpMsgSection::NHttpMsgSection(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, SourceId sourceId_) :
- sessionData(sessionData_), sourceId(sourceId_), tcpClose(sessionData->tcpClose[sourceId]), scratchPad(2*bufSize+500),
- infractions(sessionData->infractions[sourceId]), versionId(sessionData->versionId[sourceId]),
- methodId(sessionData->methodId[sourceId]), statusCodeNum(sessionData->statusCodeNum[sourceId])
+NHttpMsgSection::NHttpMsgSection(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, SourceId source_id_) :
+ session_data(session_data_), source_id(source_id_), tcp_close(session_data->tcp_close[source_id]), scratch_pad(2*buf_size+500),
+ infractions(session_data->infractions[source_id]), version_id(session_data->version_id[source_id]),
+ method_id(session_data->method_id[source_id]), status_code_num(session_data->status_code_num[source_id])
{
- msgText.start = buffer;
- msgText.length = bufSize;
+ msg_text.start = buffer;
+ msg_text.length = buf_size;
}
// Return the number of octets before the first CRLF. Return length if CRLF not present.
//
// wrappable: CRLF does not count in a header field when immediately followed by <SP> or <LF>. These whitespace characters
// at the beginning of the next line indicate that the previous header has wrapped and is continuing on the next line.
-uint32_t NHttpMsgSection::findCrlf(const uint8_t* buffer, int32_t length, bool wrappable) {
+uint32_t NHttpMsgSection::find_crlf(const uint8_t* buffer, int32_t length, bool wrappable) {
for (int32_t k=0; k < length-1; k++) {
if ((buffer[k] == '\r') && (buffer[k+1] == '\n'))
if (!wrappable || (k+2 >= length) || ((buffer[k+2] != ' ') && (buffer[k+2] != '\t'))) return k;
return length;
}
-void NHttpMsgSection::printMessageTitle(FILE *output, const char *title) const {
+void NHttpMsgSection::print_message_title(FILE *output, const char *title) const {
fprintf(output, "HTTP message %s:\n", title);
- msgText.print(output, "Input");
+ msg_text.print(output, "Input");
}
-void NHttpMsgSection::printMessageWrapup(FILE *output) const {
- fprintf(output, "Infractions: %" PRIx64 ", Events: %" PRIx64 ", TCP Close: %s\n", infractions, eventsGenerated,
- tcpClose ? "True" : "False");
+void NHttpMsgSection::print_message_wrapup(FILE *output) const {
+ fprintf(output, "Infractions: %" PRIx64 ", Events: %" PRIx64 ", TCP Close: %s\n", infractions, events_generated,
+ tcp_close ? "True" : "False");
fprintf(output, "Interface to old clients. http_mask = %x.\n", http_mask);
for (int i=0; i < HTTP_BUFFER_MAX; i++) {
if ((1 << i) & http_mask) Field(http_buffer[i].length, http_buffer[i].buf).print(output, http_buffer_name[i]);
fprintf(output, "\n");
}
-void NHttpMsgSection::createEvent(EventSid sid) {
+void NHttpMsgSection::create_event(EventSid sid) {
const uint32_t NHTTP_GID = 119;
SnortEventqAdd(NHTTP_GID, (uint32_t)sid);
- eventsGenerated |= (1 << (sid-1));
+ events_generated |= (1 << (sid-1));
}
class NHttpMsgSection {
public:
- virtual ~NHttpMsgSection() { delete[] msgText.start; };
+ virtual ~NHttpMsgSection() { delete[] msg_text.start; };
virtual void analyze() = 0; // Minimum necessary processing for every message
- virtual void printSection(FILE *output) = 0; // Test tool prints all derived message parts
- virtual void genEvents() = 0; // Converts collected information into required preprocessor events
- virtual void updateFlow() = 0; // Manages the splitter and communication between message sections
- virtual void legacyClients() = 0; // Populates the raw and normalized buffer interface used by old Snort
+ virtual void print_section(FILE *output) = 0; // Test tool prints all derived message parts
+ virtual void gen_events() = 0; // Converts collected information into required preprocessor events
+ virtual void update_flow() = 0; // Manages the splitter and communication between message sections
+ virtual void legacy_clients() = 0; // Populates the raw and normalized buffer interface used by old Snort
protected:
- NHttpMsgSection(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_);
+ NHttpMsgSection(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, NHttpEnums::SourceId source_id_);
// Convenience methods
- static uint32_t findCrlf(const uint8_t* buffer, int32_t length, bool wrappable);
- void printMessageTitle(FILE *output, const char *title) const;
- void printMessageWrapup(FILE *output) const;
- void createEvent(NHttpEnums::EventSid sid);
+ static uint32_t find_crlf(const uint8_t* buffer, int32_t length, bool wrappable);
+ void print_message_title(FILE *output, const char *title) const;
+ void print_message_wrapup(FILE *output) const;
+ void create_event(NHttpEnums::EventSid sid);
- Field msgText;
+ Field msg_text;
- NHttpFlowData* sessionData;
- NHttpEnums::SourceId sourceId;
- bool tcpClose;
- ScratchPad scratchPad;
+ NHttpFlowData* session_data;
+ NHttpEnums::SourceId source_id;
+ bool tcp_close;
+ ScratchPad scratch_pad;
// This is where all the derived values, extracted message parts, and normalized values are.
- // These are all scalars, buffer pointers, and buffer sizes. The actual buffers are in message buffer (raw pieces) or the
- // scratchPad (normalized pieces).
+ // These are all scalars, buffer pointers, and buffer sizes. The actual buffers are in message buffer (raw pieces)
+ // or the scratch_pad (normalized pieces).
uint64_t infractions;
- uint64_t eventsGenerated = 0;
- NHttpEnums::VersionId versionId;
- NHttpEnums::MethodId methodId;
- int32_t statusCodeNum;
+ uint64_t events_generated = 0;
+ NHttpEnums::VersionId version_id;
+ NHttpEnums::MethodId method_id;
+ int32_t status_code_num;
};
#endif
using namespace NHttpEnums;
void NHttpMsgStart::analyze() {
- startLine.start = msgText.start;
- startLine.length = findCrlf(startLine.start, msgText.length, false);
+ start_line.start = msg_text.start;
+ start_line.length = find_crlf(start_line.start, msg_text.length, false);
// special case of TCP close between CR and LF
- if (tcpClose && (msgText.length == startLine.length) && (startLine.start[startLine.length-1] == '\r')) startLine.length--;
- parseStartLine();
- deriveVersionId();
+ if (tcp_close && (msg_text.length == start_line.length) && (start_line.start[start_line.length-1] == '\r')) start_line.length--;
+ parse_start_line();
+ derive_version_id();
}
-void NHttpMsgStart::deriveVersionId() {
+void NHttpMsgStart::derive_version_id() {
if (version.length <= 0) {
- versionId = VERS__NOSOURCE;
+ version_id = VERS__NOSOURCE;
return;
}
if (version.length != 8) {
- versionId = VERS__PROBLEMATIC;
+ version_id = VERS__PROBLEMATIC;
infractions |= INF_BADVERSION;
return;
}
if (memcmp(version.start, "HTTP/", 5) || (version.start[6] != '.')) {
- versionId = VERS__PROBLEMATIC;
+ version_id = VERS__PROBLEMATIC;
infractions |= INF_BADVERSION;
}
else if ((version.start[5] == '1') && (version.start[7] == '1')) {
- versionId = VERS_1_1;
+ version_id = VERS_1_1;
}
else if ((version.start[5] == '1') && (version.start[7] == '0')) {
- versionId = VERS_1_0;
+ version_id = VERS_1_0;
}
else if ((version.start[5] == '2') && (version.start[7] == '0')) {
- versionId = VERS_2_0;
+ version_id = VERS_2_0;
}
else if ((version.start[5] >= '0') && (version.start[5] <= '9') && (version.start[7] >= '0') && (version.start[7] <= '9')) {
- versionId = VERS__OTHER;
+ version_id = VERS__OTHER;
infractions |= INF_UNKNOWNVERSION;
}
else {
- versionId = VERS__PROBLEMATIC;
+ version_id = VERS__PROBLEMATIC;
infractions |= INF_BADVERSION;
}
}
-void NHttpMsgStart::genEvents() {}
+void NHttpMsgStart::gen_events() {}
class NHttpMsgStart: public NHttpMsgSection {
public:
void analyze();
- void genEvents();
+ void gen_events();
protected:
- NHttpMsgStart(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_) :
- NHttpMsgSection(buffer, bufSize, sessionData_, sourceId_) {};
- virtual void parseStartLine() = 0;
- void deriveVersionId();
+ NHttpMsgStart(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, NHttpEnums::SourceId source_id_) :
+ NHttpMsgSection(buffer, buf_size, session_data_, source_id_) {};
+ virtual void parse_start_line() = 0;
+ void derive_version_id();
- Field startLine;
+ Field start_line;
Field version;
};
using namespace NHttpEnums;
-NHttpMsgStatus::NHttpMsgStatus(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, SourceId sourceId_) :
- NHttpMsgStart(buffer, bufSize, sessionData_, sourceId_), request(sessionData->requestLine) {
- delete sessionData->statusLine;
- sessionData->statusLine = this;
- delete sessionData->headers[SRC_SERVER];
- sessionData->headers[SRC_SERVER] = nullptr;
- delete sessionData->latestOther[SRC_SERVER];
- sessionData->latestOther[SRC_SERVER] = nullptr;
+NHttpMsgStatus::NHttpMsgStatus(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, SourceId source_id_) :
+ NHttpMsgStart(buffer, buf_size, session_data_, source_id_), request(session_data->request_line) {
+ delete session_data->status_line;
+ session_data->status_line = this;
+ delete session_data->headers[SRC_SERVER];
+ session_data->headers[SRC_SERVER] = nullptr;
+ delete session_data->latest_other[SRC_SERVER];
+ session_data->latest_other[SRC_SERVER] = nullptr;
}
// All the header processing that is done for every message (i.e. not just-in-time) is done here.
void NHttpMsgStatus::analyze() {
NHttpMsgStart::analyze();
- deriveStatusCodeNum();
+ derive_status_code_num();
}
-void NHttpMsgStatus::parseStartLine() {
+void NHttpMsgStatus::parse_start_line() {
// Eventually we may need to cater to certain format errors, but for now exact match or treat as error.
// HTTP/X.Y<SP>###<SP><text>
- if ((startLine.length < 13) || (startLine.start[8] != ' ') || (startLine.start[12] != ' ')) {
+ if ((start_line.length < 13) || (start_line.start[8] != ' ') || (start_line.start[12] != ' ')) {
infractions |= INF_BADSTATLINE;
return;
}
- version.start = startLine.start;
+ version.start = start_line.start;
version.length = 8;
- statusCode.start = startLine.start + 9;
- statusCode.length = 3;
- reasonPhrase.start = startLine.start + 13;
- reasonPhrase.length = startLine.length - 13;
- for (int32_t k = 0; k < reasonPhrase.length; k++) {
- if ((reasonPhrase.start[k] <= 31) || (reasonPhrase.start[k] >= 127)) {
+ status_code.start = start_line.start + 9;
+ status_code.length = 3;
+ reason_phrase.start = start_line.start + 13;
+ reason_phrase.length = start_line.length - 13;
+ for (int32_t k = 0; k < reason_phrase.length; k++) {
+ if ((reason_phrase.start[k] <= 31) || (reason_phrase.start[k] >= 127)) {
// Illegal character in reason phrase
infractions |= INF_BADPHRASE;
break;
}
}
- assert (startLine.length == version.length + statusCode.length + reasonPhrase.length + 2);
+ assert (start_line.length == version.length + status_code.length + reason_phrase.length + 2);
}
-void NHttpMsgStatus::deriveStatusCodeNum() {
- if (statusCode.length <= 0) {
- statusCodeNum = STAT_NOSOURCE;
+void NHttpMsgStatus::derive_status_code_num() {
+ if (status_code.length <= 0) {
+ status_code_num = STAT_NOSOURCE;
return;
}
- if (statusCode.length != 3) {
- statusCodeNum = STAT_PROBLEMATIC;
+ if (status_code.length != 3) {
+ status_code_num = STAT_PROBLEMATIC;
return;
}
- if ((statusCode.start[0] < '0') || (statusCode.start[0] > '9') || (statusCode.start[1] < '0') || (statusCode.start[1] > '9') ||
- (statusCode.start[2] < '0') || (statusCode.start[2] > '9')) {
+ if ((status_code.start[0] < '0') || (status_code.start[0] > '9') || (status_code.start[1] < '0') || (status_code.start[1] > '9') ||
+ (status_code.start[2] < '0') || (status_code.start[2] > '9')) {
infractions |= INF_BADSTATCODE;
- statusCodeNum = STAT_PROBLEMATIC;
+ status_code_num = STAT_PROBLEMATIC;
return;
}
- statusCodeNum = (statusCode.start[0] - '0') * 100 + (statusCode.start[1] - '0') * 10 + (statusCode.start[2] - '0');
- if ((statusCodeNum < 100) || (statusCodeNum > 599)) {
+ status_code_num = (status_code.start[0] - '0') * 100 + (status_code.start[1] - '0') * 10 + (status_code.start[2] - '0');
+ if ((status_code_num < 100) || (status_code_num > 599)) {
infractions |= INF_BADSTATCODE;
}
}
-void NHttpMsgStatus::genEvents() {}
+void NHttpMsgStatus::gen_events() {}
-void NHttpMsgStatus::printSection(FILE *output) {
- NHttpMsgSection::printMessageTitle(output, "status line");
- fprintf(output, "Version Id: %d\n", versionId);
- fprintf(output, "Status Code Num: %d\n", statusCodeNum);
- reasonPhrase.print(output, "Reason Phrase");
- NHttpMsgSection::printMessageWrapup(output);
+void NHttpMsgStatus::print_section(FILE *output) {
+ NHttpMsgSection::print_message_title(output, "status line");
+ fprintf(output, "Version Id: %d\n", version_id);
+ fprintf(output, "Status Code Num: %d\n", status_code_num);
+ reason_phrase.print(output, "Reason Phrase");
+ NHttpMsgSection::print_message_wrapup(output);
}
-void NHttpMsgStatus::updateFlow() {
- const uint64_t disasterMask = INF_BADSTATLINE;
+void NHttpMsgStatus::update_flow() {
+ const uint64_t disaster_mask = INF_BADSTATLINE;
// The following logic to determine body type is by no means the last word on this topic.
- if (tcpClose) {
- sessionData->typeExpected[sourceId] = SEC_CLOSED;
- sessionData->halfReset(sourceId);
+ if (tcp_close) {
+ session_data->type_expected[source_id] = SEC_CLOSED;
+ session_data->half_reset(source_id);
}
- else if (infractions & disasterMask) {
- sessionData->typeExpected[sourceId] = SEC_ABORT;
- sessionData->halfReset(sourceId);
+ else if (infractions & disaster_mask) {
+ session_data->type_expected[source_id] = SEC_ABORT;
+ session_data->half_reset(source_id);
}
else {
- sessionData->typeExpected[sourceId] = SEC_HEADER;
- sessionData->versionId[sourceId] = versionId;
- sessionData->statusCodeNum[sourceId] = statusCodeNum;
+ session_data->type_expected[source_id] = SEC_HEADER;
+ session_data->version_id[source_id] = version_id;
+ session_data->status_code_num[source_id] = status_code_num;
}
}
// Legacy support function. Puts message fields into the buffers used by old Snort.
-void NHttpMsgStatus::legacyClients() {
+void NHttpMsgStatus::legacy_clients() {
ClearHttpBuffers();
- if ((request != nullptr) && (request->getMethod().length > 0)) {
- SetHttpBuffer(HTTP_BUFFER_METHOD, request->getMethod().start, (unsigned)request->getMethod().length);
+ if ((request != nullptr) && (request->get_method().length > 0)) {
+ SetHttpBuffer(HTTP_BUFFER_METHOD, request->get_method().start, (unsigned)request->get_method().length);
}
- if ((request != nullptr) && (request->getUri().length > 0)) {
- SetHttpBuffer(HTTP_BUFFER_RAW_URI, request->getUri().start, (unsigned)request->getUri().length);
+ if ((request != nullptr) && (request->get_uri().length > 0)) {
+ SetHttpBuffer(HTTP_BUFFER_RAW_URI, request->get_uri().start, (unsigned)request->get_uri().length);
}
- if ((request != nullptr) && (request->getUriNormLegacy().length > 0)) {
- SetHttpBuffer(HTTP_BUFFER_URI, request->getUriNormLegacy().start, (unsigned)request->getUriNormLegacy().length);
+ if ((request != nullptr) && (request->get_uri_norm_legacy().length > 0)) {
+ SetHttpBuffer(HTTP_BUFFER_URI, request->get_uri_norm_legacy().start, (unsigned)request->get_uri_norm_legacy().length);
}
- if (statusCode.length > 0) {
- SetHttpBuffer(HTTP_BUFFER_STAT_CODE, statusCode.start, (unsigned)statusCode.length);
+ if (status_code.length > 0) {
+ SetHttpBuffer(HTTP_BUFFER_STAT_CODE, status_code.start, (unsigned)status_code.length);
}
- if (reasonPhrase.length > 0) {
- SetHttpBuffer(HTTP_BUFFER_STAT_MSG, reasonPhrase.start, (unsigned)reasonPhrase.length);
+ if (reason_phrase.length > 0) {
+ SetHttpBuffer(HTTP_BUFFER_STAT_MSG, reason_phrase.start, (unsigned)reason_phrase.length);
}
}
class NHttpMsgStatus: public NHttpMsgStart {
public:
- NHttpMsgStatus(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_);
+ NHttpMsgStatus(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, NHttpEnums::SourceId source_id_);
void analyze();
- void printSection(FILE *output);
- void genEvents();
- void updateFlow();
- void legacyClients();
+ void print_section(FILE *output);
+ void gen_events();
+ void update_flow();
+ void legacy_clients();
private:
- void parseStartLine();
- void deriveStatusCodeNum();
+ void parse_start_line();
+ void derive_status_code_num();
- Field statusCode;
- Field reasonPhrase;
+ Field status_code;
+ Field reason_phrase;
NHttpMsgRequest* request;
};
using namespace NHttpEnums;
-NHttpMsgTrailer::NHttpMsgTrailer(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, SourceId sourceId_) :
- NHttpMsgHeadShared(buffer, bufSize, sessionData_, sourceId_) {
- delete sessionData->latestOther[sourceId];
- sessionData->latestOther[sourceId] = this;
+NHttpMsgTrailer::NHttpMsgTrailer(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, SourceId source_id_) :
+ NHttpMsgHeadShared(buffer, buf_size, session_data_, source_id_) {
+ delete session_data->latest_other[source_id];
+ session_data->latest_other[source_id] = this;
}
-void NHttpMsgTrailer::genEvents() {
- NHttpMsgHeadShared::genEvents();
+void NHttpMsgTrailer::gen_events() {
+ NHttpMsgHeadShared::gen_events();
}
-void NHttpMsgTrailer::printSection(FILE *output) {
- NHttpMsgSection::printMessageTitle(output, "trailer");
- NHttpMsgHeadShared::printHeaders(output);
- NHttpMsgSection::printMessageWrapup(output);
+void NHttpMsgTrailer::print_section(FILE *output) {
+ NHttpMsgSection::print_message_title(output, "trailer");
+ NHttpMsgHeadShared::print_headers(output);
+ NHttpMsgSection::print_message_wrapup(output);
}
-void NHttpMsgTrailer::updateFlow() {
- if (tcpClose) {
- sessionData->typeExpected[sourceId] = SEC_CLOSED;
- sessionData->halfReset(sourceId);
+void NHttpMsgTrailer::update_flow() {
+ if (tcp_close) {
+ session_data->type_expected[source_id] = SEC_CLOSED;
+ session_data->half_reset(source_id);
}
else {
- sessionData->typeExpected[sourceId] = (sourceId == SRC_CLIENT) ? SEC_REQUEST : SEC_STATUS;
- sessionData->halfReset(sourceId);
+ session_data->type_expected[source_id] = (source_id == SRC_CLIENT) ? SEC_REQUEST : SEC_STATUS;
+ session_data->half_reset(source_id);
}
}
class NHttpMsgTrailer: public NHttpMsgHeadShared {
public:
- NHttpMsgTrailer(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_);
- void printSection(FILE *output);
- void genEvents();
- void updateFlow();
+ NHttpMsgTrailer(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, NHttpEnums::SourceId source_id_);
+ void print_section(FILE *output);
+ void gen_events();
+ void update_flow();
};
#endif
// Collection of stock normalization functions. This will probably grow throughout the life of the software. New functions must follow the standard signature.
// The void* at the end is for any special configuration data the function requires.
-int32_t normDecimalInteger(const uint8_t* inBuf, int32_t inLength, uint8_t* outBuf, uint64_t& infractions, const void *) {
+int32_t norm_decimal_integer(const uint8_t* in_buf, int32_t in_length, uint8_t* out_buf, uint64_t& infractions, const void *) {
// Limited to 18 decimal digits, not including leading zeros, to fit comfortably into int64_t
int64_t total = 0;
- int nonLeadingZeros = 0;
- for (int32_t k=0; k < inLength; k++) {
- int value = inBuf[k] - '0';
- if (nonLeadingZeros || (value != 0)) nonLeadingZeros++;
- if (nonLeadingZeros > 18) {
+ int non_leading_zeros = 0;
+ for (int32_t k=0; k < in_length; k++) {
+ int value = in_buf[k] - '0';
+ if (non_leading_zeros || (value != 0)) non_leading_zeros++;
+ if (non_leading_zeros > 18) {
infractions |= INF_BADHEADERDATA;
return STAT_PROBLEMATIC;
}
}
total = total*10 + value;
}
- ((int64_t*)outBuf)[0] = total;
+ ((int64_t*)out_buf)[0] = total;
return sizeof(int64_t);
}
-int32_t norm2Lower(const uint8_t* inBuf, int32_t inLength, uint8_t *outBuf, uint64_t&, const void *) {
- for (int32_t k=0; k < inLength; k++) {
- outBuf[k] = ((inBuf[k] < 'A') || (inBuf[k] > 'Z')) ? inBuf[k] : inBuf[k] - ('A' - 'a');
+int32_t norm_to_lower(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t&, const void *) {
+ for (int32_t k=0; k < in_length; k++) {
+ out_buf[k] = ((in_buf[k] < 'A') || (in_buf[k] > 'Z')) ? in_buf[k] : in_buf[k] - ('A' - 'a');
}
- return inLength;
+ return in_length;
}
-int32_t normStrCode(const uint8_t* inBuf, int32_t inLength, uint8_t *outBuf, uint64_t&, const void *table) {
- ((int64_t*)outBuf)[0] = strToCode(inBuf, inLength, (const StrCode*)table);
+int32_t norm_str_code(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t&, const void *table) {
+ ((int64_t*)out_buf)[0] = str_to_code(in_buf, in_length, (const StrCode*)table);
return sizeof(int64_t);
}
-int32_t normSeqStrCode(const uint8_t* inBuf, int32_t inLength, uint8_t *outBuf, uint64_t&, const void *table) {
- int32_t numCodes = 0;
- const uint8_t* start = inBuf;
+int32_t norm_seq_str_code(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t&, const void *table) {
+ int32_t num_codes = 0;
+ const uint8_t* start = in_buf;
while (true) {
int32_t length;
- for (length = 0; (start + length < inBuf + inLength) && (start[length] != ','); length++);
- if (length == 0) ((uint32_t*)outBuf)[numCodes++] = STAT_EMPTYSTRING;
- else ((int64_t*)outBuf)[numCodes++] = strToCode(start, length, (const StrCode*)table);
- if (start + length >= inBuf + inLength) break;
+ for (length = 0; (start + length < in_buf + in_length) && (start[length] != ','); length++);
+ if (length == 0) ((uint32_t*)out_buf)[num_codes++] = STAT_EMPTYSTRING;
+ else ((int64_t*)out_buf)[num_codes++] = str_to_code(start, length, (const StrCode*)table);
+ if (start + length >= in_buf + in_length) break;
start += length + 1;
}
- return numCodes * sizeof(int64_t);
+ return num_codes * sizeof(int64_t);
}
// Remove all space and tab characters (known as LWS or linear white space in the RFC)
-int32_t normRemoveLws(const uint8_t* inBuf, int32_t inLength, uint8_t *outBuf, uint64_t&, const void *) {
+int32_t norm_remove_lws(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t&, const void *) {
int32_t length = 0;
- for (int32_t k = 0; k < inLength; k++) {
- if ((inBuf[k] != ' ') && (inBuf[k] != '\t')) outBuf[length++] = inBuf[k];
+ for (int32_t k = 0; k < in_length; k++) {
+ if ((in_buf[k] != ' ') && (in_buf[k] != '\t')) out_buf[length++] = in_buf[k];
}
return length;
}
#ifndef NHTTP_NORMALIZERS_H
#define NHTTP_NORMALIZERS_H
-int32_t normDecimalInteger(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* notUsed);
-int32_t norm2Lower(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* notUsed);
-int32_t normStrCode(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*);
-int32_t normSeqStrCode(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*);
-int32_t normRemoveLws(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* notUsed);
+int32_t norm_decimal_integer(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* not_used);
+int32_t norm_to_lower(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* not_used);
+int32_t norm_str_code(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*);
+int32_t norm_seq_str_code(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*);
+int32_t norm_remove_lws(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* not_used);
#endif
#include "nhttp_str_to_code.h"
// Need to replace this simple algorithm for better performance
-int32_t strToCode(const uint8_t *text, int32_t textLen, const StrCode table[]) {
+int32_t str_to_code(const uint8_t *text, int32_t text_len, const StrCode table[]) {
for (int32_t k=0; table[k].name != nullptr; k++) {
- if ((textLen == (int) strlen(table[k].name)) && (memcmp(text, table[k].name, textLen) == 0)) {
+ if ((text_len == (int) strlen(table[k].name)) && (memcmp(text, table[k].name, text_len) == 0)) {
return table[k].code;
}
}
const char *name;
};
-int32_t strToCode(const uint8_t *text, int32_t textLen, const StrCode table[]);
+int32_t str_to_code(const uint8_t *text, int32_t text_len, const StrCode table[]);
#endif
using namespace NHttpEnums;
// Convenience function. All the housekeeping that must be done before we can return PAF_FLUSH to stream.
-void NHttpStreamSplitter::prepareFlush(NHttpFlowData* sessionData, uint32_t* flushOffset, SourceId sourceId, SectionType sectionType, bool tcpClose,
- uint64_t infractions, uint32_t numOctets) {
- sessionData->sectionType[sourceId] = sectionType;
- sessionData->tcpClose[sourceId] = tcpClose;
- sessionData->infractions[sourceId] = infractions;
- if (tcpClose) sessionData->typeExpected[sourceId] = SEC_CLOSED;
- if (!NHttpTestInput::test_input) *flushOffset = numOctets;
- else NHttpTestInput::testInput->flush(numOctets);
- sessionData->octetsSeen[sourceId] = 0;
- sessionData->numCrlf[sourceId] = 0;
+void NHttpStreamSplitter::prepare_flush(NHttpFlowData* session_data, uint32_t* flush_offset, SourceId source_id,
+ SectionType section_type, bool tcp_close, uint64_t infractions, uint32_t num_octets) {
+ session_data->section_type[source_id] = section_type;
+ session_data->tcp_close[source_id] = tcp_close;
+ session_data->infractions[source_id] = infractions;
+ if (tcp_close) {
+ session_data->type_expected[source_id] = SEC_CLOSED;
+ }
+ if (!NHttpTestInput::test_input) {
+ *flush_offset = num_octets;
+ }
+ else {
+ NHttpTestInput::test_input_source->flush(num_octets);
+ }
+ session_data->octets_seen[source_id] = 0;
+ session_data->num_crlf[source_id] = 0;
}
const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned offset, const uint8_t* data, unsigned len,
{
static THREAD_LOCAL StreamBuffer nhttp_buf;
if (flags & PKT_PDU_HEAD) {
- sectionBuffer = new uint8_t[65536];
+ section_buffer = new uint8_t[65536];
}
- SourceId sourceId = (flags & PKT_FROM_CLIENT) ? SRC_CLIENT : SRC_SERVER;
+ SourceId source_id = (flags & PKT_FROM_CLIENT) ? SRC_CLIENT : SRC_SERVER;
copied = len;
return nullptr;
}
uint8_t* buffer;
- NHttpTestInput::testInput->reassemble(&buffer, len, sourceId);
+ NHttpTestInput::test_input_source->reassemble(&buffer, len, source_id);
if (len == 0) {
// There is no more test data
- delete[] sectionBuffer;
- sectionBuffer = nullptr;
+ delete[] section_buffer;
+ section_buffer = nullptr;
return nullptr;
}
data = buffer;
offset = 0;
}
- memcpy(sectionBuffer+offset, data, len);
+ memcpy(section_buffer+offset, data, len);
if (flags & PKT_PDU_TAIL) {
- myInspector->process(sectionBuffer, offset + len, flow, sourceId);
- nhttp_buf.data = sectionBuffer;
+ my_inspector->process(section_buffer, offset + len, flow, source_id);
+ nhttp_buf.data = section_buffer;
nhttp_buf.length = offset + len;
- sectionBuffer = nullptr; // the buffer is the responsibility of the inspector now
+ section_buffer = nullptr; // the buffer is the responsibility of the inspector now
return &nhttp_buf;
}
return nullptr;
}
-PAF_Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* data, uint32_t length, uint32_t flags, uint32_t* flushOffset) {
+PAF_Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* data, uint32_t length, uint32_t flags, uint32_t* flush_offset) {
// When the system begins providing TCP connection close information this won't always be false. &&&
- bool tcpClose = false;
+ bool tcp_close = false;
// This is the session state information we share with HTTP Inspect and store with stream. A session is defined by a TCP connection.
// Since PAF is the first to see a new TCP connection the new flow data object is created here.
- NHttpFlowData* sessionData = (NHttpFlowData*)flow->get_application_data(NHttpFlowData::nhttp_flow_id);
- if (sessionData == nullptr) flow->set_application_data(sessionData = new NHttpFlowData);
- assert(sessionData != nullptr);
+ NHttpFlowData* session_data = (NHttpFlowData*)flow->get_application_data(NHttpFlowData::nhttp_flow_id);
+ if (session_data == nullptr) flow->set_application_data(session_data = new NHttpFlowData);
+ assert(session_data != nullptr);
- SourceId sourceId = (flags & PKT_FROM_CLIENT) ? SRC_CLIENT : SRC_SERVER;
+ SourceId source_id = (flags & PKT_FROM_CLIENT) ? SRC_CLIENT : SRC_SERVER;
if (NHttpTestInput::test_input) {
- *flushOffset = length;
- bool needBreak;
- NHttpTestInput::testInput->scan((uint8_t*&)data, length, sourceId, tcpClose, needBreak);
+ *flush_offset = length;
+ bool need_break;
+ NHttpTestInput::test_input_source->scan((uint8_t*&)data, length, source_id, tcp_close, need_break);
if (length == 0) return PAF_FLUSH;
- if (needBreak) flow->set_application_data(sessionData = new NHttpFlowData);
+ if (need_break) flow->set_application_data(session_data = new NHttpFlowData);
}
- switch (SectionType type = sessionData->typeExpected[sourceId]) {
+ switch (SectionType type = session_data->type_expected[source_id]) {
case SEC_REQUEST:
case SEC_STATUS:
case SEC_HEADER:
case SEC_CHUNKHEAD:
case SEC_TRAILER:
- pafMax = 63780;
+ paf_max = 63780;
for (uint32_t k = 0; k < length; k++) {
- sessionData->octetsSeen[sourceId]++;
+ session_data->octets_seen[source_id]++;
// Count the alternating <CR> and <LF> characters we have seen in a row
- if (((data[k] == '\r') && (sessionData->numCrlf[sourceId]%2 == 0)) || ((data[k] == '\n') && (sessionData->numCrlf[sourceId]%2 == 1))) sessionData->numCrlf[sourceId]++;
- else sessionData->numCrlf[sourceId] = 0;
+ if (((data[k] == '\r') && (session_data->num_crlf[source_id]%2 == 0)) ||
+ ((data[k] == '\n') && (session_data->num_crlf[source_id]%2 == 1))) {
+ session_data->num_crlf[source_id]++;
+ }
+ else {
+ session_data->num_crlf[source_id] = 0;
+ }
- // Check start line for leading CRLF because some 1.0 implementations put extra blank lines between messages. We tolerate this by quietly ignoring them.
- // Header/trailer may also have leading CRLF. That is completely normal and means there are no header/trailer lines.
- if ((sessionData->numCrlf[sourceId] == 2) && (sessionData->octetsSeen[sourceId] == 2) && (type != SEC_CHUNKHEAD)) {
- prepareFlush(sessionData, flushOffset, sourceId, ((type == SEC_REQUEST) || (type == SEC_STATUS)) ? SEC_DISCARD : type, tcpClose && (k == length-1), 0, k+1);
+ // Check start line for leading CRLF because some 1.0 implementations put extra blank lines between messages.
+ // We tolerate this by quietly ignoring them. Header/trailer may also have leading CRLF. That is completely
+ // normal and means there are no header/trailer lines.
+ if ((session_data->num_crlf[source_id] == 2) && (session_data->octets_seen[source_id] == 2) && (type != SEC_CHUNKHEAD)) {
+ prepare_flush(session_data, flush_offset, source_id,
+ ((type == SEC_REQUEST) || (type == SEC_STATUS)) ? SEC_DISCARD : type,
+ tcp_close && (k == length-1), 0, k+1);
return PAF_FLUSH;
}
// The start line and chunk header section always end with the first <CRLF>
- else if ((sessionData->numCrlf[sourceId] == 2) && ((type == SEC_REQUEST) || (type == SEC_STATUS) || (type == SEC_CHUNKHEAD))) {
- prepareFlush(sessionData, flushOffset, sourceId, type, tcpClose && (k == length-1), 0, k+1);
+ else if ((session_data->num_crlf[source_id] == 2) &&
+ ((type == SEC_REQUEST) || (type == SEC_STATUS) || (type == SEC_CHUNKHEAD))) {
+ prepare_flush(session_data, flush_offset, source_id, type, tcp_close && (k == length-1), 0, k+1);
return PAF_FLUSH;
}
// The header and trailer sections always end with the first double <CRLF>
- else if (sessionData->numCrlf[sourceId] == 4) {
- prepareFlush(sessionData, flushOffset, sourceId, type, tcpClose && (k == length-1), 0, k+1);
+ else if (session_data->num_crlf[source_id] == 4) {
+ prepare_flush(session_data, flush_offset, source_id, type, tcp_close && (k == length-1), 0, k+1);
return PAF_FLUSH;
}
// We must do this to protect ourself from buffer overrun.
- else if (sessionData->octetsSeen[sourceId] >= 63780) {
- prepareFlush(sessionData, flushOffset, sourceId, type, tcpClose && (k == length-1), INF_HEADTOOLONG, k+1);
+ else if (session_data->octets_seen[source_id] >= 63780) {
+ prepare_flush(session_data, flush_offset, source_id, type, tcp_close && (k == length-1), INF_HEADTOOLONG, k+1);
return PAF_FLUSH;
}
}
// Incomplete headers wait patiently for more data
- if (!tcpClose) return PAF_SEARCH;
+ if (!tcp_close) {
+ return PAF_SEARCH;
+ }
// Discard the oddball case where the new "message" starts with <CR><close>
- else if ((sessionData->octetsSeen[sourceId] == 1) && (sessionData->numCrlf[sourceId] == 1)) prepareFlush(sessionData, flushOffset, sourceId, SEC_DISCARD, true, 0, length);
+ else if ((session_data->octets_seen[source_id] == 1) && (session_data->num_crlf[source_id] == 1)) {
+ prepare_flush(session_data, flush_offset, source_id, SEC_DISCARD, true, 0, length);
+ }
// TCP connection close, flush the partial header
- else prepareFlush(sessionData, flushOffset, sourceId, type, true, INF_TRUNCATED, length);
+ else {
+ prepare_flush(session_data, flush_offset, source_id, type, true, INF_TRUNCATED, length);
+ }
return PAF_FLUSH;
case SEC_BODY:
case SEC_CHUNKBODY:
- pafMax = 16384;
- prepareFlush(sessionData, flushOffset, sourceId, type, tcpClose && (sessionData->octetsExpected[sourceId] >= length), 0, sessionData->octetsExpected[sourceId]);
+ paf_max = 16384;
+ prepare_flush(session_data, flush_offset, source_id, type,
+ tcp_close && (session_data->octets_expected[source_id] >= length),
+ 0, session_data->octets_expected[source_id]);
return PAF_FLUSH;
case SEC_ABORT:
return PAF_ABORT;
class NHttpStreamSplitter : public StreamSplitter {
public:
- NHttpStreamSplitter(bool isClientToServer, NHttpInspect* myInspector_) : StreamSplitter(isClientToServer),
- myInspector(myInspector_) {};
- ~NHttpStreamSplitter() { delete[] sectionBuffer; };
- PAF_Status scan(Flow* flow, const uint8_t* data, uint32_t length, uint32_t flags, uint32_t* flushOffset);
+ NHttpStreamSplitter(bool is_client_to_server, NHttpInspect* my_inspector_) : StreamSplitter(is_client_to_server),
+ my_inspector(my_inspector_) {};
+ ~NHttpStreamSplitter() { delete[] section_buffer; };
+ PAF_Status scan(Flow* flow, const uint8_t* data, uint32_t length, uint32_t flags, uint32_t* flush_offset);
const StreamBuffer* reassemble(Flow* flow, unsigned offset, const uint8_t* data, unsigned len, uint32_t flags,
unsigned& copied);
bool is_paf() { return true; };
- uint32_t max() { return pafMax; };
+ uint32_t max() { return paf_max; };
private:
- void prepareFlush(NHttpFlowData* sessionData, uint32_t* flushOffset, NHttpEnums::SourceId sourceId, NHttpEnums::SectionType sectionType, bool tcpClose,
- uint64_t infractions, uint32_t numOctets);
- void createEvent(NHttpEnums::EventSid sid);
+ void prepare_flush(NHttpFlowData* session_data, uint32_t* flush_offset, NHttpEnums::SourceId source_id, NHttpEnums::SectionType section_type, bool tcp_close,
+ uint64_t infractions, uint32_t num_octets);
+ void create_event(NHttpEnums::EventSid sid);
- NHttpInspect* const myInspector;
+ NHttpInspect* const my_inspector;
- uint8_t *sectionBuffer = nullptr;
- uint32_t pafMax = 63780;
+ uint8_t *section_buffer = nullptr;
+ uint32_t paf_max = 63780;
};
#endif
using namespace NHttpEnums;
-const StrCode NHttpMsgRequest::methodList[] =
+const StrCode NHttpMsgRequest::method_list[] =
{{ METH_OPTIONS, "OPTIONS"},
{ METH_GET, "GET"},
{ METH_HEAD, "HEAD"},
{ METH_UPDATEREDIRECTREF, "UPDATEREDIRECTREF"},
{ 0, nullptr} };
-const StrCode NHttpUri::schemeList[] =
+const StrCode NHttpUri::scheme_list[] =
{{ SCH_HTTP, "http"},
{ SCH_HTTPS, "https"},
{ SCH_FTP, "ftp"},
{ SCH_FILE, "file"},
{ 0, nullptr} };
-const StrCode NHttpMsgHeadShared::headerList[] =
+const StrCode NHttpMsgHeadShared::header_list[] =
{{ HEAD_CACHE_CONTROL, "cache-control"},
{ HEAD_CONNECTION, "connection"},
{ HEAD_DATE, "date"},
{ HEAD_TRUE_CLIENT_IP, "true-client-ip"},
{ 0, nullptr} };
-const StrCode NHttpMsgHeadShared::transCodeList[] =
+const StrCode NHttpMsgHeadShared::trans_code_list[] =
{{ TRANSCODE_CHUNKED, "chunked"},
{ TRANSCODE_IDENTITY, "identity"},
{ TRANSCODE_GZIP, "gzip"},
{ TRANSCODE_DEFLATE, "deflate"},
{ 0, nullptr} };
-const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_NIL {NORM_NULL, false, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
-const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_BASIC {NORM_FIELD, false, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
-const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_CAT {NORM_FIELD, true, normRemoveLws, nullptr, nullptr, nullptr, nullptr, nullptr};
-const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_DECIMAL {NORM_INT64, false, normDecimalInteger, nullptr, nullptr, nullptr, nullptr, nullptr};
-const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_TRANSCODE {NORM_ENUM64, true, normRemoveLws, nullptr, norm2Lower, nullptr, normSeqStrCode, NHttpMsgHeadShared::transCodeList};
-
-const HeaderNormalizer* const NHttpMsgHeadShared::headerNorms[HEAD__MAXVALUE] = { [0] = &NORMALIZER_NIL,
+const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_NIL {NORM_NULL, false, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr};
+const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_BASIC {NORM_FIELD, false, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr};
+const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_CAT {NORM_FIELD, true, norm_remove_lws, nullptr, nullptr,
+ nullptr, nullptr, nullptr};
+const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_DECIMAL {NORM_INT64, false, norm_decimal_integer, nullptr,
+ nullptr, nullptr, nullptr, nullptr};
+const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_TRANSCODE {NORM_ENUM64, true, norm_remove_lws, nullptr,
+ norm_to_lower, nullptr, norm_seq_str_code, NHttpMsgHeadShared::trans_code_list};
+
+const HeaderNormalizer* const NHttpMsgHeadShared::header_norms[HEAD__MAXVALUE] = { [0] = &NORMALIZER_NIL,
[HEAD__OTHER] = &NORMALIZER_BASIC,
[HEAD_CACHE_CONTROL] = &NORMALIZER_BASIC,
[HEAD_CONNECTION] = &NORMALIZER_BASIC,
[HEAD_TRUE_CLIENT_IP] = &NORMALIZER_BASIC
};
-const int32_t NHttpMsgHeadShared::numNorms = HEAD__MAXVALUE-1;
+const int32_t NHttpMsgHeadShared::num_norms = HEAD__MAXVALUE-1;
-const RuleMap NHttpModule::nhttpEvents[] =
+const RuleMap NHttpModule::nhttp_events[] =
{
{ EVENT_ASCII, "(nhttp_inspect) ascii encoding" },
{ EVENT_DOUBLE_DECODE, "(nhttp_inspect) double decoding attack" },
using namespace NHttpEnums;
bool NHttpTestInput::test_input = false;
-NHttpTestInput *NHttpTestInput::testInput = nullptr;
+NHttpTestInput *NHttpTestInput::test_input_source = nullptr;
-NHttpTestInput::NHttpTestInput(const char *fileName) {
- if ((testDataFile = fopen(fileName, "r")) == nullptr) throw std::runtime_error("Cannot open test input file");
+NHttpTestInput::NHttpTestInput(const char *file_name) {
+ if ((test_data_file = fopen(file_name, "r")) == nullptr) throw std::runtime_error("Cannot open test input file");
}
NHttpTestInput::~NHttpTestInput() {
- fclose(testDataFile);
+ fclose(test_data_file);
}
// Read from the test data file and present to PAF.
// In the process we may need to skip comments, execute simple commands, and handle escape sequences.
// The best way to understand this function is to read the comments at the top of the file of test cases.
-void NHttpTestInput::scan(uint8_t*& data, uint32_t &length, SourceId &sourceId, bool &tcpClose, bool &needBreak) {
- sourceId = lastSourceId;
- tcpClose = false;
- needBreak = false;
+void NHttpTestInput::scan(uint8_t*& data, uint32_t &length, SourceId &source_id, bool &tcp_close, bool &need_break) {
+ source_id = last_source_id;
+ tcp_close = false;
+ need_break = false;
// Need to create and inspect additional message section(s) from the previous flush before we read new stuff
- if ((endOffset == 0) && (flushOctets > 0)) {
+ if ((end_offset == 0) && (flush_octets > 0)) {
length = 0;
return;
}
- if (justFlushed) {
+ if (just_flushed) {
// PAF just flushed and it has all been sent to inspection. There may or may not be leftover data from the
// last segment that was not flushed.
- justFlushed = false;
- data = msgBuf;
- length = endOffset - flushOctets; // this is the leftover data
- previousOffset = 0;
- endOffset = length;
+ just_flushed = false;
+ data = msg_buf;
+ length = end_offset - flush_octets; // this is the leftover data
+ previous_offset = 0;
+ end_offset = length;
if (length > 0) {
// Must present unflushed leftovers to PAF again.
// If we don't take this opportunity to left justify our data in the buffer we may "walk" to the right until we run out of buffer space
- memmove(msgBuf, msgBuf+flushOctets, length);
- tcpClose = tcpAlreadyClosed;
+ memmove(msg_buf, msg_buf+flush_octets, length);
+ tcp_close = tcp_already_closed;
return;
}
// If we reach here then PAF has already flushed all the data we have read so far.
- tcpAlreadyClosed = false;
+ tcp_already_closed = false;
}
else {
// The data we gave PAF last time was not flushed
length = 0;
- previousOffset = endOffset;
- data = msgBuf + previousOffset;
+ previous_offset = end_offset;
+ data = msg_buf + previous_offset;
}
// Now we need to move forward by reading more data from the file
- int newChar;
+ int new_char;
typedef enum { WAITING, COMMENT, COMMAND, SECTION, ESCAPE, HEXVAL } State;
State state = WAITING;
bool ending;
- int commandLength;
- const int MaxCommand = 100;
- char commandValue[MaxCommand];
- uint8_t hexVal;
- int numDigits;
+ int command_length;
+ const int max_command = 100;
+ char command_value[max_command];
+ uint8_t hex_val;
+ int num_digits;
- while ((newChar = getc(testDataFile)) != EOF) {
+ while ((new_char = getc(test_data_file)) != EOF) {
switch (state) {
case WAITING:
- if (newChar == '#') state = COMMENT;
- else if (newChar == '@') {
+ if (new_char == '#') {
+ state = COMMENT;
+ }
+ else if (new_char == '@') {
state = COMMAND;
- commandLength = 0;
+ command_length = 0;
}
- else if (newChar == '\\') {
+ else if (new_char == '\\') {
state = ESCAPE;
ending = false;
}
- else if (newChar != '\n') {
+ else if (new_char != '\n') {
state = SECTION;
ending = false;
- data[length++] = (uint8_t) newChar;
+ data[length++] = (uint8_t) new_char;
}
break;
case COMMENT:
- if (newChar == '\n') state = WAITING;
+ if (new_char == '\n') {
+ state = WAITING;
+ }
break;
case COMMAND:
- if (newChar == '\n') {
+ if (new_char == '\n') {
state = WAITING;
- if ((commandLength == strlen("request")) && !memcmp(commandValue, "request", strlen("request"))) sourceId = lastSourceId = SRC_CLIENT;
- else if ((commandLength == strlen("response")) && !memcmp(commandValue, "response", strlen("response"))) sourceId = lastSourceId = SRC_SERVER;
- else if ((commandLength == strlen("break")) && !memcmp(commandValue, "break", strlen("break"))) needBreak = true;
- else if ((commandLength == strlen("bodyend")) && !memcmp(commandValue, "bodyend", strlen("bodyend"))) {
- termBytes[0] = 'x';
- termBytes[1] = 'y';
+ if ((command_length == strlen("request")) && !memcmp(command_value, "request", strlen("request"))) {
+ source_id = last_source_id = SRC_CLIENT;
+ }
+ else if ((command_length == strlen("response")) && !memcmp(command_value, "response", strlen("response"))) {
+ source_id = last_source_id = SRC_SERVER;
}
- else if ((commandLength == strlen("chunkend")) && !memcmp(commandValue, "chunkend", strlen("chunkend"))) {
- termBytes[0] = '\r';
- termBytes[1] = '\n';
+ else if ((command_length == strlen("break")) && !memcmp(command_value, "break", strlen("break"))) {
+ need_break = true;
}
- else if (commandLength > 0) {
+ else if ((command_length == strlen("bodyend")) && !memcmp(command_value, "bodyend", strlen("bodyend"))) {
+ term_bytes[0] = 'x';
+ term_bytes[1] = 'y';
+ }
+ else if ((command_length == strlen("chunkend")) && !memcmp(command_value, "chunkend", strlen("chunkend"))) {
+ term_bytes[0] = '\r';
+ term_bytes[1] = '\n';
+ }
+ else if (command_length > 0) {
// Look for a test number
- bool isNumber = true;
- for (int k=0; (k < commandLength) && isNumber; k++) {
- isNumber = (commandValue[k] >= '0') && (commandValue[k] <= '9');
+ bool is_number = true;
+ for (int k=0; (k < command_length) && is_number; k++) {
+ is_number = (command_value[k] >= '0') && (command_value[k] <= '9');
}
- if (isNumber) {
- testNumber = 0;
- for (int j=0; j < commandLength; j++) {
- testNumber = testNumber * 10 + (commandValue[j] - '0');
+ if (is_number) {
+ test_number = 0;
+ for (int j=0; j < command_length; j++) {
+ test_number = test_number * 10 + (command_value[j] - '0');
}
}
}
}
else {
- if (commandLength < MaxCommand) commandValue[commandLength++] = newChar;
- else assert(0);
+ if (command_length < max_command) {
+ command_value[command_length++] = new_char;
+ }
+ else {
+ assert(0);
+ }
}
break;
case SECTION:
- if (newChar == '\\') {
+ if (new_char == '\\') {
state = ESCAPE;
ending = false;
}
- else if (newChar == '\n') {
+ else if (new_char == '\n') {
if (ending) {
// Found the blank line that ends the section.
- endOffset = previousOffset + length;
+ end_offset = previous_offset + length;
return;
}
ending = true;
}
else {
ending = false;
- data[length++] = (uint8_t) newChar;
+ data[length++] = (uint8_t) new_char;
}
break;
case ESCAPE:
- switch (newChar) {
+ switch (new_char) {
case 'n': state = SECTION; data[length++] = '\n'; break;
case 'r': state = SECTION; data[length++] = '\r'; break;
case 't': state = SECTION; data[length++] = '\t'; break;
case '@': state = SECTION; data[length++] = '@'; break;
case '\\': state = SECTION; data[length++] = '\\'; break;
case 'x':
- case 'X': state = HEXVAL; hexVal = 0; numDigits = 0; break;
+ case 'X': state = HEXVAL; hex_val = 0; num_digits = 0; break;
default: assert(0); state = SECTION; break;
}
break;
case HEXVAL:
- if ((newChar >= '0') && (newChar <= '9')) hexVal = hexVal * 16 + (newChar - '0');
- else if ((newChar >= 'a') && (newChar <= 'f')) hexVal = hexVal * 16 + 10 + (newChar - 'a');
- else if ((newChar >= 'A') && (newChar <= 'F')) hexVal = hexVal * 16 + 10 + (newChar - 'A');
+ if ((new_char >= '0') && (new_char <= '9')) hex_val = hex_val * 16 + (new_char - '0');
+ else if ((new_char >= 'a') && (new_char <= 'f')) hex_val = hex_val * 16 + 10 + (new_char - 'a');
+ else if ((new_char >= 'A') && (new_char <= 'F')) hex_val = hex_val * 16 + 10 + (new_char - 'A');
else assert(0);
- if (++numDigits == 2) {
- data[length++] = hexVal;
+ if (++num_digits == 2) {
+ data[length++] = hex_val;
state = SECTION;
}
break;
}
// Don't allow a buffer overrun.
- if (previousOffset + length >= sizeof(msgBuf)) assert(0);
+ if (previous_offset + length >= sizeof(msg_buf)) assert(0);
}
// End-of-file. Return everything we have so far.
- endOffset = previousOffset + length;
+ end_offset = previous_offset + length;
return;
}
void NHttpTestInput::flush(uint32_t length) {
- flushOctets = previousOffset + length;
- justFlushed = true;
+ flush_octets = previous_offset + length;
+ just_flushed = true;
}
-void NHttpTestInput::reassemble(uint8_t **buffer, unsigned &length, SourceId &sourceId) {
- sourceId = lastSourceId;
- *buffer = msgBuf;
+void NHttpTestInput::reassemble(uint8_t **buffer, unsigned &length, SourceId &source_id) {
+ source_id = last_source_id;
+ *buffer = msg_buf;
- if (flushOctets <= endOffset) {
+ if (flush_octets <= end_offset) {
// All the data we need comes from the file
- length = flushOctets;
+ length = flush_octets;
}
else {
// We need to generate additional data to fill out the body or chunk section
// We may come through here multiple times as we generate all the PAF max body sections needed for a single flush
- length = (flushOctets <= 16384) ? flushOctets : 16384;
- for (uint32_t k = endOffset; k < length; k++) {
- msgBuf[k] = 'A' + k % 26;
+ length = (flush_octets <= 16384) ? flush_octets : 16384;
+ for (uint32_t k = end_offset; k < length; k++) {
+ msg_buf[k] = 'A' + k % 26;
}
- flushOctets -= length;
+ flush_octets -= length;
- if (flushOctets == 0) {
- if (length-endOffset > 1) {
- msgBuf[length-2] = termBytes[0];
+ if (flush_octets == 0) {
+ if (length-end_offset > 1) {
+ msg_buf[length-2] = term_bytes[0];
}
- msgBuf[length-1] = termBytes[1];
+ msg_buf[length-1] = term_bytes[1];
}
- else if (flushOctets == 1) {
- msgBuf[length-1] = termBytes[0];
+ else if (flush_octets == 1) {
+ msg_buf[length-1] = term_bytes[0];
}
- endOffset = 0;
+ end_offset = 0;
}
}
public:
NHttpTestInput(const char *fileName);
~NHttpTestInput();
- void scan(uint8_t*& data, uint32_t &length, NHttpEnums::SourceId &sourceId, bool &tcpClose, bool &needBreak);
+ void scan(uint8_t*& data, uint32_t &length, NHttpEnums::SourceId &source_id, bool &tcp_close, bool &need_break);
void flush(uint32_t length);
- void reassemble(uint8_t **buffer, unsigned &length, NHttpEnums::SourceId &sourceId);
+ void reassemble(uint8_t **buffer, unsigned &length, NHttpEnums::SourceId &source_id);
static bool test_input;
- static NHttpTestInput *testInput;
- int64_t getTestNumber() { return testNumber; };
+ static NHttpTestInput *test_input_source;
+ int64_t get_test_number() { return test_number; };
private:
- FILE *testDataFile;
- uint8_t msgBuf[2 * NHttpEnums::MAXOCTETS];
- bool justFlushed = true; // all octets sent to inspection and must resume reading the file
- bool tcpAlreadyClosed = false; // so we can keep presenting a TCP close to PAF until all the remaining octets are consumed and flushed
- uint32_t flushOctets = 0; // number of octets that have been flushed and must go to inspection
- uint32_t previousOffset = 0; // last character in the buffer shown to PAF but not flushed yet
- uint32_t endOffset = 0; // last read character in the buffer
- int64_t testNumber = 0; // for numbering test output files
- NHttpEnums::SourceId lastSourceId = NHttpEnums::SRC_CLIENT; // current direction of traffic flow. Toggled by commands in file.
- uint8_t termBytes[2] = { 'x', 'y' };
+ FILE *test_data_file;
+ uint8_t msg_buf[2 * NHttpEnums::MAXOCTETS];
+ bool just_flushed = true; // all octets sent to inspection and must resume reading the file
+ bool tcp_already_closed = false; // so we can keep presenting a TCP close to PAF until all the remaining octets are consumed and flushed
+ uint32_t flush_octets = 0; // number of octets that have been flushed and must go to inspection
+ uint32_t previous_offset = 0; // last character in the buffer shown to PAF but not flushed yet
+ uint32_t end_offset = 0; // last read character in the buffer
+ int64_t test_number = 0; // for numbering test output files
+ NHttpEnums::SourceId last_source_id = NHttpEnums::SRC_CLIENT; // current direction of traffic flow. Toggled by commands in file.
+ uint8_t term_bytes[2] = { 'x', 'y' };
};
#endif
using namespace NHttpEnums;
-void NHttpUri::parseUri() {
- if (uriType != URI__NOTCOMPUTE) return;
+void NHttpUri::parse_uri() {
+ if (uri_type != URI__NOTCOMPUTE) {
+ return;
+ }
if (uri.length <= 0) {
- uriType = URI__NOSOURCE;
+ uri_type = URI__NOSOURCE;
scheme.length = STAT_NOSOURCE;
authority.length = STAT_NOSOURCE;
- absPath.length = STAT_NOSOURCE;
+ abs_path.length = STAT_NOSOURCE;
return;
}
// Four basic types of HTTP URI
// "*" means request does not apply to any specific resource
if ((uri.length == 1) && (uri.start[0] == '*')) {
- uriType = URI_ASTERISK;
+ uri_type = URI_ASTERISK;
scheme.length = STAT_NOTPRESENT;
authority.length = STAT_NOTPRESENT;
- absPath.length = STAT_NOTPRESENT;
+ abs_path.length = STAT_NOTPRESENT;
}
// CONNECT method uses an authority
- else if (methodId == METH_CONNECT) {
- uriType = URI_AUTHORITY;
+ else if (method_id == METH_CONNECT) {
+ uri_type = URI_AUTHORITY;
scheme.length = STAT_NOTPRESENT;
authority.length = uri.length;
authority.start = uri.start;
- absPath.length = STAT_NOTPRESENT;
+ abs_path.length = STAT_NOTPRESENT;
}
// Absolute path is a path but no scheme or authority
else if (uri.start[0] == '/') {
- uriType = URI_ABSPATH;
+ uri_type = URI_ABSPATH;
scheme.length = STAT_NOTPRESENT;
authority.length = STAT_NOTPRESENT;
- absPath.length = uri.length;
- absPath.start = uri.start;
+ abs_path.length = uri.length;
+ abs_path.start = uri.start;
}
// Absolute URI includes scheme, authority, and path
else {
for (j = 0; (uri.start[j] != ':') && (j < uri.length); j++);
for (k = j+3; (uri.start[k] != '/') && (k < uri.length); k++);
if ((k < uri.length) && (uri.start[j+1] == '/') && (uri.start[j+2] == '/')) {
- uriType = URI_ABSOLUTE;
+ uri_type = URI_ABSOLUTE;
scheme.length = j;
scheme.start = uri.start;
authority.length = k - j - 3;
authority.start = uri.start + j + 3;
- absPath.length = uri.length - k;
- absPath.start = uri.start + k;
+ abs_path.length = uri.length - k;
+ abs_path.start = uri.start + k;
}
else {
- formatInfractions |= INF_BADURI;
- uriType = URI__PROBLEMATIC;
+ format_infractions |= INF_BADURI;
+ uri_type = URI__PROBLEMATIC;
scheme.length = STAT_PROBLEMATIC;
authority.length = STAT_PROBLEMATIC;
- absPath.length = STAT_PROBLEMATIC;
+ abs_path.length = STAT_PROBLEMATIC;
}
}
}
-SchemeId NHttpUri::getSchemeId() {
- if (schemeId != SCH__NOTCOMPUTE) return schemeId;
- if (getScheme().length <= 0) {
- schemeId = SCH__NOSOURCE;
- return schemeId;
+SchemeId NHttpUri::get_scheme_id() {
+ if (scheme_id != SCH__NOTCOMPUTE) {
+ return scheme_id;
+ }
+ if (get_scheme().length <= 0) {
+ scheme_id = SCH__NOSOURCE;
+ return scheme_id;
}
// Normalize scheme name to lower case for matching purposes
- uint8_t *lowerScheme;
- if ((lowerScheme = scratchPad.request(scheme.length)) == nullptr) {
- schemeInfractions |= INF_NOSCRATCH;
- schemeId = SCH__INSUFMEMORY;
- return schemeId;
- }
- norm2Lower(scheme.start, scheme.length, lowerScheme, schemeInfractions, nullptr);
- schemeId = (SchemeId) strToCode(lowerScheme, scheme.length, schemeList);
- return schemeId;
+ uint8_t *lower_scheme;
+ if ((lower_scheme = scratch_pad.request(scheme.length)) == nullptr) {
+ scheme_infractions |= INF_NOSCRATCH;
+ scheme_id = SCH__INSUFMEMORY;
+ return scheme_id;
+ }
+ norm_to_lower(scheme.start, scheme.length, lower_scheme, scheme_infractions, nullptr);
+ scheme_id = (SchemeId) str_to_code(lower_scheme, scheme.length, scheme_list);
+ return scheme_id;
}
-const Field& NHttpUri::getNormHost() {
- if (hostNorm.length != STAT_NOTCOMPUTE) return hostNorm;
- if (getHost().length < 0) {
- hostNorm.length = STAT_NOSOURCE;
- return hostNorm;
- }
- UriNormalizer::normalize(host, hostNorm, false, scratchPad, hostInfractions);
- return hostNorm;
+const Field& NHttpUri::get_norm_host() {
+ if (host_norm.length != STAT_NOTCOMPUTE) {
+ return host_norm;
+ }
+ if (get_host().length < 0) {
+ host_norm.length = STAT_NOSOURCE;
+ return host_norm;
+ }
+ UriNormalizer::normalize(host, host_norm, false, scratch_pad, host_infractions);
+ return host_norm;
}
-const Field& NHttpUri::getNormPath() {
- if (pathNorm.length != STAT_NOTCOMPUTE) return pathNorm;
- if (getPath().length < 0) {
- pathNorm.length = STAT_NOSOURCE;
- return pathNorm;
- }
- UriNormalizer::normalize(path, pathNorm, true, scratchPad, pathInfractions);
- return pathNorm;
+const Field& NHttpUri::get_norm_path() {
+ if (path_norm.length != STAT_NOTCOMPUTE) {
+ return path_norm;
+ }
+ if (get_path().length < 0) {
+ path_norm.length = STAT_NOSOURCE;
+ return path_norm;
+ }
+ UriNormalizer::normalize(path, path_norm, true, scratch_pad, path_infractions);
+ return path_norm;
}
-const Field& NHttpUri::getNormQuery() {
- if (queryNorm.length != STAT_NOTCOMPUTE) return queryNorm;
- if (getQuery().length < 0) {
- queryNorm.length = STAT_NOSOURCE;
- return queryNorm;
- }
- UriNormalizer::normalize(query, queryNorm, false, scratchPad, queryInfractions);
- return queryNorm;
+const Field& NHttpUri::get_norm_query() {
+ if (query_norm.length != STAT_NOTCOMPUTE) {
+ return query_norm;
+ }
+ if (get_query().length < 0) {
+ query_norm.length = STAT_NOSOURCE;
+ return query_norm;
+ }
+ UriNormalizer::normalize(query, query_norm, false, scratch_pad, query_infractions);
+ return query_norm;
}
-const Field& NHttpUri::getNormFragment() {
- if (fragmentNorm.length != STAT_NOTCOMPUTE) return fragmentNorm;
- if (getFragment().length < 0) {
- fragmentNorm.length = STAT_NOSOURCE;
- return fragmentNorm;
- }
- UriNormalizer::normalize(fragment, fragmentNorm, false, scratchPad, fragmentInfractions);
- return fragmentNorm;
+const Field& NHttpUri::get_norm_fragment() {
+ if (fragment_norm.length != STAT_NOTCOMPUTE) {
+ return fragment_norm;
+ }
+ if (get_fragment().length < 0) {
+ fragment_norm.length = STAT_NOSOURCE;
+ return fragment_norm;
+ }
+ UriNormalizer::normalize(fragment, fragment_norm, false, scratch_pad, fragment_infractions);
+ return fragment_norm;
}
-int32_t NHttpUri::getPortValue() {
- if (portValue != STAT_NOTCOMPUTE) return portValue;
- if (getPort().length <= 0) {
- portValue = STAT_NOSOURCE;
- return portValue;
+int32_t NHttpUri::get_port_value() {
+ if (port_value != STAT_NOTCOMPUTE) {
+ return port_value;
+ }
+ if (get_port().length <= 0) {
+ port_value = STAT_NOSOURCE;
+ return port_value;
}
- portValue = 0;
+ port_value = 0;
for (int k = 0; k < port.length; k++) {
- portValue = portValue * 10 + (port.start[k] - '0');
- if ((port.start[k] < '0') || (port.start[k] > '9') || (portValue > 65535))
+ port_value = port_value * 10 + (port.start[k] - '0');
+ if ((port.start[k] < '0') || (port.start[k] > '9') || (port_value > 65535))
{
- portInfractions |= INF_BADPORT;
- portValue = STAT_PROBLEMATIC;
+ port_infractions |= INF_BADPORT;
+ port_value = STAT_PROBLEMATIC;
break;
}
}
- return portValue;
+ return port_value;
}
-void NHttpUri::parseAuthority() {
- if (host.length != STAT_NOTCOMPUTE) return;
- if (getAuthority().length <= 0) {
+void NHttpUri::parse_authority() {
+ if (host.length != STAT_NOTCOMPUTE) {
+ return;
+ }
+ if (get_authority().length <= 0) {
host.length = STAT_NOSOURCE;
port.length = STAT_NOSOURCE;
return;
else port.length = STAT_NOTPRESENT;
}
-void NHttpUri::parseAbsPath() {
+void NHttpUri::parse_abs_path() {
if (path.length != STAT_NOTCOMPUTE) return;
- if (getAbsPath().length <= 0) {
+ if (get_abs_path().length <= 0) {
path.length = STAT_NOSOURCE;
query.length = STAT_NOSOURCE;
fragment.length = STAT_NOSOURCE;
return;
}
- path.start = absPath.start;
- for (path.length = 0; (absPath.start[path.length] != '?') && (absPath.start[path.length] != '#') && (path.length < absPath.length); path.length++);
- if (path.length == absPath.length) {
+ path.start = abs_path.start;
+ for (path.length = 0; (abs_path.start[path.length] != '?') && (abs_path.start[path.length] != '#') && (path.length < abs_path.length); path.length++);
+ if (path.length == abs_path.length) {
query.length = STAT_NOTPRESENT;
fragment.length = STAT_NOTPRESENT;
return;
}
- if (absPath.start[path.length] == '?') {
- query.start = absPath.start + path.length + 1;
- for (query.length = 0; (query.start[query.length] != '#') && (query.length < absPath.length - path.length - 1); query.length++);
+ if (abs_path.start[path.length] == '?') {
+ query.start = abs_path.start + path.length + 1;
+ for (query.length = 0; (query.start[query.length] != '#') && (query.length < abs_path.length - path.length - 1); query.length++);
fragment.start = query.start + query.length + 1;
- fragment.length = absPath.length - path.length - 1 - query.length - 1;
+ fragment.length = abs_path.length - path.length - 1 - query.length - 1;
}
else {
query.length = STAT_NOTPRESENT;
- fragment.start = absPath.start + path.length + 1;
- fragment.length = absPath.length - path.length - 1;
+ fragment.start = abs_path.start + path.length + 1;
+ fragment.length = abs_path.length - path.length - 1;
}
}
// Glue normalized URI fields back together
-const Field& NHttpUri::getNormLegacy() {
- if (legacyNorm.length != STAT_NOTCOMPUTE) return legacyNorm;
-
- if (getPath().length >= 0) UriNormalizer::normalize(path, pathNorm, true, scratchPad, pathInfractions);
- if (getHost().length >= 0) UriNormalizer::normalize(host, hostNorm, false, scratchPad, hostInfractions);
- if (getQuery().length >= 0) UriNormalizer::normalize(query, queryNorm, false, scratchPad, queryInfractions);
- if (getFragment().length >= 0) UriNormalizer::normalize(fragment, fragmentNorm, false, scratchPad, fragmentInfractions);
+const Field& NHttpUri::get_norm_legacy() {
+ if (legacy_norm.length != STAT_NOTCOMPUTE) {
+ return legacy_norm;
+ }
+ if (get_path().length >= 0) {
+ UriNormalizer::normalize(path, path_norm, true, scratch_pad, path_infractions);
+ }
+ if (get_host().length >= 0) {
+ UriNormalizer::normalize(host, host_norm, false, scratch_pad, host_infractions);
+ }
+ if (get_query().length >= 0) {
+ UriNormalizer::normalize(query, query_norm, false, scratch_pad, query_infractions);
+ }
+ if (get_fragment().length >= 0) {
+ UriNormalizer::normalize(fragment, fragment_norm, false, scratch_pad, fragment_infractions);
+ }
// We can reuse the raw URI for the normalized URI unless at least one part of the URI has been normalized
- if ((hostInfractions == 0) && (pathInfractions == 0) && (queryInfractions == 0) && (fragmentInfractions == 0)) {
- legacyNorm.start = uri.start;
- legacyNorm.length = uri.length;
- return legacyNorm;
+ if ((host_infractions == 0) && (path_infractions == 0) && (query_infractions == 0) && (fragment_infractions == 0)) {
+ legacy_norm.start = uri.start;
+ legacy_norm.length = uri.length;
+ return legacy_norm;
}
// Glue normalized URI pieces back together
- const uint32_t totalLength = ((scheme.length >= 0) ? scheme.length + 3 : 0) +
- ((hostNorm.length >= 0) ? hostNorm.length : 0) +
+ const uint32_t total_length = ((scheme.length >= 0) ? scheme.length + 3 : 0) +
+ ((host_norm.length >= 0) ? host_norm.length : 0) +
((port.length >= 0) ? port.length + 1 : 0) +
- ((pathNorm.length >= 0) ? pathNorm.length : 0) +
- ((queryNorm.length >= 0) ? queryNorm.length + 1 : 0) +
- ((fragmentNorm.length >= 0) ? fragmentNorm.length + 1 : 0);
- uint8_t* const scratch = scratchPad.request(totalLength);
+ ((path_norm.length >= 0) ? path_norm.length : 0) +
+ ((query_norm.length >= 0) ? query_norm.length + 1 : 0) +
+ ((fragment_norm.length >= 0) ? fragment_norm.length + 1 : 0);
+ uint8_t* const scratch = scratch_pad.request(total_length);
if (scratch != nullptr) {
uint8_t *current = scratch;
if (scheme.length >= 0) {
memcpy(current, "://", 3);
current += 3;
}
- if (hostNorm.length >= 0) {
- memcpy(current, hostNorm.start, hostNorm.length);
- current += hostNorm.length;
+ if (host_norm.length >= 0) {
+ memcpy(current, host_norm.start, host_norm.length);
+ current += host_norm.length;
}
if (port.length >= 0) {
memcpy(current, ":", 1);
memcpy(current, port.start, port.length);
current += port.length;
}
- if (pathNorm.length >= 0) {
- memcpy(current, pathNorm.start, pathNorm.length);
- current += pathNorm.length;
+ if (path_norm.length >= 0) {
+ memcpy(current, path_norm.start, path_norm.length);
+ current += path_norm.length;
}
- if (queryNorm.length >= 0) {
+ if (query_norm.length >= 0) {
memcpy(current, "?", 1);
current += 1;
- memcpy(current, queryNorm.start, queryNorm.length);
- current += queryNorm.length;
+ memcpy(current, query_norm.start, query_norm.length);
+ current += query_norm.length;
}
- if (fragmentNorm.length >= 0) {
+ if (fragment_norm.length >= 0) {
memcpy(current, "#", 1);
current += 1;
- memcpy(current, fragmentNorm.start, fragmentNorm.length);
- current += fragmentNorm.length;
+ memcpy(current, fragment_norm.start, fragment_norm.length);
+ current += fragment_norm.length;
}
- assert(totalLength == current - scratch);
- scratchPad.commit(current - scratch);
- legacyNorm.start = scratch;
- legacyNorm.length = current - scratch;
+ assert(total_length == current - scratch);
+ scratch_pad.commit(current - scratch);
+ legacy_norm.start = scratch;
+ legacy_norm.length = current - scratch;
}
- else legacyNorm.length = STAT_INSUFMEMORY;
- return legacyNorm;
+ else legacy_norm.length = STAT_INSUFMEMORY;
+ return legacy_norm;
}
class NHttpUri {
public:
- NHttpUri(const uint8_t* start, int32_t length, NHttpEnums::MethodId method) : uri(length, start), methodId(method),
- scratchPad(2*length+200) {};
- const Field& getUri() const { return uri; };
- NHttpEnums::UriType getUriType() { parseUri(); return uriType; };
- const Field& getScheme() { parseUri(); return scheme; };
- const Field& getAuthority() { parseUri(); return authority; };
- const Field& getHost() { parseAuthority(); return host; };
- const Field& getPort() { parseAuthority(); return port; };
- const Field& getAbsPath() { parseUri(); return absPath; };
- const Field& getPath() { parseAbsPath(); return path; };
- const Field& getQuery() { parseAbsPath(); return query; };
- const Field& getFragment() { parseAbsPath(); return fragment; };
-
- uint64_t getFormatInfractions() { parseUri(); return formatInfractions; };
- uint64_t getSchemeInfractions() { getSchemeId(); return schemeInfractions; };
- uint64_t getHostInfractions() { getNormHost(); return hostInfractions; };
- uint64_t getPortInfractions() { getPortValue(); return portInfractions; };
- uint64_t getPathInfractions() { getNormPath(); return pathInfractions; };
- uint64_t getQueryInfractions() { getNormQuery(); return queryInfractions; };
- uint64_t getFragmentInfractions() { getNormFragment(); return fragmentInfractions; };
- uint64_t getUriInfractions() { return getFormatInfractions() | getSchemeInfractions() | getHostInfractions() |
- getPortInfractions() | getPathInfractions() | getQueryInfractions() | getFragmentInfractions(); };
-
- NHttpEnums::SchemeId getSchemeId();
- const Field& getNormHost();
- int32_t getPortValue();
- const Field& getNormPath();
- const Field& getNormQuery();
- const Field& getNormFragment();
- const Field& getNormLegacy();
+ NHttpUri(const uint8_t* start, int32_t length, NHttpEnums::MethodId method) : uri(length, start), method_id(method),
+ scratch_pad(2*length+200) {};
+ const Field& get_uri() const { return uri; };
+ NHttpEnums::UriType get_uri_type() { parse_uri(); return uri_type; };
+ const Field& get_scheme() { parse_uri(); return scheme; };
+ const Field& get_authority() { parse_uri(); return authority; };
+ const Field& get_host() { parse_authority(); return host; };
+ const Field& get_port() { parse_authority(); return port; };
+ const Field& get_abs_path() { parse_uri(); return abs_path; };
+ const Field& get_path() { parse_abs_path(); return path; };
+ const Field& get_query() { parse_abs_path(); return query; };
+ const Field& get_fragment() { parse_abs_path(); return fragment; };
+
+ uint64_t get_format_infractions() { parse_uri(); return format_infractions; };
+ uint64_t get_scheme_infractions() { get_scheme_id(); return scheme_infractions; };
+ uint64_t get_host_infractions() { get_norm_host(); return host_infractions; };
+ uint64_t get_port_infractions() { get_port_value(); return port_infractions; };
+ uint64_t get_path_infractions() { get_norm_path(); return path_infractions; };
+ uint64_t get_query_infractions() { get_norm_query(); return query_infractions; };
+ uint64_t get_fragment_infractions() { get_norm_fragment(); return fragment_infractions; };
+ uint64_t get_uri_infractions() { return get_format_infractions() | get_scheme_infractions() | get_host_infractions() |
+ get_port_infractions() | get_path_infractions() | get_query_infractions() | get_fragment_infractions(); };
+
+ NHttpEnums::SchemeId get_scheme_id();
+ const Field& get_norm_host();
+ int32_t get_port_value();
+ const Field& get_norm_path();
+ const Field& get_norm_query();
+ const Field& get_norm_fragment();
+ const Field& get_norm_legacy();
private:
- static const StrCode schemeList[];
+ static const StrCode scheme_list[];
Field uri;
- const NHttpEnums::MethodId methodId;
+ const NHttpEnums::MethodId method_id;
Field scheme;
Field authority;
Field host;
Field port;
- Field absPath;
+ Field abs_path;
Field path;
Field query;
Field fragment;
- uint64_t formatInfractions = 0;
- uint64_t schemeInfractions = 0;
- uint64_t hostInfractions = 0;
- uint64_t portInfractions = 0;
- uint64_t pathInfractions = 0;
- uint64_t queryInfractions = 0;
- uint64_t fragmentInfractions = 0;
-
- NHttpEnums::UriType uriType = NHttpEnums::URI__NOTCOMPUTE;
- NHttpEnums::SchemeId schemeId = NHttpEnums::SCH__NOTCOMPUTE;
- Field hostNorm;
- int32_t portValue = NHttpEnums::STAT_NOTCOMPUTE;
- Field pathNorm;
- Field queryNorm;
- Field fragmentNorm;
- Field legacyNorm;
-
- void parseUri();
- void parseAuthority();
- void parseAbsPath();
-
- ScratchPad scratchPad;
+ uint64_t format_infractions = 0;
+ uint64_t scheme_infractions = 0;
+ uint64_t host_infractions = 0;
+ uint64_t port_infractions = 0;
+ uint64_t path_infractions = 0;
+ uint64_t query_infractions = 0;
+ uint64_t fragment_infractions = 0;
+
+ NHttpEnums::UriType uri_type = NHttpEnums::URI__NOTCOMPUTE;
+ NHttpEnums::SchemeId scheme_id = NHttpEnums::SCH__NOTCOMPUTE;
+ Field host_norm;
+ int32_t port_value = NHttpEnums::STAT_NOTCOMPUTE;
+ Field path_norm;
+ Field query_norm;
+ Field fragment_norm;
+ Field legacy_norm;
+
+ void parse_uri();
+ void parse_authority();
+ void parse_abs_path();
+
+ ScratchPad scratch_pad;
};
#endif
using namespace NHttpEnums;
-void UriNormalizer::normalize(const Field &input, Field &result, bool doPath, ScratchPad &scratchPad, uint64_t &infractions) {
+void UriNormalizer::normalize(const Field &input, Field &result, bool do_path, ScratchPad &scratch_pad, uint64_t &infractions) {
if (result.length != STAT_NOTCOMPUTE) return;
assert (input.length >= 0);
// Almost all HTTP requests are honest and rarely need expensive normalization processing. We do a quick scan for
// red flags and only perform normalization if something comes up. Otherwise we set the normalized field to point
// at the raw value.
- if ( ( doPath && pathCheck(input.start, input.length, infractions)) ||
- (!doPath && noPathCheck(input.start, input.length, infractions)))
+ if ( ( do_path && path_check(input.start, input.length, infractions)) ||
+ (!do_path && no_path_check(input.start, input.length, infractions)))
{
result.start = input.start;
result.length = input.length;
// Add an extra byte because normalization on rare occasions adds an extra character
// We need working space for two copies to do multiple passes.
// Round up to multiple of eight so that both copies are 64-bit aligned.
- const int32_t bufferLength = input.length + 1 + (8-(input.length+1)%8)%8;
- uint8_t * const scratch = scratchPad.request(2 * bufferLength);
+ const int32_t buffer_length = input.length + 1 + (8-(input.length+1)%8)%8;
+ uint8_t * const scratch = scratch_pad.request(2 * buffer_length);
if (scratch == nullptr) {
result.length = STAT_INSUFMEMORY;
return;
}
- uint8_t* const frontHalf = scratch;
- uint8_t* const backHalf = scratch + bufferLength;
-
- int32_t dataLength;
- dataLength = normCharClean(input.start, input.length, frontHalf, infractions, nullptr);
- if (doPath) {
- dataLength = normBackSlash(frontHalf, dataLength, backHalf, infractions, nullptr);
- dataLength = normPathClean(backHalf, dataLength, frontHalf, infractions, nullptr);
+ uint8_t* const front_half = scratch;
+ uint8_t* const back_half = scratch + buffer_length;
+
+ int32_t data_length;
+ data_length = norm_char_clean(input.start, input.length, front_half, infractions, nullptr);
+ if (do_path) {
+ data_length = norm_backslash(front_half, data_length, back_half, infractions, nullptr);
+ data_length = norm_path_clean(back_half, data_length, front_half, infractions, nullptr);
}
- scratchPad.commit(dataLength);
- result.start = frontHalf;
- result.length = dataLength;
+ scratch_pad.commit(data_length);
+ result.start = front_half;
+ result.length = data_length;
}
-bool UriNormalizer::noPathCheck(const uint8_t* inBuf, int32_t inLength, uint64_t& infractions) {
- for (int32_t k = 0; k < inLength; k++) {
- if ((uriChar[inBuf[k]] == CHAR_NORMAL) || (uriChar[inBuf[k]] == CHAR_PATH)) continue;
+bool UriNormalizer::no_path_check(const uint8_t* in_buf, int32_t in_length, uint64_t& infractions) {
+ for (int32_t k = 0; k < in_length; k++) {
+ if ((uri_char[in_buf[k]] == CHAR_NORMAL) || (uri_char[in_buf[k]] == CHAR_PATH)) continue;
infractions |= INF_URINEEDNORM;
return false;
}
return true;
}
-bool UriNormalizer::pathCheck(const uint8_t* inBuf, int32_t inLength, uint64_t& infractions) {
- for (int32_t k = 0; k < inLength; k++) {
- if (uriChar[inBuf[k]] == CHAR_NORMAL) continue;
- if ((inBuf[k] == '/') && ((k == 0) || (inBuf[k-1] != '/'))) continue;
+bool UriNormalizer::path_check(const uint8_t* in_buf, int32_t in_length, uint64_t& infractions) {
+ for (int32_t k = 0; k < in_length; k++) {
+ if (uri_char[in_buf[k]] == CHAR_NORMAL) continue;
+ if ((in_buf[k] == '/') && ((k == 0) || (in_buf[k-1] != '/'))) continue;
infractions |= INF_URINEEDNORM;
return false;
}
return true;
}
-int32_t UriNormalizer::normCharClean(const uint8_t* inBuf, int32_t inLength, uint8_t *outBuf, uint64_t& infractions, const void *) {
+int32_t UriNormalizer::norm_char_clean(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t& infractions, const void *) {
int32_t length = 0;
- for (int32_t k = 0; k < inLength; k++) {
- switch (uriChar[inBuf[k]]) {
+ for (int32_t k = 0; k < in_length; k++) {
+ switch (uri_char[in_buf[k]]) {
case CHAR_NORMAL:
case CHAR_PATH:
- outBuf[length++] = inBuf[k];
+ out_buf[length++] = in_buf[k];
break;
case CHAR_INVALID:
infractions |= INF_URIBADCHAR;
- outBuf[length++] = inBuf[k];
+ out_buf[length++] = in_buf[k];
break;
case CHAR_EIGHTBIT:
infractions |= INF_URI8BITCHAR;
- outBuf[length++] = inBuf[k];
+ out_buf[length++] = in_buf[k];
break;
case CHAR_PERCENT:
- if ((k+2 < inLength) && (asHex[inBuf[k+1]] != -1) && (asHex[inBuf[k+2]] != -1)) {
- if (asHex[inBuf[k+1]] <= 7) {
- uint8_t value = asHex[inBuf[k+1]] * 16 + asHex[inBuf[k+2]];
- if (goodPercent[value]) {
+ if ((k+2 < in_length) && (as_hex[in_buf[k+1]] != -1) && (as_hex[in_buf[k+2]] != -1)) {
+ if (as_hex[in_buf[k+1]] <= 7) {
+ uint8_t value = as_hex[in_buf[k+1]] * 16 + as_hex[in_buf[k+2]];
+ if (good_percent[value]) {
// Normal % escape of an ASCII special character that is supposed to be escaped
infractions |= INF_URIPERCENTNORMAL;
- outBuf[length++] = '%';
+ out_buf[length++] = '%';
}
else {
// Suspicious % escape of an ASCII character that does not need to be escaped
infractions |= INF_URIPERCENTASCII;
- if (uriChar[value] == CHAR_INVALID) infractions |= INF_URIBADCHAR;
- outBuf[length++] = value;
+ if (uri_char[value] == CHAR_INVALID) infractions |= INF_URIBADCHAR;
+ out_buf[length++] = value;
k += 2;
}
}
else {
// UTF-8 decoding not implemented yet
infractions |= INF_URIPERCENTUTF8;
- outBuf[length++] = '%';
+ out_buf[length++] = '%';
}
}
- else if ((k+5 < inLength) && (inBuf[k+1] == 'u') && (asHex[inBuf[k+2]] != -1) && (asHex[inBuf[k+3]] != -1)
- && (asHex[inBuf[k+4]] != -1) && (asHex[inBuf[k+5]] != -1)) {
+ else if ((k+5 < in_length) && (in_buf[k+1] == 'u') && (as_hex[in_buf[k+2]] != -1) && (as_hex[in_buf[k+3]] != -1)
+ && (as_hex[in_buf[k+4]] != -1) && (as_hex[in_buf[k+5]] != -1)) {
// 'u' UTF-16 decoding not implemented yet
infractions |= INF_URIPERCENTUCODE;
- outBuf[length++] = '%';
+ out_buf[length++] = '%';
}
else {
// Don't recognize it
infractions |= INF_URIPERCENTOTHER;
- outBuf[length++] = '%';
+ out_buf[length++] = '%';
}
break;
}
}
// Convert URI backslashes to slashes
-int32_t UriNormalizer::normBackSlash(const uint8_t* inBuf, int32_t inLength, uint8_t *outBuf, uint64_t& infractions, const void *) {
- for (int32_t k = 0; k < inLength; k++) {
- if (inBuf[k] != '\\') outBuf[k] = inBuf[k];
+int32_t UriNormalizer::norm_backslash(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t& infractions, const void *) {
+ for (int32_t k = 0; k < in_length; k++) {
+ if (in_buf[k] != '\\') out_buf[k] = in_buf[k];
else {
- outBuf[k] = '/';
+ out_buf[k] = '/';
infractions |= INF_URIBACKSLASH;
}
}
- return inLength;
+ return in_length;
}
// Caution: worst case output length is one greater than input length
-int32_t UriNormalizer::normPathClean(const uint8_t* inBuf, int32_t inLength, uint8_t *outBuf, uint64_t& infractions, const void *) {
+int32_t UriNormalizer::norm_path_clean(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t& infractions, const void *) {
int32_t length = 0;
// It simplifies the code that handles /./ and /../ to pretend there is an extra '/' after the buffer.
// Avoids making a special case of URIs that end in . or ..
// That is why the loop steps off the end of the input buffer by saying <= instead of <.
- for (int32_t k = 0; k <= inLength; k++) {
+ for (int32_t k = 0; k <= in_length; k++) {
// Pass through all non-slash characters and also the leading slash
- if (((k < inLength) && (inBuf[k] != '/')) || (k == 0)) {
- outBuf[length++] = inBuf[k];
+ if (((k < in_length) && (in_buf[k] != '/')) || (k == 0)) {
+ out_buf[length++] = in_buf[k];
}
// Ignore this slash if it directly follows another slash
- else if ((k < inLength) && (length >= 1) && (outBuf[length-1] == '/')) {
+ else if ((k < in_length) && (length >= 1) && (out_buf[length-1] == '/')) {
infractions |= INF_URIMULTISLASH;
}
// This slash is the end of a /./ pattern, ignore this slash and remove the period from the output
- else if ((length >= 2) && (outBuf[length-1] == '.') && (outBuf[length-2] == '/')) {
+ else if ((length >= 2) && (out_buf[length-1] == '.') && (out_buf[length-2] == '/')) {
infractions |= INF_URISLASHDOT;
length -= 1;
}
// This slash is the end of a /../ pattern, normalization depends on whether there is a previous directory that
// we can remove
- else if ((length >= 3) && (outBuf[length-1] == '.') && (outBuf[length-2] == '.') && (outBuf[length-3] == '/')) {
+ else if ((length >= 3) && (out_buf[length-1] == '.') && (out_buf[length-2] == '.') && (out_buf[length-3] == '/')) {
infractions |= INF_URISLASHDOTDOT;
// Traversing above the root of the absolute path. A path of the form /../../../foo/bar/whatever cannot be
// further normalized. Instead of taking away a directory we leave the .. and write out the new slash.
// This code can write out the pretend slash after the end of the buffer. That is intentional so that the
// normal form of "/../../../.." is "/../../../../"
if ( (length == 3) ||
- ((length >= 6) && (outBuf[length-4] == '.') && (outBuf[length-5] == '.') && (outBuf[length-6] == '/')))
+ ((length >= 6) && (out_buf[length-4] == '.') && (out_buf[length-5] == '.') && (out_buf[length-6] == '/')))
{
infractions |= INF_URIROOTTRAV;
- outBuf[length++] = '/';
+ out_buf[length++] = '/';
}
// Remove the previous directory from the output. "/foo/bar/../" becomes "/foo/"
else {
- for (length -= 3; outBuf[length-1] != '/'; length--);
+ for (length -= 3; out_buf[length-1] != '/'; length--);
}
}
// Pass through an ordinary slash
- else if (k < inLength) outBuf[length++] = '/';
+ else if (k < in_length) {
+ out_buf[length++] = '/';
+ }
}
return length;
}
class UriNormalizer {
public:
- static void normalize(const Field &input, Field &result, bool doPath, ScratchPad &scratchPad, uint64_t &infractions);
+ static void normalize(const Field &input, Field &result, bool do_path, ScratchPad &scratch_pad, uint64_t &infractions);
private:
- static const NHttpEnums::CharAction uriChar[256];
- static const int8_t asHex[256];
- static const bool goodPercent[256];
+ static const NHttpEnums::CharAction uri_char[256];
+ static const int8_t as_hex[256];
+ static const bool good_percent[256];
- static bool noPathCheck(const uint8_t* inBuf, int32_t inLength, uint64_t& infractions);
- static bool pathCheck(const uint8_t* inBuf, int32_t inLength, uint64_t& infractions);
+ static bool no_path_check(const uint8_t* in_buf, int32_t in_length, uint64_t& infractions);
+ static bool path_check(const uint8_t* in_buf, int32_t in_length, uint64_t& infractions);
- static int32_t normCharClean(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* notUsed);
- static int32_t normBackSlash(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* notUsed);
- static int32_t normPathClean(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* notUsed);
+ static int32_t norm_char_clean(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* not_used);
+ static int32_t norm_backslash(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* not_used);
+ static int32_t norm_path_clean(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* not_used);
};
#endif
using namespace NHttpEnums;
-const CharAction UriNormalizer::uriChar[256] = {
+const CharAction UriNormalizer::uri_char[256] = {
CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID,
CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID,
CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID,
CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT,
CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT };
-const int8_t UriNormalizer::asHex[256] = {
+const int8_t UriNormalizer::as_hex[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
-const bool UriNormalizer::goodPercent[256] = {
+const bool UriNormalizer::good_percent[256] = {
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,