From: Tom Peters Date: Mon, 14 Jul 2014 15:51:54 +0000 (-0400) Subject: just-in-time implementation and many refactorings X-Git-Tag: 3.0.0-233~1446 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=31cd6074cb05153a189dcc704ad3391f3b017ddb;p=thirdparty%2Fsnort3.git just-in-time implementation and many refactorings --- diff --git a/src/service_inspectors/nhttp_inspect/nhttp_api.cc b/src/service_inspectors/nhttp_inspect/nhttp_api.cc index 94bff6977..db9420bb6 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_api.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_api.cc @@ -50,7 +50,7 @@ void NHttpApi::nhttp_init() Inspector* NHttpApi::nhttp_ctor(Module* mod) { const NHttpModule* nhttpMod = (NHttpModule*) mod; - return new NHttpInspect(nhttpMod->get_test_input(), nhttpMod->get_test_output(), nhttpMod->get_test_inspect()); + return new NHttpInspect(nhttpMod->get_test_input(), nhttpMod->get_test_output()); } static const char* buffers[] = diff --git a/src/service_inspectors/nhttp_inspect/nhttp_enum.h b/src/service_inspectors/nhttp_inspect/nhttp_enum.h index fa94fb342..fcc8d6f31 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_enum.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_enum.h @@ -100,8 +100,11 @@ typedef enum { TRANSCODE__OTHER=1, TRANSCODE_CHUNKED, TRANSCODE_IDENTITY, TRANSC // Never use the start pointer without verifying that length > 0. struct field { public: - const uint8_t *start = nullptr; int32_t length = NHttpEnums::STAT_NOTCOMPUTE; + const uint8_t* start = nullptr; + + field(int32_t length_, const uint8_t* start_) : length(length_), start(start_) {}; + field() = default; }; typedef enum diff --git a/src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc b/src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc index 818c22900..b1e99bc28 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc @@ -41,17 +41,18 @@ NHttpFlowData::NHttpFlowData() : FlowData(nhttp_flow_id) {} void NHttpFlowData::halfReset(SourceId sourceId) { assert((sourceId == SRC_CLIENT) || (sourceId == SRC_SERVER)); - dataLength[sourceId] = STAT_NOTPRESENT; octetsExpected[sourceId] = STAT_NOTPRESENT; + + versionId[sourceId] = VERS__NOTPRESENT; + methodId[sourceId] = METH__NOTPRESENT; + statusCodeNum[sourceId] = 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; - - versionId[sourceId] = VERS__NOTPRESENT; - methodId[sourceId] = METH__NOTPRESENT; - statusCodeNum[sourceId] = STAT_NOTPRESENT; } diff --git a/src/service_inspectors/nhttp_inspect/nhttp_flow_data.h b/src/service_inspectors/nhttp_inspect/nhttp_flow_data.h index c35ed00be..de787eb02 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_flow_data.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_flow_data.h @@ -58,19 +58,17 @@ public: friend class NHttpMsgChunkHead; friend class NHttpMsgChunkBody; friend class NHttpMsgTrailer; - friend class NHttpTestInput; friend class NHttpStreamSplitter; private: void halfReset(NHttpEnums::SourceId sourceId); // StreamSplitter => Inspector (facts about the most recent message section) - NHttpEnums::SourceId sourceId = NHttpEnums::SRC__NOTCOMPUTE; - NHttpEnums::SectionType sectionType = NHttpEnums::SEC__NOTCOMPUTE; - bool tcpClose = false; - uint64_t infractions = 0; + // 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 }; + uint64_t infractions[2] = { 0, 0 }; // Inspector => StreamSplitter (facts about the message section that is coming next) - // 0 element refers to client request, 1 element refers to server response 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 diff --git a/src/service_inspectors/nhttp_inspect/nhttp_head_norm.cc b/src/service_inspectors/nhttp_inspect/nhttp_head_norm.cc index 9b3d6adc8..da296d607 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_head_norm.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_head_norm.cc @@ -60,57 +60,46 @@ int32_t HeaderNormalizer::deriveHeaderContent(const uint8_t *value, int32_t leng } // This method normalizes the header field value for headId. -int32_t HeaderNormalizer::normalize(HeaderId headId, ScratchPad &scratchPad, uint64_t &infractions, const HeaderId headerNameId[], const field headerValue[], int32_t numHeaders, - field &resultField) const { - // If the raw header is not present length will be STAT_NOSOURCE and normalization is skipped +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) { - resultField.length = STAT_NOTCONFIGURED; - return resultField.length; - } + if (format == NORM_NULL) return resultField.length = STAT_NOTCONFIGURED; + if (count == 0) return resultField.length = STAT_NOSOURCE; - // Search Header IDs from all the headers in this message. A critical issue is whether the header can be present more than once in a message. concatenateRepeats means the - // header can be present more than once. The standard normalization is to concatenate all the repeated field values into a comma-separated list. Otherwise there should not - // be more than one instance of this header. infractRepeats causes us to inspect for improper repeated headers. Regardless of whether we look for these extra values only - // the first value will be normalized. + // Search Header IDs from all the headers in this message. concatenateRepeats 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 firstMatch = -1; + int currMatch; for (int k=0; k < numHeaders; k++) { - if (headerNameId[k] == HEAD__NOTCOMPUTE) break; if (headerNameId[k] == headId) { - numMatches++; - if (numMatches == 1) firstMatch = k; - if ((numMatches == 1) || concatenateRepeats) bufferLength += headerValue[k].length; - if (!concatenateRepeats && !infractRepeats) break; + if (++numMatches == 1) currMatch = k; // remembering location of the first matching header + bufferLength += headerValue[k].length; + if (!concatenateRepeats || (numMatches >= count)) break; } } - if (numMatches == 0) { - resultField.length = STAT_NOSOURCE; - return resultField.length; - } - if (infractRepeats && (numMatches >= 2)) infractions |= INF_BADHEADERREPS; - - // The scratchPad provides the space to store the normalized value. 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. - if (concatenateRepeats) bufferLength += numMatches - 1; // allow space for concatenation commas - // 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. Needs improvement. + assert((!concatenateRepeats && (numMatches == 1)) || (concatenateRepeats && (numMatches == count))); + bufferLength += numMatches - 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. + + // 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) { - resultField.length = STAT_INSUFMEMORY; - return resultField.length; - } + 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; - int currMatch = firstMatch; + 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++) { if (j >= 1) { @@ -121,16 +110,12 @@ int32_t HeaderNormalizer::normalize(HeaderId headId, ScratchPad &scratchPad, uin int32_t growth = deriveHeaderContent(headerValue[currMatch].start, headerValue[currMatch].length, working); working += growth; dataLength += growth; - if (!concatenateRepeats) break; } 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) { - resultField.length = dataLength; - return resultField.length; - } + if (dataLength <= 0) return resultField.length = dataLength; } resultField.start = scratch; resultField.length = dataLength; @@ -139,3 +124,4 @@ int32_t HeaderNormalizer::normalize(HeaderId headId, ScratchPad &scratchPad, uin } + diff --git a/src/service_inspectors/nhttp_inspect/nhttp_head_norm.h b/src/service_inspectors/nhttp_inspect/nhttp_head_norm.h index 63b0d7e03..46af08127 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_head_norm.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_head_norm.h @@ -43,17 +43,16 @@ class HeaderNormalizer { public: - constexpr HeaderNormalizer(NHttpEnums::NormFormat _format, bool _concatenateRepeats, bool _infractRepeats, int32_t (*f1)(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*), + 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), - infractRepeats(_infractRepeats), normalizer { f1, f2, f3 }, normArg { f1Arg, f2Arg, f3Arg }, numNormalizers((f1 != nullptr) + (f1 != nullptr)*(f2 != nullptr) + (f1 != nullptr)*(f2 != nullptr)*(f3 != nullptr)) {}; - int32_t normalize(NHttpEnums::HeaderId headId, ScratchPad &scratchPad, uint64_t &infractions, const NHttpEnums::HeaderId headerNameId[], const field headerName[], int32_t numHeaders, - field &resultField) const; + 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;}; private: @@ -61,7 +60,6 @@ private: const NHttpEnums::NormFormat format; const bool concatenateRepeats; - const bool infractRepeats; int32_t (* const normalizer[3])(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*); const void * normArg[3]; const int numNormalizers; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc b/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc index 4bc2aec15..ef99df940 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc @@ -42,7 +42,7 @@ using namespace NHttpEnums; -NHttpInspect::NHttpInspect(bool test_input, bool _test_output, bool _test_inspect) : test_output(_test_output), test_inspect(_test_inspect) +NHttpInspect::NHttpInspect(bool test_input, bool _test_output) : test_output(_test_output) { NHttpTestInput::test_input = test_input; if (NHttpTestInput::test_input) { @@ -104,10 +104,10 @@ void NHttpInspect::eval(Packet* p) // Only packets from the StreamSplitter can be processed if (!PacketHasPAFPayload(p)) return; - process(p->data, p->dsize, p->flow); + process(p->data, p->dsize, p->flow, (p->packet_flags & PKT_FROM_CLIENT) ? SRC_CLIENT : SRC_SERVER); } -void NHttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const flow) +void NHttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const flow, SourceId sourceId) { delete msgSection; msgSection = nullptr; @@ -116,48 +116,44 @@ void NHttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* cons assert(sessionData); if (!NHttpTestInput::test_input) { - switch (sessionData->sectionType) { - case SEC_REQUEST: msgSection = new NHttpMsgRequest; break; - case SEC_STATUS: msgSection = new NHttpMsgStatus; break; - case SEC_HEADER: msgSection = new NHttpMsgHeader; break; - case SEC_BODY: msgSection = new NHttpMsgBody; break; - case SEC_CHUNKHEAD: msgSection = new NHttpMsgChunkHead; break; - case SEC_CHUNKBODY: msgSection = new NHttpMsgChunkBody; break; - case SEC_TRAILER: msgSection = new NHttpMsgTrailer; break; + 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; case SEC_DISCARD: return; default: assert(0); return; } - msgSection->loadSection(data, dsize, sessionData); } else { uint8_t *testBuffer; uint16_t testLength; - if ((testLength = NHttpTestInput::testInput->toEval(&testBuffer, testNumber)) > 0) { - switch (sessionData->sectionType) { - case SEC_REQUEST: msgSection = new NHttpMsgRequest; break; - case SEC_STATUS: msgSection = new NHttpMsgStatus; break; - case SEC_HEADER: msgSection = new NHttpMsgHeader; break; - case SEC_BODY: msgSection = new NHttpMsgBody; break; - case SEC_CHUNKHEAD: msgSection = new NHttpMsgChunkHead; break; - case SEC_CHUNKBODY: msgSection = new NHttpMsgChunkBody; break; - case SEC_TRAILER: msgSection = new NHttpMsgTrailer; break; + if ((testLength = NHttpTestInput::testInput->toEval(&testBuffer, testNumber, sourceId)) > 0) { + switch (sessionData->sectionType[sourceId]) { + case SEC_REQUEST: msgSection = new NHttpMsgRequest(testBuffer, testLength, sessionData, sourceId); break; + case SEC_STATUS: msgSection = new NHttpMsgStatus(testBuffer, testLength, sessionData, sourceId); break; + case SEC_HEADER: msgSection = new NHttpMsgHeader(testBuffer, testLength, sessionData, sourceId); break; + case SEC_BODY: msgSection = new NHttpMsgBody(testBuffer, testLength, sessionData, sourceId); break; + case SEC_CHUNKHEAD: msgSection = new NHttpMsgChunkHead(testBuffer, testLength, sessionData, sourceId); break; + case SEC_CHUNKBODY: msgSection = new NHttpMsgChunkBody(testBuffer, testLength, sessionData, sourceId); break; + case SEC_TRAILER: msgSection = new NHttpMsgTrailer(testBuffer, testLength, sessionData, sourceId); break; case SEC_DISCARD: return; default: assert(0); return; } - msgSection->loadSection(testBuffer, testLength, sessionData); } else { printf("Zero length test data.\n"); return; } } - msgSection->initSection(); msgSection->analyze(); msgSection->updateFlow(); msgSection->genEvents(); msgSection->legacyClients(); - if (test_inspect) msgSection->analyzeAll(); if (test_output) { if (!NHttpTestInput::test_input) msgSection->printSection(stdout); else { diff --git a/src/service_inspectors/nhttp_inspect/nhttp_inspect.h b/src/service_inspectors/nhttp_inspect/nhttp_inspect.h index e1db545f7..1e70bf881 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_inspect.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_inspect.h @@ -42,7 +42,7 @@ class NHttpApi; class NHttpInspect : public Inspector { public: - NHttpInspect(bool test_input, bool _test_output, bool _test_inspect); + NHttpInspect(bool test_input, bool _test_output); ~NHttpInspect(); bool get_buf(unsigned, Packet*, InspectionBuffer&); @@ -59,11 +59,10 @@ private: friend NHttpApi; NHttpMsgSection *msgSection = nullptr; - void process(const uint8_t* data, const uint16_t dsize, Flow* const flow); + void process(const uint8_t* data, const uint16_t dsize, Flow* const flow, NHttpEnums::SourceId sourceId_); // Test mode bool test_output; - bool test_inspect; const char *testInputFile = "nhttp_test_msgs.txt"; const char *testOutputPrefix = "nhttpresults/testcase"; FILE *testOut = nullptr; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_module.cc b/src/service_inspectors/nhttp_inspect/nhttp_module.cc index 691641f32..73b5670e1 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_module.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_module.cc @@ -39,13 +39,11 @@ NHttpModule::NHttpModule() : Module("nhttp_inspect", nhttpParams, nhttpEvents) { const Parameter NHttpModule::nhttpParams[] = {{ "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" }, - { "test_inspect", Parameter::PT_BOOL, nullptr, "false", "force all possible inspections and normalizations" }, { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }}; bool NHttpModule::begin(const char*, int, SnortConfig*) { test_input = false; test_output = false; - test_inspect = false; return true; } @@ -56,7 +54,6 @@ bool NHttpModule::end(const char*, int, SnortConfig*) { 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 if (val.is("test_inspect")) test_inspect = val.get_bool(); else return false; return true; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_module.h b/src/service_inspectors/nhttp_inspect/nhttp_module.h index 6b2b9a993..e1a9f566d 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_module.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_module.h @@ -41,13 +41,11 @@ public: unsigned get_gid() const; bool get_test_input() const { return test_input; }; bool get_test_output() const { return test_output; }; - bool get_test_inspect() const { return test_inspect; }; private: static const Parameter nhttpParams[]; static const RuleMap nhttpEvents[]; bool test_input = false; bool test_output = false; - bool test_inspect = false; }; #endif diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc index 207947370..b9adba537 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc @@ -38,17 +38,9 @@ using namespace NHttpEnums; -void NHttpMsgBody::loadSection(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_) { - NHttpMsgSection::loadSection(buffer, bufSize, sessionData_); - - dataLength = sessionData->dataLength[sourceId]; - bodySections = sessionData->bodySections[sourceId]; - bodyOctets = sessionData->bodyOctets[sourceId]; -} - -void NHttpMsgBody::initSection() { - data.length = STAT_NOTCOMPUTE; -} +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]) {} void NHttpMsgBody::analyze() { bodySections++; @@ -65,7 +57,7 @@ void NHttpMsgBody::genEvents() { if (infractions != 0) SnortEventqAdd(NHTTP_GID, EVENT_ASCII); // I'm just an example event } -void NHttpMsgBody::printSection(FILE *output) const { +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); printInterval(output, "Data", data.start, data.length); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_body.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_body.h index 97a3c5800..73af41a93 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_body.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_body.h @@ -37,11 +37,9 @@ class NHttpMsgBody : public NHttpMsgSection { public: - NHttpMsgBody() {}; - void loadSection(const uint8_t *buffer, const uint16_t bufsize, NHttpFlowData *sessionData_); - void initSection(); + NHttpMsgBody(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_); void analyze(); - void printSection(FILE *output) const; + void printSection(FILE *output); void genEvents(); void updateFlow(); void legacyClients(); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.cc index fddf73cc1..5197aaa31 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.cc @@ -38,17 +38,9 @@ using namespace NHttpEnums; -void NHttpMsgChunkBody::loadSection(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_) { - NHttpMsgBody::loadSection(buffer, bufSize, sessionData_); - - numChunks = sessionData->numChunks[sourceId]; - chunkSections = sessionData->chunkSections[sourceId]; - chunkOctets = sessionData->chunkOctets[sourceId]; -} - -void NHttpMsgChunkBody::initSection() { - NHttpMsgBody::initSection(); -} +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]) {} void NHttpMsgChunkBody::analyze() { bodySections++; @@ -82,7 +74,7 @@ void NHttpMsgChunkBody::genEvents() { if (infractions != 0) SnortEventqAdd(NHTTP_GID, EVENT_ASCII); // I'm just an example event } -void NHttpMsgChunkBody::printSection(FILE *output) const { +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); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.h index f18e6c2e4..0430affa4 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.h @@ -37,11 +37,9 @@ class NHttpMsgChunkBody : public NHttpMsgBody { public: - NHttpMsgChunkBody() {}; - void loadSection(const uint8_t *buffer, const uint16_t bufsize, NHttpFlowData *sessionData_); - void initSection(); + NHttpMsgChunkBody(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_); void analyze(); - void printSection(FILE *output) const; + void printSection(FILE *output); void genEvents(); void updateFlow(); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.cc index c15382e85..1a2598de7 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.cc @@ -38,6 +38,10 @@ 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]) {} + // 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 @@ -70,19 +74,6 @@ void NHttpMsgChunkHead::deriveChunkLength() { } } -void NHttpMsgChunkHead::loadSection(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_) { - NHttpMsgSection::loadSection(buffer, bufSize, sessionData_); - - bodySections = sessionData->bodySections[sourceId]; - numChunks = sessionData->numChunks[sourceId]; -} - -void NHttpMsgChunkHead::initSection() { - startLine.length = STAT_NOTCOMPUTE; - chunkSize.length = STAT_NOTCOMPUTE; - chunkExtensions.length = STAT_NOTCOMPUTE; -} - void NHttpMsgChunkHead::analyze() { bodySections++; // First section in a new chunk is just the start line. @@ -111,7 +102,7 @@ void NHttpMsgChunkHead::genEvents() { if (infractions != 0) SnortEventqAdd(NHTTP_GID, EVENT_ASCII); // I'm just an example event } -void NHttpMsgChunkHead::printSection(FILE *output) const { +void NHttpMsgChunkHead::printSection(FILE *output) { NHttpMsgSection::printMessageTitle(output, "chunk header"); fprintf(output, "Chunk size: %" PRIi64 "\n", dataLength); printInterval(output, "Chunk extensions", chunkExtensions.start, chunkExtensions.length); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.h index e99ca5e24..b32de8e9a 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.h @@ -37,11 +37,9 @@ class NHttpMsgChunkHead : public NHttpMsgSection { public: - NHttpMsgChunkHead() {}; - void loadSection(const uint8_t *buffer, const uint16_t bufsize, NHttpFlowData *sessionData_); - void initSection(); + NHttpMsgChunkHead(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_); void analyze(); - void printSection(FILE *output) const; + void printSection(FILE *output); void genEvents(); void updateFlow(); void legacyClients(); @@ -53,7 +51,7 @@ private: field chunkSize; field chunkExtensions; - int64_t dataLength; + int64_t dataLength = NHttpEnums::STAT_NOTCOMPUTE; int64_t bodySections; int64_t numChunks; }; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_head.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_head.cc index 997464a17..a4acd6d1d 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_head.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_head.cc @@ -42,7 +42,7 @@ void NHttpMsgHeader::genEvents() { if (infractions != 0) SnortEventqAdd(NHTTP_GID, EVENT_ASCII); // I'm just an example event } -void NHttpMsgHeader::printSection(FILE *output) const { +void NHttpMsgHeader::printSection(FILE *output) { NHttpMsgSection::printMessageTitle(output, "header"); NHttpMsgHeadShared::printHeaders(output); NHttpMsgSection::printMessageWrapup(output); @@ -51,9 +51,6 @@ void NHttpMsgHeader::printSection(FILE *output) const { void NHttpMsgHeader::updateFlow() { const uint64_t disasterMask = 0; - ; - headerNorms[HEAD_CONTENT_LENGTH]->normalize(HEAD_CONTENT_LENGTH, scratchPad, infractions, headerNameId, headerValue, MAXHEADERS, headerValueNorm[HEAD_CONTENT_LENGTH]); - // The following logic to determine body type is by no means the last word on this topic. if (tcpClose) { sessionData->typeExpected[sourceId] = SEC_CLOSED; @@ -69,8 +66,8 @@ void NHttpMsgHeader::updateFlow() { sessionData->halfReset(sourceId); } // 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, scratchPad, infractions, - headerNameId, headerValue, MAXHEADERS, headerValueNorm[HEAD_TRANSFER_ENCODING]) > 0) && + 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) ) { // Chunked body sessionData->typeExpected[sourceId] = SEC_CHUNKHEAD; @@ -78,8 +75,8 @@ void NHttpMsgHeader::updateFlow() { sessionData->bodyOctets[sourceId] = 0; sessionData->numChunks[sourceId] = 0; } - else if ((headerNorms[HEAD_CONTENT_LENGTH]->normalize(HEAD_CONTENT_LENGTH, scratchPad, infractions, - headerNameId, headerValue, MAXHEADERS, headerValueNorm[HEAD_CONTENT_LENGTH]) > 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)) { // Regular body sessionData->typeExpected[sourceId] = SEC_BODY; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_head.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_head.h index bb9898c3e..5584c11f5 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_head.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_head.h @@ -37,8 +37,9 @@ class NHttpMsgHeader: public NHttpMsgHeadShared { public: - NHttpMsgHeader() {}; - void printSection(FILE *output) const; + NHttpMsgHeader(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_) : + NHttpMsgHeadShared(buffer, bufSize, sessionData_, sourceId_) {}; + void printSection(FILE *output); void genEvents(); void updateFlow(); }; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.cc index b22a1bdd3..b5154dc18 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.cc @@ -38,37 +38,14 @@ using namespace NHttpEnums; -// Reinitialize everything derived in preparation for analyzing a new message -void NHttpMsgHeadShared::initSection() { - headers.length = STAT_NOTCOMPUTE; - numHeaders = STAT_NOTCOMPUTE; - for(int k = 0; k < MAXHEADERS; k++) { - headerLine[k].length = STAT_NOTCOMPUTE; - headerName[k].length = STAT_NOTCOMPUTE; - headerNameId[k] = HEAD__NOTCOMPUTE; - headerValue[k].length = STAT_NOTCOMPUTE; - } - for (int k = 1; k < HEAD__MAXVALUE; k++) { - headerValueNorm[k].length = STAT_NOSOURCE; - } -} - // 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 < MAXHEADERS; j++) { - if (headerName[j].length <= 0) break; + for (int j=0; j < numHeaders; j++) { deriveHeaderNameId(j); - // Mark this header field as present and therefore eligible for normalization - if (headerNameId[j] > 0) headerValueNorm[headerNameId[j]].length = STAT_NOTCOMPUTE; - } -} - -void NHttpMsgHeadShared::analyzeAll() { - for (int k=1; k <= numNorms; k++) { - headerNorms[k]->normalize((HeaderId)k, scratchPad, infractions, headerNameId, headerValue, MAXHEADERS, headerValueNorm[k]); + if (headerNameId[j] > 0) headerCount[headerNameId[j]]++; } } @@ -176,7 +153,7 @@ void NHttpMsgHeadShared::legacyClients() { 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; (headerNameId[k] != HEAD__NOTCOMPUTE) && (k < MAXHEADERS); k++) { + 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); break; @@ -184,26 +161,28 @@ void NHttpMsgHeadShared::legacyClients() { } if (sourceId == SRC_CLIENT) { - if (headerNorms[HEAD_COOKIE]->normalize(HEAD_COOKIE, scratchPad, infractions, headerNameId, headerValue, MAXHEADERS, headerValueNorm[HEAD_COOKIE]) > 0) { + 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); } } else { - if (headerNorms[HEAD_SET_COOKIE]->normalize(HEAD_SET_COOKIE, scratchPad, infractions, headerNameId, headerValue, MAXHEADERS, headerValueNorm[HEAD_SET_COOKIE]) > 0) { + 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); } } } -void NHttpMsgHeadShared::printHeaders(FILE *output) const { +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 < 200; j++) { + for (int j=0; j < numHeaders; j++) { snprintf(titleBuf, sizeof(titleBuf), "Header ID %d", headerNameId[j]); printInterval(output, titleBuf, headerValue[j].start, headerValue[j].length); } for (int k=1; k <= numNorms; k++) { - if (headerValueNorm[k].length != STAT_NOSOURCE) { + 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); printInterval(output, titleBuf, headerValueNorm[k].start, headerValueNorm[k].length, true); } @@ -214,8 +193,3 @@ void NHttpMsgHeadShared::printHeaders(FILE *output) const { - - - - - diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.h index 155015e82..4271e7a33 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.h @@ -39,14 +39,15 @@ class NHttpMsgHeadShared: public NHttpMsgSection { public: - void initSection(); void analyze(); - void analyzeAll(); void genEvents(); void legacyClients(); protected: - // Header normalization. There should be one of these for every different way we can process a header field value. + NHttpMsgHeadShared(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_) : + NHttpMsgSection(buffer, bufSize, sessionData_, sourceId_) {}; + + // 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; @@ -58,29 +59,29 @@ protected: static const HeaderNormalizer* const headerNorms[]; static const int32_t numNorms; - // Code conversion tables are for turning token strings into enums. + // Tables of header field names and header value names static const StrCode headerList[]; static const StrCode transCodeList[]; - // "Parse" methods cut things into pieces. "Derive" methods convert things into a new format such as an integer or enum token. "Normalize" methods convert - // things into a standard form without changing the underlying format. void parseWhole(); void parseHeaderBlock(); void parseHeaderLines(); void deriveHeaderNameId(int index); - void printHeaders(FILE *output) const; + void printHeaders(FILE *output); - // This is where all the derived values, extracted message parts, and normalized values are. - // Note that this is all scalars, buffer pointers, and buffer sizes. The actual buffers are in the message buffer (raw pieces) or the - // scratchPad (normalized pieces). 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; + int32_t numHeaders = NHttpEnums::STAT_NOTCOMPUTE; field headerLine[MAXHEADERS]; field headerName[MAXHEADERS]; NHttpEnums::HeaderId headerNameId[MAXHEADERS]; field headerValue[MAXHEADERS]; + + // Normalized values are indexed by HeaderId + int headerCount[NHttpEnums::HEAD__MAXVALUE] = { }; field headerValueNorm[NHttpEnums::HEAD__MAXVALUE]; }; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc index df05d1093..d7b630cf1 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc @@ -39,14 +39,6 @@ using namespace NHttpEnums; -// Reinitialize everything derived in preparation for analyzing a new message -void NHttpMsgRequest::initSection() { - NHttpMsgStart::initSection(); - method.length = STAT_NOTCOMPUTE; - delete uri; - uri = nullptr; -} - void NHttpMsgRequest::parseStartLine() { // 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 @@ -88,7 +80,7 @@ void NHttpMsgRequest::genEvents() { if (infractions != 0) SnortEventqAdd(NHTTP_GID, EVENT_ASCII); // I'm just an example event } -void NHttpMsgRequest::printSection(FILE *output) const { +void NHttpMsgRequest::printSection(FILE *output) { NHttpMsgSection::printMessageTitle(output, "request line"); fprintf(output, "Version Id: %d\n", versionId); fprintf(output, "Method Id: %d\n", methodId); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_request.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_request.h index db3968622..6fda62a87 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_request.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_request.h @@ -40,26 +40,20 @@ class NHttpMsgRequest: public NHttpMsgStart { public: - NHttpMsgRequest() {}; + NHttpMsgRequest(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_) : + NHttpMsgStart(buffer, bufSize, sessionData_, sourceId_) {}; ~NHttpMsgRequest() { delete uri; }; - void initSection(); - void printSection(FILE *output) const; + void printSection(FILE *output); void genEvents(); void updateFlow(); void legacyClients(); private: - // Code conversion tables are for turning token strings into enums. static const StrCode methodList[]; - // "Parse" methods cut things into pieces. "Extract" methods find the named item. "Derive" methods convert things into a new format - // such as an integer or enum token. "Normalize" methods convert things into a standard form without changing the underlying format. void parseStartLine(); void deriveMethodId(); - // This is where all the derived values, extracted message parts, and normalized values are. - // Note that these are all scalars, buffer pointers, and buffer sizes. The actual buffers are in the message buffer (raw pieces) or the - // scratchPad (normalized pieces). field method; NHttpUri* uri = nullptr; }; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc index 7071aa690..c9019a4a6 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc @@ -37,6 +37,16 @@ using namespace NHttpEnums; +NHttpMsgSection::NHttpMsgSection(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, SourceId sourceId_) : + length(bufSize), sessionData(sessionData_), sourceId(sourceId_), tcpClose(sessionData->tcpClose[sourceId]), + scratchPad(2*length+500), infractions(sessionData->infractions[sourceId]), versionId(sessionData->versionId[sourceId]), + methodId(sessionData->methodId[sourceId]), statusCodeNum(sessionData->statusCodeNum[sourceId]) +{ + rawBuf = new uint8_t[length]; + memcpy(rawBuf, buffer, length); + msgText = rawBuf; +} + // 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 or . These whitespace characters @@ -49,22 +59,6 @@ uint32_t NHttpMsgSection::findCrlf(const uint8_t* buffer, int32_t length, bool w return length; } -// Load a new message section -void NHttpMsgSection::loadSection(const uint8_t *buffer, const uint16_t bufsize, NHttpFlowData *sessionData_) { - length = bufsize; - memcpy(rawBuf, buffer, length); - - sessionData = sessionData_; - infractions = sessionData->infractions; - sourceId = sessionData->sourceId; - tcpClose = sessionData->tcpClose; - versionId = sessionData->versionId[sourceId]; - methodId = sessionData->methodId[sourceId]; - statusCodeNum = sessionData->statusCodeNum[sourceId]; - - scratchPad.reinit(); -} - void NHttpMsgSection::printInterval(FILE *output, const char* name, const uint8_t *text, int32_t length, bool intVals) { if ((length == STAT_NOTPRESENT) || (length == STAT_NOTCOMPUTE) || (length == STAT_NOSOURCE)) return; int outCount = fprintf(output, "%s, length = %d, ", name, length); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h index 19c378255..2a3f47187 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h @@ -39,17 +39,16 @@ class NHttpMsgSection { public: - virtual void loadSection(const uint8_t *buffer, const uint16_t bufsize, NHttpFlowData *sessionData_); - virtual ~NHttpMsgSection() = default; - virtual void initSection() = 0; + virtual ~NHttpMsgSection() {delete[] rawBuf;}; virtual void analyze() = 0; // Minimum necessary processing for every message - virtual void analyzeAll() {}; // Force all just-in-time processing (testing method) - virtual void printSection(FILE *output) const = 0; - virtual void genEvents() = 0; - virtual void updateFlow() = 0; - virtual void legacyClients() = 0; + 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 protected: + NHttpMsgSection(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_); + // Convenience methods static uint32_t findCrlf(const uint8_t* buffer, int32_t length, bool wrappable); static void printInterval(FILE *output, const char* name, const uint8_t *text, int32_t length, bool intVals = false); @@ -57,22 +56,20 @@ protected: void printMessageWrapup(FILE *output) const; // The current strategy is to copy the entire raw message section into this object. Here it is. - int32_t length; // Length of the original message section in octets - uint8_t rawBuf[NHttpEnums::MAXOCTETS]; // The original HTTP message section octets - // This pointer is the handle for working with the original message data. It makes it simple to later replace rawBuf with some other form of storage - // such as the buffer in the packet structure or something dynamic. Const x 2 because this pointer should never change and people working with the - // original message should not be changing it. Only loading a completely new message into rawBuf should do that. - const uint8_t * const msgText = rawBuf; + int32_t length; + uint8_t* rawBuf; + // This pseudonym for rawBuf isolates details of how the raw message is stored from everything else. + const uint8_t* msgText; NHttpFlowData* sessionData; - ScratchPad scratchPad {NHttpEnums::MAXOCTETS*2}; + NHttpEnums::SourceId sourceId; + bool tcpClose; + ScratchPad scratchPad; // This is where all the derived values, extracted message parts, and normalized values are. - // Note that these are all scalars, buffer pointers, and buffer sizes. The actual buffers are in message buffer (raw pieces) or the + // These are all scalars, buffer pointers, and buffer sizes. The actual buffers are in message buffer (raw pieces) or the // scratchPad (normalized pieces). uint64_t infractions; - bool tcpClose; - NHttpEnums::SourceId sourceId; NHttpEnums::VersionId versionId; NHttpEnums::MethodId methodId; int32_t statusCodeNum; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_start.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_start.cc index cdcdf445a..bb16694bd 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_start.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_start.cc @@ -23,7 +23,7 @@ // // @author Tom Peters // -// @brief NHttpMsgStart virtual class rolls up all the common elements of start line processing. +// @brief NHttpMsgStart virtual class rolls up all the common elements of request and status line processing. // @@ -38,13 +38,6 @@ using namespace NHttpEnums; -// Reinitialize everything derived in preparation for analyzing a new message -void NHttpMsgStart::initSection() { - startLine.length = STAT_NOTCOMPUTE; - version.length = STAT_NOTCOMPUTE; -} - -// Required message processing that is automatically done instead of being just-in-time void NHttpMsgStart::analyze() { startLine.start = msgText; startLine.length = findCrlf(startLine.start, length, false); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_start.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_start.h index 726602299..b46eb4f2b 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_start.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_start.h @@ -37,20 +37,15 @@ class NHttpMsgStart: public NHttpMsgSection { public: - NHttpMsgStart() {}; - void initSection(); void analyze(); void genEvents(); protected: - // "Parse" methods cut things into pieces. "Derive" methods convert things into a new format such as an integer or enum token. "Normalize" methods convert - // things into a standard form without changing the underlying format. + 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(); - // This is where all the derived values, extracted message parts, and normalized values are. - // Note that this is all scalars, buffer pointers, and buffer sizes. The actual buffers are in the message buffer (raw pieces) or the - // scratchPad (normalized pieces). field startLine; field version; }; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc index 48f3368e0..ba390aae6 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc @@ -38,13 +38,6 @@ using namespace NHttpEnums; -// Reinitialize everything derived in preparation for analyzing a new message -void NHttpMsgStatus::initSection() { - NHttpMsgStart::initSection(); - statusCode.length = STAT_NOTCOMPUTE; - reasonPhrase.length = STAT_NOTCOMPUTE; -} - // All the header processing that is done for every message (i.e. not just-in-time) is done here. void NHttpMsgStatus::analyze() { NHttpMsgStart::analyze(); @@ -100,7 +93,7 @@ void NHttpMsgStatus::genEvents() { if (infractions != 0) SnortEventqAdd(NHTTP_GID, EVENT_ASCII); // I'm just an example event } -void NHttpMsgStatus::printSection(FILE *output) const { +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); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_status.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_status.h index 597332d72..baf02883e 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_status.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_status.h @@ -37,23 +37,18 @@ class NHttpMsgStatus: public NHttpMsgStart { public: - NHttpMsgStatus() {}; - void initSection(); + NHttpMsgStatus(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_) : + NHttpMsgStart(buffer, bufSize, sessionData_, sourceId_) {}; void analyze(); - void printSection(FILE *output) const; + void printSection(FILE *output); void genEvents(); void updateFlow(); void legacyClients(); private: - // "Parse" methods cut things into pieces. "Derive" methods convert things into a new format such as an integer or enum token. "Normalize" methods convert - // things into a standard form without changing the underlying format. void parseStartLine(); void deriveStatusCodeNum(); - // This is where all the derived values, extracted message parts, and normalized values are. - // Note that this is all scalars, buffer pointers, and buffer sizes. The actual buffers are in the message buffer (raw pieces) or the - // scratchPad (normalized pieces). field statusCode; field reasonPhrase; }; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc index 049451a64..409b5872a 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc @@ -41,7 +41,7 @@ void NHttpMsgTrailer::genEvents() { if (infractions != 0) SnortEventqAdd(NHTTP_GID, EVENT_ASCII); // I'm just an example event } -void NHttpMsgTrailer::printSection(FILE *output) const { +void NHttpMsgTrailer::printSection(FILE *output) { NHttpMsgSection::printMessageTitle(output, "trailer"); NHttpMsgHeadShared::printHeaders(output); NHttpMsgSection::printMessageWrapup(output); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.h index 6c5101dd3..f74db6596 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.h @@ -37,8 +37,9 @@ class NHttpMsgTrailer: public NHttpMsgHeadShared { public: - NHttpMsgTrailer() {}; - void printSection(FILE *output) const; + NHttpMsgTrailer(const uint8_t *buffer, const uint16_t bufSize, NHttpFlowData *sessionData_, NHttpEnums::SourceId sourceId_) : + NHttpMsgHeadShared(buffer, bufSize, sessionData_, sourceId_) {}; + void printSection(FILE *output); void genEvents(); void updateFlow(); }; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_scratch_pad.h b/src/service_inspectors/nhttp_inspect/nhttp_scratch_pad.h index 4ad6cb074..3501eebc3 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_scratch_pad.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_scratch_pad.h @@ -46,7 +46,7 @@ class ScratchPad { public: ScratchPad(uint32_t _capacity) : capacity(_capacity), buffer(new uint64_t[_capacity/8+1]) {}; ~ScratchPad() { delete[] buffer; }; - void reinit() {used = 0;}; + /* &&& not needed anymore I think */ void reinit() {used = 0;}; uint8_t *request(uint32_t needed) const {return (needed <= capacity-used) ? (uint8_t*)(buffer+used) : nullptr;}; void commit(uint32_t taken) { used += taken + (8-(taken%8))%8; }; // round up to multiple of 8 to preserve alignment diff --git a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc index cb61fd70f..6bea3f9d2 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc @@ -39,10 +39,9 @@ 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->sourceId = sourceId; - sessionData->sectionType = sectionType; - sessionData->tcpClose = tcpClose; - sessionData->infractions = infractions; + 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->pafFlush(numOctets); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_tables.cc b/src/service_inspectors/nhttp_inspect/nhttp_tables.cc index fdad4c2d5..81917f9ec 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_tables.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_tables.cc @@ -167,12 +167,11 @@ const StrCode NHttpMsgHeadShared::transCodeList[] = { TRANSCODE_DEFLATE, "deflate"}, { 0, nullptr} }; -const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_NIL {NORM_NULL, false, false, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; -const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_BASIC {NORM_FIELD, false, false, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; -const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_CAT {NORM_FIELD, true, false, normRemoveLws, nullptr, nullptr, nullptr, nullptr, nullptr}; -const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_NOREPEAT {NORM_FIELD, false, true, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; -const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_DECIMAL {NORM_INT64, false, true, normDecimalInteger, nullptr, nullptr, nullptr, nullptr, nullptr}; -const HeaderNormalizer NHttpMsgHeadShared::NORMALIZER_TRANSCODE {NORM_ENUM64, true, false, normRemoveLws, nullptr, norm2Lower, nullptr, normSeqStrCode, NHttpMsgHeadShared::transCodeList}; +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, [HEAD__OTHER] = &NORMALIZER_BASIC, diff --git a/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc b/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc index d2f246c9d..70cbff4d3 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc @@ -253,9 +253,10 @@ void NHttpTestInput::pafFlush(uint32_t length) { } -uint16_t NHttpTestInput::toEval(uint8_t **buffer, int64_t &testNumber_) { +uint16_t NHttpTestInput::toEval(uint8_t **buffer, int64_t &testNumber_, SourceId &sourceId) { if (!flushed) return 0; testNumber_ = testNumber; + sourceId = lastSourceId; *buffer = msgBuf; if (fillOctets > 0) { uint32_t fillOut = (fillOctets <= 16384) ? fillOctets : 16384; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_test_input.h b/src/service_inspectors/nhttp_inspect/nhttp_test_input.h index 03e27a569..834458559 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_test_input.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_test_input.h @@ -35,7 +35,7 @@ public: ~NHttpTestInput(); void toPaf(uint8_t*& data, uint32_t &length, NHttpEnums::SourceId &sourceId, bool &tcpClose, bool &needBreak); void pafFlush(uint32_t length); - uint16_t toEval(uint8_t **buffer, int64_t &testNumber); + uint16_t toEval(uint8_t **buffer, int64_t &testNumber, NHttpEnums::SourceId &sourceId); // Hard for NHttpInspect and PAF to share these without making them "global". This is as good a place as any for them to live. static bool test_input; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_uri.h b/src/service_inspectors/nhttp_inspect/nhttp_uri.h index 181ccd2f6..669110386 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_uri.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_uri.h @@ -39,9 +39,7 @@ class NHttpUri { public: - NHttpUri(const uint8_t* start, int32_t length, NHttpEnums::MethodId method) : methodId(method) { - uri.length = length; uri.start = start; }; - + NHttpUri(const uint8_t* start, int32_t length, NHttpEnums::MethodId method) : uri(length, start), methodId(method) {}; field getUri() const { return uri; }; NHttpEnums::UriType getUriType() { parseUri(); return uriType; }; field getScheme() { parseUri(); return scheme; };