+++ /dev/null
-/****************************************************************************
- *
-** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
- * Copyright (C) 2003-2013 Sourcefire, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation. You may not use, modify or
- * distribute this program under any other version of the GNU General
- * Public License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- ****************************************************************************/
-
-//
-// @author Tom Peters <thopeter@cisco.com>
-//
-// @brief Flow Data object used to store session information with Streams
-//
-
-#include <assert.h>
-#include <string.h>
-#include <sys/types.h>
-#include "snort.h"
-#include "flow/flow.h"
-#include "nhttp_enum.h"
-#include "nhttp_flowdata.h"
-
-unsigned NHttpFlowData::nhttp_flow_id = 0;
-
-NHttpFlowData::NHttpFlowData() : FlowData(nhttp_flow_id)
-{
-}
-
-NHttpFlowData::~NHttpFlowData()
-{
-}
-
+++ /dev/null
-/****************************************************************************
- *
-** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
- * Copyright (C) 2003-2013 Sourcefire, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation. You may not use, modify or
- * distribute this program under any other version of the GNU General
- * Public License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- ****************************************************************************/
-
-//
-// @author Tom Peters <thopeter@cisco.com>
-//
-// @brief Converts protocol constant string to enum
-//
-
-#ifndef NHTTP_FLOWDATA_H
-#define NHTTP_FLOWDATA_H
-
-class NHttpFlowData : public FlowData
-{
-public:
- NHttpFlowData();
- ~NHttpFlowData();
- static unsigned nhttp_flow_id;
- static void init() { nhttp_flow_id = FlowData::get_flow_id(); };
-
- // PAF data
- NHttpEnums::SourceId sourceId = NHttpEnums::SRC_CLIENT;
- bool tcpClose = false;
- uint64_t infractions = 0;
-
- // Client message data
- NHttpEnums::SectionType clientTypeExpected = NHttpEnums::SEC_HEADER;
- int32_t clientOctetsExpected = NHttpEnums::STAT_NOTPRESENT;
-
- // Server message data
- NHttpEnums::SectionType serverTypeExpected = NHttpEnums::SEC_HEADER;
- int32_t serverOctetsExpected = NHttpEnums::STAT_NOTPRESENT;
-
- // Session data
-};
-
-#endif
-
+++ /dev/null
-/****************************************************************************
- *
-** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
- * Copyright (C) 2003-2013 Sourcefire, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation. You may not use, modify or
- * distribute this program under any other version of the GNU General
- * Public License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- ****************************************************************************/
-
-//
-// @author Tom Peters <thopeter@cisco.com>
-//
-// @brief HeaderNormalizer class
-//
-
-
-#include <assert.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include "snort.h"
-#include "snort_types.h"
-
-#include "nhttp_enum.h"
-#include "nhttp_scratchpad.h"
-#include "nhttp_strtocode.h"
-#include "nhttp_headnorm.h"
-
-using namespace NHttpEnums;
-
-// This derivation removes embedded CRLFs (wrapping), omits leading and trailing 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) const {
- int32_t outLength = 0;
- bool lastWhite = true;
- for (int 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];
- }
- else if (!lastWhite) {
- lastWhite = true;
- buffer[outLength++] = ' ';
- }
- }
- if ((outLength > 0) && (buffer[outLength - 1] == ' ')) outLength--;
- return outLength;
-}
-
-void HeaderNormalizer::normalize(ScratchPad &scratchPad, uint64_t &infractions, HeaderId headId, const HeaderId headerNameId[], const field headerValue[], int32_t numHeaders,
- field &resultField) const {
- // This method normalizes the header field value for headId.
- if (format == NORM_NULL) {
- resultField.length = STAT_NOTCONFIGURED;
- return;
- }
-
- // 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.
-
- int numMatches = 0;
- int32_t bufferLength = 0;
- int firstMatch = -1;
- 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 == 0) {
- resultField.length = STAT_NOTPRESENT;
- return;
- }
- 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
- bufferLength += (4-bufferLength%4)%4 + 200; // &&& 200 is a "way too big" fudge factor to allow for modest expansion of field size during normalization. Needs improvement.
- uint8_t *scratch;
- if ((scratch = scratchPad.request(2*bufferLength)) == nullptr) {
- resultField.length = STAT_INSUFMEMORY;
- return;
- }
-
- uint8_t * const frontHalf = scratch;
- uint8_t * const backHalf = scratch + bufferLength;
- uint8_t *working = (numNormalizers%2 == 0) ? frontHalf : backHalf;
- int currMatch = firstMatch;
- int32_t growth;
- int32_t dataLength = 0;
- for (int j=0; j < numMatches; j++) {
- if (j >= 1) {
- *working++ = ',';
- dataLength++;
- while (headerNameId[++currMatch] != headId);
- }
- 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.start = scratch;
- resultField.length = dataLength;
- scratchPad.commit(dataLength);
-}
-
-// 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 *notUsed) {
- uint32_t total = 0;
- int value;
- for (int32_t k=0; k < inLength; k++) {
- value = inBuf[k] - '0';
- if ((value < 0) || (value > 9)) {
- infractions |= INF_BADHEADERDATA;
- return STAT_PROBLEMATIC;
- }
- total = total*10 + value;
- }
- ((uint32_t*)outBuf)[0] = total;
- return sizeof(uint32_t);
-}
-
-
-int32_t norm2Lower(const uint8_t* inBuf, int32_t inLength, uint8_t* outBuf, uint64_t& infractions, const void *notUsed) {
- for (int32_t k=0; k < inLength; k++) {
- outBuf[k] = ((inBuf[k] < 'A') || (inBuf[k] > 'Z')) ? inBuf[k] : inBuf[k] - ('A' - 'a');
- }
- return inLength;
-}
-
-
-int32_t normStrCode(const uint8_t* inBuf, int32_t inLength, uint8_t* outBuf, uint64_t& infractions, const void *table) {
- ((uint32_t*)outBuf)[0] = strToCode(inBuf, inLength, (const StrCode*)table);
- return sizeof(uint32_t);
-}
-
-int32_t normSeqStrCode(const uint8_t* inBuf, int32_t inLength, uint8_t* outBuf, uint64_t& infractions, const void *table) {
- int32_t numCodes = 0;
- const uint8_t* start = inBuf;
- int32_t length = 0;
- while (true) {
- start += length;
- for (length = 0; (start + length < inBuf + inLength) && (start[length] != ','); length++);
- if (length == 0) ((uint32_t*)outBuf)[numCodes++] = STAT_EMPTYSTRING;
- else ((uint32_t*)outBuf)[numCodes++] = strToCode(start, length, (const StrCode*)table);
- if (start + length++ >= inBuf + inLength) break;
- }
- return numCodes * sizeof(uint32_t);
-}
-
-
-
-
-
+++ /dev/null
-/****************************************************************************
- *
-** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
- * Copyright (C) 2003-2013 Sourcefire, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation. You may not use, modify or
- * distribute this program under any other version of the GNU General
- * Public License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- ****************************************************************************/
-
-//
-// @author Tom Peters <thopeter@cisco.com>
-//
-// @brief HeaderNormalizer class declaration
-//
-
-#ifndef NHTTP_HEADNORM_H
-#define NHTTP_HEADNORM_H
-
-
-//-------------------------------------------------------------------------
-// HeaderNormalizer class
-// 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.
-
-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*),
- 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)) {};
- void normalize(ScratchPad &scratchPad, uint64_t &infractions, NHttpEnums::HeaderId headId, const NHttpEnums::HeaderId headerNameId[], const field headerName[], int32_t numHeaders,
- field &resultField) const;
- NHttpEnums::NormFormat getFormat() const {return format;};
-
-private:
- int32_t deriveHeaderContent(const uint8_t *value, int32_t length, uint8_t *buffer) const;
-
- 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;
-};
-
-// Normalizer functions
-
-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*);
-
-#endif
-
-
+++ /dev/null
-/****************************************************************************
- *
-** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
- * Copyright (C) 2003-2013 Sourcefire, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation. You may not use, modify or
- * distribute this program under any other version of the GNU General
- * Public License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- ****************************************************************************/
-
-//
-// @author Tom Peters <thopeter@cisco.com>
-//
-// @brief NHttpMsgHeader class analyzes individual HTTP messages.
-//
-
-
-#include <assert.h>
-#include <string.h>
-#include <sys/types.h>
-#include <stdio.h>
-
-#include "snort.h"
-#include "flow/flow.h"
-#include "detection/detection_util.h"
-#include "nhttp_enum.h"
-#include "nhttp_scratchpad.h"
-#include "nhttp_strtocode.h"
-#include "nhttp_headnorm.h"
-#include "nhttp_flowdata.h"
-#include "nhttp_msgheader.h"
-
-using namespace NHttpEnums;
-
-// 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 NHttpMsgHeader::findCrlf(const uint8_t* buffer, uint32_t length, bool wrappable) {
- for (uint32_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;
-}
-
-// Reinitialize everything and load a new message
-void NHttpMsgHeader::loadMessage(const uint8_t *buffer, const uint16_t bufsize, NHttpFlowData *sessionData_) {
- length = (bufsize <= MAXOCTETS) ? bufsize : MAXOCTETS;
- memcpy(rawBuf, buffer, length);
-
- sessionData = sessionData_;
- infractions = sessionData->infractions;
- sourceId = sessionData->sourceId;
- tcpClose = sessionData->tcpClose;
-
- scratchPad.reinit();
-
- startLine.length = STAT_NOTCOMPUTE;
- version.length = STAT_NOTCOMPUTE;
- versionId = VERS__NOTCOMPUTE;
- method.length = STAT_NOTCOMPUTE;
- methodId = METH__NOTCOMPUTE;
- uri.length = STAT_NOTCOMPUTE;
- statusCode.length = STAT_NOTCOMPUTE;
- statusCodeNum = STAT_NOTCOMPUTE;
- reasonPhrase.length = STAT_NOTCOMPUTE;
- 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_NOTCOMPUTE;
- }
-}
-
-// All the header processing that is done for every message (i.e. not just-in-time) is done here.
-void NHttpMsgHeader::analyze() {
- parseWhole();
- if (sourceId == SRC_CLIENT) {
- parseRequestLine();
- deriveMethodId();
- }
- else if (sourceId == SRC_SERVER) {
- parseStatusLine();
- deriveStatusCodeNum();
- }
- deriveVersionId();
- parseHeaderBlock();
- parseHeaderLines();
- for (int j=0; j < MAXHEADERS; j++) {
- if (headerName[j].length <= 0) break;
- deriveHeaderNameId(j);
- }
- for (int k=1; k <= numNorms; k++) {
- headerNorms[k]->normalize(scratchPad, infractions, (HeaderId)k, headerNameId, headerValue, MAXHEADERS, headerValueNorm[k]);
- }
-}
-
-// All we do here is separate the start line from the header fields.
-// It is so complicated because 1) there might not be any header fields and 2) the message may have been truncated by a TCP connection close.
-// The asserts are very useful in test mode because they pick up bad test case data that we are not designed to handle. Otherwise they should
-// never go off unless PAF is broken and feeding us bad stuff.
-void NHttpMsgHeader::parseWhole() {
- startLine.start = msgText;
- startLine.length = findCrlf(startLine.start, length, false);
- // findCrtl() guarentees that either the start line is the whole message or there must be at least two more characters and the first two are <CR><LF>.
- assert((length == startLine.length) || ((length >= startLine.length+2) && !memcmp(msgText + startLine.length, "\r\n", 2)));
- // We trust PAF. !tcpClose guarentees that either there are exactly four more characters <CR><LF><CR><LF> or there are at least seven more characters
- // with the first two being <CR><LF> and the last four being <CR><LF><CR><LF>.
- assert(tcpClose ||
- ((length == startLine.length+4) && !memcmp(msgText + startLine.length, "\r\n\r\n", 4)) ||
- ((length >= startLine.length+7) && !memcmp(msgText + startLine.length, "\r\n", 2) && !memcmp(msgText + length - 4, "\r\n\r\n", 4)));
-
- // The following if-else ladder puts the extremely common normal cases at the beginning and the rare pathological cases at the end
- // Normal case with header fields
- if (!tcpClose && (length >= startLine.length+7)) {
- headers.start = msgText + startLine.length + 2;
- headers.length = length - startLine.length - 6;
- }
- // Normal case no header fields (only a start line)
- else if (!tcpClose) {
- headers.length = STAT_NOTPRESENT;
- }
- // Normal case with header fields and TCP connection close
- else if ((length >= startLine.length+7) && !memcmp(msgText+length-4, "\r\n\r\n", 4)) {
- headers.start = msgText + startLine.length + 2;
- headers.length = length - startLine.length - 6;
- }
- // Normal case no header fields and TCP connection close
- else if ((length == startLine.length + 4) && !memcmp(msgText+length-2, "\r\n", 2)) {
- headers.length = STAT_NOTPRESENT;
- }
- // Abnormal cases truncated by TCP connection close
- else {
- infractions |= INF_TRUNCATED;
- // Either start line incomplete or start line complete but no leftover octets for anything else
- if (length <= startLine.length+2) {
- headers.length = STAT_NOTPRESENT;
- }
- // Start line complete followed by lone <CR>
- else if ((length == startLine.length+3) && (msgText[length-1] == '\r')) {
- headers.length = STAT_NOTPRESENT;
- }
- // Truncation occurred somewhere in the header fields
- else {
- headers.start = msgText + startLine.length + 2;
- headers.length = length - startLine.length - 2;
- // When present, remove partial <CR><LF><CR><LF> sequence from the very end
- if ((length > startLine.length+6) && !memcmp(msgText+length-3, "\r\n\r", 3)) headers.length -= 3;
- else if ((length > startLine.length+5) && !memcmp(msgText+length-2, "\r\n", 2)) headers.length -= 2;
- else if ((length > startLine.length+4) && (msgText[length-1] == '\r')) headers.length -= 1;
- }
- }
-}
-
-void NHttpMsgHeader::parseRequestLine() {
- // There should be exactly two spaces. One following the method and one before "HTTP/".
- // Eventually we may need to cater to certain format errors, but for now exact match or treat as error.
- // <method><SP><URI><SP>HTTP/X.Y
- if (startLine.start[startLine.length-9] != ' ') {
- // space before "HTTP" missing or in wrong place
- infractions |= INF_BADREQLINE;
- return;
- }
-
- int space = -1;
- for (int32_t k=0; k < startLine.length-9; k++) {
- if (startLine.start[k] == ' ') {
- if (space == -1) space = k;
- else {
- // too many spaces
- infractions |= INF_BADREQLINE;
- return;
- }
- }
- }
- if ((space <= 0)) {
- // no first space or a leading space
- infractions |= INF_BADREQLINE;
- return;
- }
-
- method.start = startLine.start;
- method.length = space;
- uri.start = startLine.start + method.length + 1;
- uri.length = startLine.length - method.length - 10;
- version.start = startLine.start + (startLine.length - 8);
- version.length = 8;
- assert (startLine.length == method.length + uri.length + version.length + 2);
-}
-
-void NHttpMsgHeader::parseStatusLine() {
- // 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] != ' ')) {
- infractions |= INF_BADSTATLINE;
- return;
- }
- version.start = startLine.start;
- version.length = 8;
- statusCode.start = startLine.start + 9;
- statusCode.length = 3;
- reasonPhrase.start = startLine.start + 13;
- reasonPhrase.length = startLine.length - 13;
- assert (startLine.length == version.length + statusCode.length + reasonPhrase.length + 2);
-}
-
-// Divide up the block of header fields into individual header field lines.
-void NHttpMsgHeader::parseHeaderBlock() {
- if (headers.length <= 0) 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) {
- break;
- }
- }
- if (bytesused < headers.length) {
- infractions |= INF_TOOMANYHEADERS;
- }
-}
-
-// Divide header field lines into field name and field value
-void NHttpMsgHeader::parseHeaderLines() {
- int colon;
- for (int k=0; k < numHeaders; k++) {
- for (colon=0; colon < headerLine[k].length; colon++) {
- if (headerLine[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;
- }
- else {
- infractions |= INF_BADHEADER;
- }
- }
-}
-
-void NHttpMsgHeader::deriveStatusCodeNum() {
- if (statusCode.length != 3) {
- statusCodeNum = 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')) {
- infractions |= INF_BADSTATCODE;
- statusCodeNum = STAT_PROBLEMATIC;
- return;
- }
- statusCodeNum = (statusCode.start[0] - '0') * 100 + (statusCode.start[1] - '0') * 10 + (statusCode.start[2] - '0');
- if ((statusCodeNum < 100) || (statusCodeNum > 599)) {
- infractions |= INF_BADSTATCODE;
- }
-}
-
-void NHttpMsgHeader::deriveVersionId() {
- if (version.length != 8) {
- versionId = VERS__PROBLEMATIC;
- return;
- }
- if (memcmp(version.start, "HTTP/", 5) || (version.start[6] != '.')) {
- versionId = VERS__PROBLEMATIC;
- infractions |= INF_BADVERSION;
- }
- else if ((version.start[5] == '1') && (version.start[7] == '1')) {
- versionId = VERS_1_1;
- }
- else if ((version.start[5] == '1') && (version.start[7] == '0')) {
- versionId = VERS_1_0;
- }
- else if ((version.start[5] == '2') && (version.start[7] == '0')) {
- versionId = VERS_2_0;
- }
- else if ((version.start[5] >= '0') && (version.start[5] <= '9') && (version.start[7] >= '0') && (version.start[7] <= '9')) {
- versionId = VERS__OTHER;
- infractions |= INF_UNKNOWNVERSION;
- }
- else {
- versionId = VERS__PROBLEMATIC;
- infractions |= INF_BADVERSION;
- }
-}
-
-void NHttpMsgHeader::deriveMethodId() {
- methodId = (MethodId) strToCode(method.start, method.length, methodList);
-}
-
-void NHttpMsgHeader::deriveHeaderNameId(int index) {
- if (headerName[index].length <= 0) return;
- // Normalize header field name to lower case for matching purposes
- uint8_t *lowerName;
- if ((lowerName = scratchPad.request(headerName[index].length)) == nullptr) {
- infractions |= INF_NOSCRATCH;
- headerNameId[index] = HEAD__INSUFMEMORY;
- return;
- }
- int32_t lowerLength = norm2Lower(headerName[index].start, headerName[index].length, lowerName, infractions, nullptr);
- headerNameId[index] = (HeaderId) strToCode(lowerName, lowerLength, headerList);
-}
-
-void NHttpMsgHeader::genEvents() {
- if (infractions != 0) SnortEventqAdd(GID_HTTP_CLIENT, 1); // I'm just an example event (HI_CLIENT_ASCII)
-}
-
-void NHttpMsgHeader::printInterval(FILE *output, const char* name, const uint8_t *text, int32_t length, bool intVals) {
- if ((length == STAT_NOTPRESENT) || (length == STAT_NOTCOMPUTE)) return;
- fprintf(output, "%s, length = %d\n", name, length);
- if (length <= 0) return;
- if (text == nullptr) {
- fprintf(output, "nullptr\n");
- return;
- }
- for (int k=0; k < length; k++) {
- if ((text[k] >= 0x20) && (text[k] <= 0x7E)) fprintf(output, "%c", (char)text[k]);
- else if (text[k] == 0x0) fprintf(output, "~");
- else if (text[k] == 0xD) fprintf(output, "`");
- else if (text[k] == 0xA) fprintf(output, "'");
- else fprintf(output, "*");
- if (k%200 == 199) fprintf(output, "\n");
- }
-
- if (intVals && (length%4 == 0)) {
- fprintf(output, "\nInteger values =");
- for (int j=0; j < length; j+=4) {
- fprintf(output, " %u", *((const uint32_t*)(text+j)));
- }
- }
- fprintf(output, "\n");
-}
-
-void NHttpMsgHeader::printMessage(FILE *output) {
- fprintf(output, "Printout of HTTP message structure.\n");
- printInterval(output, "Raw message", msgText, length);
- printInterval(output, "Start Line", startLine.start, startLine.length);
- if (sourceId != SRC__NOTCOMPUTE) fprintf(output, "Source Id: %d\n", sourceId);
- printInterval(output, "Version", version.start, version.length);
- if (versionId != VERS__NOTCOMPUTE) fprintf(output, "Version Id: %d\n", versionId);
- printInterval(output, "Method", method.start, method.length);
- if (methodId != METH__NOTCOMPUTE) fprintf(output, "Method Id: %d\n", methodId);
- printInterval(output, "URI", uri.start, uri.length);
- printInterval(output, "Status Code", statusCode.start, statusCode.length);
- if (statusCodeNum != STAT_NOTCOMPUTE) fprintf(output, "Status Code Num: %d\n", statusCodeNum);
- printInterval(output, "Reason Phrase", reasonPhrase.start, reasonPhrase.length);
- printInterval(output, "Headers", headers.start, headers.length);
- if (numHeaders != STAT_NOTCOMPUTE) fprintf(output, "Number of headers: %d\n", numHeaders);
- for (int j=0; j < numHeaders && j < 200; j++) {
- printInterval(output, "Header Line", headerLine[j].start, headerLine[j].length);
- printInterval(output, "Header Name", headerName[j].start, headerName[j].length);
- fprintf(output, "Header name Id: %d\n", headerNameId[j]);
- printInterval(output, "Header Value", headerValue[j].start, headerValue[j].length);
- }
- for (int k=1; k <= numNorms; k++) {
- if (headerValueNorm[k].length != STAT_NOTPRESENT) fprintf(output, "Header ID = %d\n", k);
- printInterval(output, "Header Value Normalized", headerValueNorm[k].start, headerValueNorm[k].length, true);
- }
- fprintf(output, "Infractions: %lx\n", infractions);
- fprintf(output, "TCP Close: %s\n", tcpClose ? "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) printInterval(output, http_buffer_name[i], http_buffer[i].buf, http_buffer[i].length);
- }
-}
-
-// Legacy support function. Puts message fields into the buffers used by old Snort. This should go away.
-void NHttpMsgHeader::oldClients() {
- ClearHttpBuffers();
-
- if (method.length > 0) SetHttpBuffer(HTTP_BUFFER_METHOD, method.start, (unsigned)method.length);
- if (uri.length > 0) SetHttpBuffer(HTTP_BUFFER_RAW_URI, uri.start, (unsigned)uri.length);
- if (uri.length > 0) SetHttpBuffer(HTTP_BUFFER_URI, uri.start, (unsigned)uri.length);
- 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);
- if (statusCode.length > 0) SetHttpBuffer(HTTP_BUFFER_STAT_CODE, statusCode.start, (unsigned)statusCode.length);
- if (reasonPhrase.length > 0) SetHttpBuffer(HTTP_BUFFER_STAT_MSG, reasonPhrase.start, (unsigned)reasonPhrase.length);
-
- for (int k=0; (headerNameId[k] != HEAD__NOTCOMPUTE) && (k < MAXHEADERS); 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;
- }
- }
-
- if ((sourceId == SRC_CLIENT) && (headerValueNorm[HEAD_COOKIE].length > 0))
- SetHttpBuffer(HTTP_BUFFER_COOKIE, headerValueNorm[HEAD_COOKIE].start, (unsigned)headerValueNorm[HEAD_COOKIE].length);
- else if ((sourceId == SRC_SERVER) && (headerValueNorm[HEAD_SET_COOKIE].length > 0))
- SetHttpBuffer(HTTP_BUFFER_COOKIE, headerValueNorm[HEAD_SET_COOKIE].start, (unsigned)headerValueNorm[HEAD_SET_COOKIE].length);
-}
-
+++ /dev/null
-/****************************************************************************
- *
-** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
- * Copyright (C) 2003-2013 Sourcefire, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation. You may not use, modify or
- * distribute this program under any other version of the GNU General
- * Public License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- ****************************************************************************/
-
-//
-// @author Tom Peters <thopeter@cisco.com>
-//
-// @brief NHttpMsgHeader class declaration
-//
-
-#ifndef NHTTP_MSGHEADER_H
-#define NHTTP_MSGHEADER_H
-
-
-//-------------------------------------------------------------------------
-// NHttpMsgHeader class
-//-------------------------------------------------------------------------
-
-class NHttpMsgHeader {
-public:
- NHttpMsgHeader() {};
- void loadMessage(const uint8_t *buffer, const uint16_t bufsize, NHttpFlowData *sessionData_);
- void analyze();
- void printMessage(FILE *output);
- void genEvents();
- void oldClients(); // I'm a legacy support method and should go away eventually
- static const uint32_t MAXOCTETS = 65535;
-
-private:
- // Header normalization. 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_NOREPEAT;
- static const HeaderNormalizer NORMALIZER_DECIMAL;
- 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;
-
- // Code conversion tables are for turning token strings into enums.
- static const StrCode methodList[];
- 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 deriveSourceId();
- void parseRequestLine();
- void parseStatusLine();
- void parseHeaderBlock();
- void parseHeaderLines();
- void deriveHeaderNameId(int index);
- void deriveStatusCodeNum();
- void deriveVersionId();
- void deriveMethodId();
-
- // Convenience methods
- uint32_t findCrlf(const uint8_t* buffer, uint32_t length, bool wrappable);
- void printInterval(FILE *output, const char* name, const uint8_t *text, int32_t length, bool intVals = false);
-
- // The current strategy is to copy the entire raw message headers into this object. Here it is.
- uint32_t length; // Length of the original message headers in octets
- uint8_t rawBuf[MAXOCTETS]; // The original HTTP message header 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;
-
- // Working space and storage for all the derived fields. See scratchPad.h for usage instructions.
- // Allocation size may be complete overkill. Need to revisit this.
- uint32_t derivedBuf[MAXOCTETS/4];
- NHttpFlowData* sessionData;
- ScratchPad scratchPad {derivedBuf, MAXOCTETS/4};
-
- // 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 original message buffer (raw pieces) or the
- // scratchPad (normalized pieces).
- uint64_t infractions;
- bool tcpClose;
- field startLine;
- NHttpEnums::SourceId sourceId;
- field version;
- NHttpEnums::VersionId versionId;
- field method;
- NHttpEnums::MethodId methodId;
- field uri;
- field statusCode;
- int32_t statusCodeNum;
- field reasonPhrase;
- field headers;
- static const int MAXHEADERS = 200; // I'm an arbitrary number. Need to revisit.
- int32_t numHeaders;
- field headerLine[MAXHEADERS];
- field headerName[MAXHEADERS];
- NHttpEnums::HeaderId headerNameId[MAXHEADERS];
- field headerValue[MAXHEADERS];
- field headerValueNorm[NHttpEnums::HEAD__MAXVALUE];
-};
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+++ /dev/null
-/****************************************************************************
- *
-** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
- * Copyright (C) 2003-2013 Sourcefire, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation. You may not use, modify or
- * distribute this program under any other version of the GNU General
- * Public License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- ****************************************************************************/
-
-//
-// @author Tom Peters <thopeter@cisco.com>
-//
-// @brief ScratchPad class declaration
-//
-
-#ifndef NHTTP_SCRATCHPAD_H
-#define NHTTP_SCRATCHPAD_H
-
-
-//-------------------------------------------------------------------------
-// ScratchPad class
-// Memory management for NHttpMsgHeader class
-//-------------------------------------------------------------------------
-
-// Working space and storage for all the derived fields
-// Return value of request is 32-bit aligned and may be freely cast to uint32_t*
-// 1. request the maximum number of bytes you might need
-// 2. use what you need
-// 3. commit() what you actually used if you want to keep it
-// Anything you do not commit will be reused by the next request.
-
-class ScratchPad {
-public:
- ScratchPad(uint32_t *buff, uint32_t length) : buffer(buff), capacity(length*4), used(0) {}; // Careful: length must be number of uint32_ts provided, not octets.
- 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 + (4-(taken%4))%4; }; // round up to multiple of 4 to preserve alignment
-
-private:
- uint32_t *buffer;
- uint32_t capacity;
- uint32_t used;
-};
-
-#endif
-
+++ /dev/null
-/****************************************************************************
- *
-** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
- * Copyright (C) 2003-2013 Sourcefire, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation. You may not use, modify or
- * distribute this program under any other version of the GNU General
- * Public License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- ****************************************************************************/
-
-//
-// @author Tom Peters <thopeter@cisco.com>
-//
-// @brief Converts token strings to enum codes
-//
-
-
-#include <assert.h>
-#include <string.h>
-#include <sys/types.h>
-#include "snort.h"
-#include "nhttp_enum.h"
-#include "nhttp_strtocode.h"
-
-// Need to replace this simple algorithm for better performance
-int32_t strToCode(const uint8_t *text, int32_t textLen, const StrCode table[]) {
- if (textLen <= 0) return NHttpEnums::STAT_PROBLEMATIC;
- for (int32_t k=0; table[k].name != nullptr; k++) {
- if ((textLen == (int) strlen(table[k].name)) && (memcmp(text, table[k].name, textLen) == 0)) {
- return table[k].code;
- }
- }
- return NHttpEnums::STAT_OTHER;
-}
-
+++ /dev/null
-/****************************************************************************
- *
-** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
- * Copyright (C) 2003-2013 Sourcefire, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation. You may not use, modify or
- * distribute this program under any other version of the GNU General
- * Public License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- ****************************************************************************/
-
-//
-// @author Tom Peters <thopeter@cisco.com>
-//
-// @brief Converts protocol constant string to enum
-//
-
-#ifndef NHTTP_STRTOCODE_H
-#define NHTTP_STRTOCODE_H
-
-struct StrCode {
- int32_t code;
- const char *name;
-};
-
-int32_t strToCode(const uint8_t *text, int32_t textLen, const StrCode table[]);
-
-#endif
-
+++ /dev/null
-/****************************************************************************
- *
-** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
- * Copyright (C) 2003-2013 Sourcefire, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation. You may not use, modify or
- * distribute this program under any other version of the GNU General
- * Public License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- ****************************************************************************/
-
-//
-// @author Tom Peters <thopeter@cisco.com>
-//
-// @brief Interface to file test messages
-//
-
-
-#include <assert.h>
-#include <string.h>
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdexcept>
-#include "snort.h"
-#include "flow/flow.h"
-#include "nhttp_enum.h"
-#include "nhttp_scratchpad.h"
-#include "nhttp_strtocode.h"
-#include "nhttp_headnorm.h"
-#include "nhttp_flowdata.h"
-#include "nhttp_msgheader.h"
-#include "nhttp_testinput.h"
-
-NHttpTestInput::NHttpTestInput(const char *fileName) {
- if ((msgFile = fopen(fileName, "r")) == nullptr) throw std::runtime_error("Cannot open test input file");
-}
-
-NHttpTestInput::~NHttpTestInput() {
- fclose(msgFile);
-}
-
-// Read the next message section from the test data file.
-// In the process we may need to skip comments, execute simple commands, and handle simple escape sequences.
-// The best way to understand this function is to read the comments at the top of the file of test cases.
-int32_t NHttpTestInput::ntiGet(uint8_t **buffer, NHttpFlowData* sessionData, int64_t &testNumber) {
- int32_t length = 0;
- *buffer = msgBuf;
- int newChar;
- typedef enum { WAITING, COMMENT, COMMAND, SECTION, ESCAPE0, ESCAPE1, ESCAPE2 } State;
- State state = WAITING;
- bool ending;
- char escapeNum[] = { 0, 0, '\0' };
- int commandLength = 0;
- const int MaxCommand = 100;
- char commandValue[MaxCommand];
-
- sessionData->tcpClose = false;
- sessionData->infractions = 0;
-
- while ((newChar = getc(msgFile)) != EOF) {
- switch (state) {
- case WAITING:
- if (newChar == '#') state = COMMENT;
- else if (newChar == '@') {
- state = COMMAND;
- commandLength = 0;
- }
- else if (newChar == '\\') {
- state = ESCAPE0;
- ending = false;
- }
- else if (newChar != '\n') {
- state = SECTION;
- ending = false;
- msgBuf[length++] = (uint8_t) newChar;
- }
- break;
- case COMMENT:
- if (newChar == '\n') state = WAITING;
- break;
- case COMMAND:
- if (newChar == '\n') {
- state = WAITING;
- if ((commandLength == strlen("request")) && !memcmp(commandValue, "request", strlen("request"))) sessionData->sourceId = NHttpEnums::SRC_CLIENT;
- else if ((commandLength == strlen("response")) && !memcmp(commandValue, "response", strlen("response"))) sessionData->sourceId = NHttpEnums::SRC_SERVER;
- else if ((commandLength == strlen("tcpclose")) && !memcmp(commandValue, "tcpclose", strlen("tcpclose"))) sessionData->tcpClose = true;
- else if ((commandLength == strlen("break")) && !memcmp(commandValue, "break", strlen("break"))) {
- // &&& signifies start of new session so wipe "session data" when we define some. See flowdata.h.
- }
- else if (commandLength > 0) {
- // Look for a test number
- bool isNumber = true;
- for (int k=0; isNumber && (k < commandLength); k++) {
- isNumber = (commandValue[k] >= '0') && (commandValue[k] <= '9');
- }
- if (isNumber) {
- testNumber = 0;
- for (int j=0; j < commandLength; j++) {
- testNumber = testNumber * 10 + (commandValue[j] - '0');
- }
- }
- }
- }
- else {
- if (commandLength < MaxCommand) commandValue[commandLength++] = newChar;
- }
- break;
- case SECTION:
- if (newChar == '\\') {
- state = ESCAPE0;
- }
- else if (newChar == '\n') {
- if (ending) return length; // Found the blank line that ends the section.
- ending = true;
- }
- else {
- ending = false;
- msgBuf[length++] = (uint8_t) newChar;
- }
- break;
- case ESCAPE0:
- if (newChar == 'n') { state = SECTION; ending = false; msgBuf[length++] = '\n'; }
- else if (newChar == 'r') { state = SECTION; ending = false; msgBuf[length++] = '\r'; }
- else if (newChar == 't') { state = SECTION; ending = false; msgBuf[length++] = '\t'; }
- else if (newChar == '#') { state = SECTION; ending = false; msgBuf[length++] = '#'; }
- else if (newChar == '@') { state = SECTION; ending = false; msgBuf[length++] = '@'; }
- else if (newChar == '\\') { state = SECTION; ending = false; msgBuf[length++] = '\\'; }
- else if ((newChar == 'x') || (newChar == 'X')) state = ESCAPE1;
- else { state = SECTION; ending = false; }
- break;
- case ESCAPE1:
- state = ESCAPE2;
- escapeNum[0] = newChar;
- break;
- case ESCAPE2:
- state = SECTION;
- ending = false;
- escapeNum[1] = newChar;
- if (((escapeNum[0] < '0') || (escapeNum[0] > '9')) && ((escapeNum[0] < 'A') || (escapeNum[0] > 'Z')) && ((escapeNum[0] < 'a') || (escapeNum[0] > 'z'))) break;
- if (((escapeNum[1] < '0') || (escapeNum[1] > '9')) && ((escapeNum[1] < 'A') || (escapeNum[1] > 'Z')) && ((escapeNum[1] < 'a') || (escapeNum[1] > 'z'))) break;
- msgBuf[length++] = strtoul(escapeNum, nullptr, 16);
- break;
- }
- // Return because the buffer is full. Not a feature just a safety precaution against bad input.
- if (length >= sizeof(msgBuf)) return length;
- }
- // End-of-file. Return everything we have so far.
- return length;
-}
-
-
+++ /dev/null
-/****************************************************************************
- *
-** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
- * Copyright (C) 2003-2013 Sourcefire, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License Version 2 as
- * published by the Free Software Foundation. You may not use, modify or
- * distribute this program under any other version of the GNU General
- * Public License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- ****************************************************************************/
-
-//
-// @author Tom Peters <thopeter@cisco.com>
-//
-// @brief Converts protocol constant string to enum
-//
-
-#ifndef NHTTP_TESTINPUT_H
-#define NHTTP_TESTINPUT_H
-
-// ntiGet() returns the same static buffer each time.
-// Do not call it again before you are finished with the previous output.
-class NHttpTestInput {
-public:
- NHttpTestInput(const char *fileName);
- ~NHttpTestInput();
- int32_t ntiGet(uint8_t **buffer, NHttpFlowData* sessionData, int64_t &testNumber);
-private:
- FILE *msgFile;
- uint8_t msgBuf[NHttpMsgHeader::MAXOCTETS];
-};
-
-#endif
-
+++ /dev/null
-# A message section is the unit of data passed to the inspector and may by headers, body, a chunk, or trailing headers.
-# Blank lines separate message sections. Extra blank lines don't have any effect.
-# Lines beginning with '@' are control commands.
-# You cannot put comments or control commands in the middle of a message section.
-# If a message section begins with # or @ (presumably a very rare situation) you must escape it: \# or \@
-# Control commands:
-# @request or @response sets the message direction. Applies to subsequent sections until changed.
-# @tcpclose specifies that the section ends with a TCP close. Applies only to the very next section.
-# @<decimal number> sets the test number and hence the test output file name. Applies to subsequent sections until changed. Don't reuse numbers.
-# Commands must be all lower case with no white space.
-# The escape character is \ and it is used only within message sections.
-# \# and \@ are only necessary for the very first character of a message section. \r, \n, \t, \x, \X, and \\ may appear anywhere in a section.
-# \x and \X are identical and signify the beginning of an arbitrary two-digit hexadecimal escape value. Examples: 0x3A, 0X27, 0xeE. Case a-f or A-F
-# does not matter.
-
-@1
-@response
-HTTP/1.1 200 OK\r\n\r\n
-
-@2
-@response
-HTTP/1.0 315 Redirection test with spaces\r\n\r\n
-
-@3
-@request
-MKREDIRECTREF / HTTP/2.0\r\n\r\n
-
-@4
-@request
-BIND 1234567890?abcdef HTTP/3.8\r\n\r\n
-
-@5
-@response
-HTTP/2.0 600 Bogus-status-code\r\n\r\n
-
-@6
-@response
-HTTP/1.9 26 Short?status++co\nde\r\n\r\n
-
-@7
-@response
-HTTP/1.F 502 abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghij
-klmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstu
-vwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890\r\n\r\n
-
-@8
-@request
-GET /test/hi-there.txt HTTP/1.0\r\n\r\n
-
-@9
-@request
-GET /test/hi-there.htm HTTP/1.1\r\nAccept: text/*\r\nAccept-Language: en,fr\r\n\r\n
-
-@10
-@request
-GET /test/trigger/hi-there.htm HTTP/1.1\r\nAccept: text/*\r\nAccept-Language: en,fr\r\n\r\n
-
-@11
-@request
-@tcpclose
-GET /test/trigger/hi-there.htm HTTP/1.1\r\nAccept: text/*\r\nAccept-Language: en,fr\r\n\r\n
-
-@12
-@response
-HTTP/2.0 200 OK\r\nContent-type: \ttext/plain\t\r\nContent-LENGTH: 19\r\n\r\n
-