]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
infractions onject
authorTom Peters <thopeter@cisco.com>
Mon, 22 Dec 2014 21:58:17 +0000 (16:58 -0500)
committerTom Peters <thopeter@cisco.com>
Mon, 22 Dec 2014 21:58:17 +0000 (16:58 -0500)
25 files changed:
src/service_inspectors/nhttp_inspect/CMakeLists.txt
src/service_inspectors/nhttp_inspect/Makefile.am
src/service_inspectors/nhttp_inspect/nhttp_enum.h
src/service_inspectors/nhttp_inspect/nhttp_flow_data.h
src/service_inspectors/nhttp_inspect/nhttp_head_norm.cc
src/service_inspectors/nhttp_inspect/nhttp_head_norm.h
src/service_inspectors/nhttp_inspect/nhttp_infractions.h [new file with mode: 0644]
src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_section.h
src/service_inspectors/nhttp_inspect/nhttp_msg_start.cc
src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc
src/service_inspectors/nhttp_inspect/nhttp_normalizers.cc
src/service_inspectors/nhttp_inspect/nhttp_normalizers.h
src/service_inspectors/nhttp_inspect/nhttp_splitter.cc
src/service_inspectors/nhttp_inspect/nhttp_splitter.h
src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc
src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.h
src/service_inspectors/nhttp_inspect/nhttp_uri.cc
src/service_inspectors/nhttp_inspect/nhttp_uri.h
src/service_inspectors/nhttp_inspect/nhttp_uri_norm.cc
src/service_inspectors/nhttp_inspect/nhttp_uri_norm.h

index af789dbd860bbad58c36ad734da6f71d4a266332..88f8b2d89ecfd0890d6fa35356459cd0f511d785 100644 (file)
@@ -51,6 +51,7 @@ set (FILE_LIST
     nhttp_stream_splitter.h
     nhttp_splitter.cc
     nhttp_splitter.h
+    nhttp_infractions.h
 )
 
 if (STATIC_INSPECTORS)
index dea586e56f0b9cf828b53fa2cb1b8a574224afd5..f066f980fc2d2f3b1e87c1e4b733f5df2d89d6c6 100644 (file)
@@ -28,7 +28,8 @@ nhttp_splitter.cc nhttp_splitter.h \
 nhttp_scratch_pad.h \
 nhttp_enum.h \
 nhttp_test_manager.cc nhttp_test_manager.h \
-nhttp_field.cc nhttp_field.h
+nhttp_field.cc nhttp_field.h \
+nhttp_infractions.h
 
 if STATIC_INSPECTORS
 noinst_LIBRARIES = libnhttp_inspect.a
index 47b381b084f89199f644761cbbc63c5fd2b8aeb0..157fbb093cdd867bff2eb86c6d2fd19265442485 100644 (file)
@@ -83,13 +83,38 @@ typedef enum { HEAD__NOTCOMPUTE=-4, HEAD__INSUFMEMORY=-3, HEAD__PROBLEMATIC=-2,
 
 // All the infractions we might find while parsing and analyzing a message
 typedef enum {
-   INF_TRUNCATED=0x1, INF_HEADTOOLONG=0x2, INF_BADREQLINE=0x4, INF_BADSTATLINE=0x8, INF_TOOMANYHEADERS=0x10,
-   INF_BADHEADER=0x20, INF_BADSTATCODE=0x40, INF_UNKNOWNVERSION=0x80, INF_BADVERSION=0x100, INF_NOSCRATCH=0x200,
-   INF_BADHEADERREPS=0x400, INF_BADHEADERDATA=0x800, INF_BADCHUNKSIZE=0x2000,
-   INF_BADPHRASE=0x4000, INF_BADURI=0x8000, INF_BADPORT=0x10000, INF_URINEEDNORM=0x20000, INF_URIPERCENTNORMAL=0x40000,
-   INF_URIPERCENTASCII=0x80000, INF_URIPERCENTUTF8=0x100000, INF_URIPERCENTUCODE=0x200000, INF_URIPERCENTOTHER=0x400000,
-   INF_URIBADCHAR=0x800000, INF_URI8BITCHAR=0x1000000, INF_URIMULTISLASH=0x2000000, INF_URIBACKSLASH=0x4000000,
-   INF_URISLASHDOT=0x8000000, INF_URISLASHDOTDOT=0x10000000, INF_URIROOTTRAV=0x20000000 } Infraction;
+   INF_TRUNCATED = 0,
+   INF_HEADTOOLONG,
+   INF_BADREQLINE,
+   INF_BADSTATLINE,
+   INF_TOOMANYHEADERS,
+   INF_BADHEADER,
+   INF_BADSTATCODE,
+   INF_UNKNOWNVERSION,
+   INF_BADVERSION,
+   INF_NOSCRATCH,
+   INF_BADHEADERREPS,
+   INF_BADHEADERDATA,
+   INF_FIXIT_L_UNUSED,
+   INF_BADCHUNKSIZE,
+   INF_BADPHRASE,
+   INF_BADURI,
+   INF_BADPORT,
+   INF_URINEEDNORM,
+   INF_URIPERCENTNORMAL,
+   INF_URIPERCENTASCII,
+   INF_URIPERCENTUTF8,
+   INF_URIPERCENTUCODE,
+   INF_URIPERCENTOTHER,
+   INF_URIBADCHAR,
+   INF_URI8BITCHAR,
+   INF_URIMULTISLASH,
+   INF_URIBACKSLASH,
+   INF_URISLASHDOT,
+   INF_URISLASHDOTDOT,
+   INF_URIROOTTRAV,
+   INF_TOOMUCHLEADINGWS,
+} Infraction;
 
 // Formats for output from a header normalization function
 typedef enum { NORM_NULL, NORM_FIELD, NORM_INT64, NORM_ENUM64, NORM_ENUM64LIST } NormFormat;
@@ -102,13 +127,13 @@ typedef enum { TRANSCODE__OTHER=1, TRANSCODE_CHUNKED, TRANSCODE_IDENTITY, TRANSC
    TRANSCODE_DEFLATE } Transcoding;
 
 typedef enum 
-{
+{   // FIXIT-L limit 63 before code changes required
     EVENT_ASCII = 1,
     EVENT_DOUBLE_DECODE, 
     EVENT_U_ENCODE, 
     EVENT_BARE_BYTE, 
     EVENT_OBSOLETE_1,
-    EVENT_UTF_8, 
+    EVENT_UTF_8,
     EVENT_IIS_UNICODE, 
     EVENT_MULTI_SLASH, 
     EVENT_IIS_BACKSLASH, 
index 8c53e054fca5b852c143f720f2da7bd591976996..5b91f9ef70137cb6368fb34aa4aa345eec7d9e33 100644 (file)
@@ -25,6 +25,7 @@
 #include "stream/stream_api.h"
 
 #include "nhttp_splitter.h"
+#include "nhttp_infractions.h"
 
 class NHttpTransaction;
 
@@ -63,14 +64,14 @@ private:
     int32_t chunk_buffer_length[2] = { 0, 0 };
     bool chunk_buffer_owned[2] = { true, true }; // never actually false and not checked, just here to simplify code
     bool zero_chunk[2] = { false, false };
-    uint64_t chunk_infractions[2] = { 0, 0 };
+    NHttpInfractions chunk_infractions[2];
 
     // StreamSplitter => Inspector (facts about the most recent message section)
     // 0 element refers to client request, 1 element refers to server response
     NHttpEnums::SectionType section_type[2] = { NHttpEnums::SEC__NOTCOMPUTE, NHttpEnums::SEC__NOTCOMPUTE };
     uint32_t num_excess[2] = { 0, 0 };
     bool tcp_close[2] = { false, false };
-    uint64_t infractions[2] = { 0, 0 };
+    NHttpInfractions infractions[2];
     uint32_t unused_octets_visible[2] = { 0, 0 };
     uint32_t header_octets_visible[2] = { 0, 0 };
 
index 4bf87d1a1e64cea4101e468dfd37778710550fb4..f8eaab15ac364b07d1c305ada9087cafbc7290e8 100644 (file)
@@ -54,8 +54,9 @@ int32_t HeaderNormalizer::derive_header_content(const uint8_t *value, int32_t le
 }
 
 // This method normalizes the header field value for headId.
-int32_t HeaderNormalizer::normalize(const HeaderId head_id, const int count, ScratchPad &scratch_pad, uint64_t &infractions,
-        const HeaderId header_name_id[], const Field header_value[], const int32_t num_headers, Field &result_field) const {
+int32_t HeaderNormalizer::normalize(const HeaderId head_id, const int count, ScratchPad &scratch_pad,
+        NHttpInfractions &infractions, const HeaderId header_name_id[], const Field header_value[],
+        const int32_t num_headers, Field &result_field) const {
     if (result_field.length != STAT_NOTCOMPUTE) {
         return result_field.length;
     }
index 6ccb1625be855c9a2ed481492e5a3f79f15c356f..708c1b080dde0505a6bdb0126e2fd4312fa6269f 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "nhttp_scratch_pad.h"
 #include "nhttp_field.h"
+#include "nhttp_infractions.h"
 
 //-------------------------------------------------------------------------
 // HeaderNormalizer class
@@ -39,19 +40,19 @@ public:
     constexpr HeaderNormalizer(
        NHttpEnums::NormFormat _format,
        bool _concatenate_repeats,
-       int32_t (*f1)(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*),
+       int32_t (*f1)(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, const void*),
        const void *f1_arg,
-       int32_t (*f2)(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*),
+       int32_t (*f2)(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, const void*),
        const void *f2_arg,
-       int32_t (*f3)(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*),
+       int32_t (*f3)(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, const void*),
        const void *f3_arg)
        : format(_format), concatenate_repeats(_concatenate_repeats), normalizer { f1, f2, f3 },
          norm_arg { f1_arg, f2_arg, f3_arg },
          num_normalizers((f1 != nullptr) + (f1 != nullptr)*(f2 != nullptr) + (f1 != nullptr)*(f2 != nullptr)*(f3 != nullptr))
        {};
-    int32_t normalize(const NHttpEnums::HeaderId head_id, const int count, ScratchPad &scratch_pad, uint64_t &infractions,
-       const NHttpEnums::HeaderId header_name_id[], const Field header_value[], const int32_t num_headers,
-       Field &result_field) const;
+    int32_t normalize(const NHttpEnums::HeaderId head_id, const int count, ScratchPad &scratch_pad,
+       NHttpInfractions &infractions, const NHttpEnums::HeaderId header_name_id[], const Field header_value[],
+       const int32_t num_headers, Field &result_field) const;
     NHttpEnums::NormFormat get_format() const { return format; };
 
 private:
@@ -59,7 +60,7 @@ private:
 
     const NHttpEnums::NormFormat format;
     const bool concatenate_repeats;
-    int32_t (* const normalizer[3])(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*);
+    int32_t (* const normalizer[3])(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, const void*);
     const void * norm_arg[3];
     const int num_normalizers;
 };
diff --git a/src/service_inspectors/nhttp_inspect/nhttp_infractions.h b/src/service_inspectors/nhttp_inspect/nhttp_infractions.h
new file mode 100644 (file)
index 0000000..9722b26
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License Version 2 as
+** published by the Free Software Foundation.  You may not use, modify or
+** distribute this program under any other version of the GNU General
+** Public License.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+*/
+// nhttp_scratch_pad.h author Tom Peters <thopeter@cisco.com>
+
+#ifndef NHTTP_INFRACTIONS_H
+#define NHTTP_INFRACTIONS_H
+
+#include <assert.h>
+
+//-------------------------------------------------------------------------
+// Infractions class
+//-------------------------------------------------------------------------
+
+class NHttpInfractions {
+public:
+    NHttpInfractions() {};
+    NHttpInfractions(int inf) : infractions(1 << inf) { assert((inf >= 0) && (inf < 64)); };
+    bool found_new(int inf) {
+       assert((inf >= 0) && (inf < 64));
+       const bool ret_val = ((1 << inf) & infractions & ~previous_infractions) != 0;
+       previous_infractions |= (1 << inf) & infractions;
+       return ret_val; };
+    bool none_found() const { return infractions == 0; };
+    NHttpInfractions& operator+=(const NHttpInfractions& rhs) { infractions |= rhs.infractions;
+       previous_infractions |= rhs.previous_infractions; return *this; };
+    friend NHttpInfractions operator+(NHttpInfractions lhs, const NHttpInfractions& rhs) { lhs += rhs; return lhs; };
+    friend bool operator&&(const NHttpInfractions& lhs, const NHttpInfractions& rhs) {
+       return (lhs.infractions & rhs.infractions) != 0; };
+
+    // The following two methods are for convenience of debug and test output only!
+    // The 64-bit implementation will not be big enough forever and this interface cannot be all over the code.
+    uint64_t get_raw() const { return infractions; };
+    uint64_t get_raw_prev() const { return previous_infractions; };
+private:
+    NHttpInfractions(uint64_t infractions_, uint64_t previous_infractions_) : infractions(infractions_),
+       previous_infractions(previous_infractions_) {};
+
+    uint64_t infractions = 0;
+    uint64_t previous_infractions = 0;
+};
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
index 5f36124218e936adbf8bd08342e784cf680f8a4e..d17b18f086c363679b4e33c98a313837f64d0e06 100644 (file)
@@ -43,7 +43,7 @@ void NHttpMsgBody::analyze() {
     data.start = msg_text.start;
     data.length = msg_text.length;
 
-    if (tcp_close && (body_octets < data_length)) infractions |= INF_TRUNCATED;
+    if (tcp_close && (body_octets < data_length)) infractions += INF_TRUNCATED;
 }
 
 void NHttpMsgBody::gen_events() {
index fc91b95346457b501263578467ce507c83f47694..9b29c6a323597c4ee6bfb75c4f12e6add68d284e 100644 (file)
@@ -55,7 +55,7 @@ void NHttpMsgHeadShared::parse_header_block() {
         }
     }
     if (bytes_used < msg_text.length) {
-        infractions |= INF_TOOMANYHEADERS;
+        infractions += INF_TOOMANYHEADERS;
     }
 }
 
@@ -99,7 +99,7 @@ void NHttpMsgHeadShared::parse_header_lines() {
             header_value[k].length = header_line[k].length - colon - 1;
         }
         else {
-            infractions |= INF_BADHEADER;
+            infractions += INF_BADHEADER;
         }
     }
 }
@@ -108,7 +108,7 @@ void NHttpMsgHeadShared::derive_header_name_id(int index) {
     // Normalize header field name to lower case for matching purposes
     uint8_t *lower_name;
     if ((lower_name = scratch_pad.request(header_name[index].length)) == nullptr) {
-        infractions |= INF_NOSCRATCH;
+        infractions += INF_NOSCRATCH;
         header_name_id[index] = HEAD__INSUFMEMORY;
         return;
     }
@@ -123,7 +123,7 @@ const Field& NHttpMsgHeadShared::get_header_value_norm(NHttpEnums::HeaderId head
 }
 
 void NHttpMsgHeadShared::gen_events() {
-    if (infractions & INF_TOOMANYHEADERS) create_event(EVENT_MAX_HEADERS);
+    if (infractions && INF_TOOMANYHEADERS) create_event(EVENT_MAX_HEADERS);
 }
 
 void NHttpMsgHeadShared::print_headers(FILE *output) {
index eb937e32f11e1eba2c1d02376657f63ec2f49d87..786849d5f095b54106d947065ba66e97617bf594 100644 (file)
@@ -60,7 +60,7 @@ void NHttpMsgHeader::update_flow() {
         session_data->type_expected[source_id] = SEC_CLOSED;
         session_data->half_reset(source_id);
     }
-    else if (infractions & disaster_mask) {
+    else if (infractions && disaster_mask) {
         session_data->type_expected[source_id] = SEC_ABORT;
         session_data->half_reset(source_id);
     }
index 31bd71b8b0f4d8440b0d8f1358fb46b5f9ea9899..e4e8c707e39332abae2edc578ed64db8c1893c19 100644 (file)
@@ -48,7 +48,7 @@ void NHttpMsgRequest::parse_start_line() {
     // <method><SP><URI><SP>HTTP/X.Y
     if (start_line.start[start_line.length-9] != ' ') {
         // space before "HTTP" missing or in wrong place
-        infractions |= INF_BADREQLINE;
+        infractions += INF_BADREQLINE;
         return;
     }
 
@@ -58,7 +58,7 @@ void NHttpMsgRequest::parse_start_line() {
     }
     if (space >= start_line.length-9) {
         // leading space or no space
-        infractions |= INF_BADREQLINE;
+        infractions += INF_BADREQLINE;
         return;
     }
 
@@ -97,18 +97,18 @@ void NHttpMsgRequest::gen_events() {
     if (method_id == METH__OTHER) create_event(EVENT_UNKNOWN_METHOD);
 
     // URI character encoding events
-    if (uri && (uri->get_uri_infractions() & INF_URIPERCENTASCII)) create_event(EVENT_ASCII);
-    if (uri && (uri->get_uri_infractions() & INF_URIPERCENTUCODE)) create_event(EVENT_U_ENCODE);
-    if (uri && (uri->get_uri_infractions() & INF_URI8BITCHAR)) create_event(EVENT_BARE_BYTE);
-    if (uri && (uri->get_uri_infractions() & INF_URIPERCENTUTF8)) create_event(EVENT_UTF_8);
-    if (uri && (uri->get_uri_infractions() & INF_URIBADCHAR)) create_event(EVENT_NON_RFC_CHAR);
+    if (uri && (uri->get_uri_infractions() && INF_URIPERCENTASCII)) create_event(EVENT_ASCII);
+    if (uri && (uri->get_uri_infractions() && INF_URIPERCENTUCODE)) create_event(EVENT_U_ENCODE);
+    if (uri && (uri->get_uri_infractions() && INF_URI8BITCHAR)) create_event(EVENT_BARE_BYTE);
+    if (uri && (uri->get_uri_infractions() && INF_URIPERCENTUTF8)) create_event(EVENT_UTF_8);
+    if (uri && (uri->get_uri_infractions() && INF_URIBADCHAR)) create_event(EVENT_NON_RFC_CHAR);
 
     // URI path events
-    if (uri && (uri->get_path_infractions() & INF_URIMULTISLASH)) create_event(EVENT_MULTI_SLASH);
-    if (uri && (uri->get_path_infractions() & INF_URIBACKSLASH)) create_event(EVENT_IIS_BACKSLASH);
-    if (uri && (uri->get_path_infractions() & INF_URISLASHDOT)) create_event(EVENT_SELF_DIR_TRAV);
-    if (uri && (uri->get_path_infractions() & INF_URISLASHDOTDOT)) create_event(EVENT_DIR_TRAV);
-    if (uri && (uri->get_path_infractions() & INF_URIROOTTRAV)) create_event(EVENT_WEBROOT_DIR);
+    if (uri && (uri->get_path_infractions() && INF_URIMULTISLASH)) create_event(EVENT_MULTI_SLASH);
+    if (uri && (uri->get_path_infractions() && INF_URIBACKSLASH)) create_event(EVENT_IIS_BACKSLASH);
+    if (uri && (uri->get_path_infractions() && INF_URISLASHDOT)) create_event(EVENT_SELF_DIR_TRAV);
+    if (uri && (uri->get_path_infractions() && INF_URISLASHDOTDOT)) create_event(EVENT_DIR_TRAV);
+    if (uri && (uri->get_path_infractions() && INF_URIROOTTRAV)) create_event(EVENT_WEBROOT_DIR);
 
 }
 
@@ -135,8 +135,10 @@ void NHttpMsgRequest::print_section(FILE *output) {
         uri->get_norm_fragment().print(output, "Normalized Fragment");
         fprintf(output, "URI infractions: overall %" PRIx64 ", format %" PRIx64 ", scheme %" PRIx64 ", host %" PRIx64 ", port %" PRIx64 ", path %"
            PRIx64 ", query %" PRIx64 ", fragment %" PRIx64 "\n",
-           uri->get_uri_infractions(), uri->get_format_infractions(), uri->get_scheme_infractions(), uri->get_host_infractions(),
-           uri->get_port_infractions(), uri->get_path_infractions(), uri->get_query_infractions(), uri->get_fragment_infractions());
+           uri->get_uri_infractions().get_raw(), uri->get_format_infractions().get_raw(),
+           uri->get_scheme_infractions().get_raw(), uri->get_host_infractions().get_raw(),
+           uri->get_port_infractions().get_raw(), uri->get_path_infractions().get_raw(),
+           uri->get_query_infractions().get_raw(), uri->get_fragment_infractions().get_raw());
     }
     NHttpMsgSection::print_message_wrapup(output);
  }
@@ -149,7 +151,7 @@ void NHttpMsgRequest::update_flow() {
         session_data->type_expected[source_id] = SEC_CLOSED;
         session_data->half_reset(source_id);
     }
-    else if (infractions & disaster_mask) {
+    else if (infractions && disaster_mask) {
         session_data->type_expected[source_id] = SEC_ABORT;
         session_data->half_reset(source_id);
     }
index 0596f3c4b318bf295e22e109e532ff71f1403fdd..d61ace4de2585aaa228b6ab1e6f52df3aaa78f34 100644 (file)
@@ -55,8 +55,8 @@ void NHttpMsgSection::print_message_title(FILE *output, const char *title) const
 }
 
 void NHttpMsgSection::print_message_wrapup(FILE *output) const {
-    fprintf(output, "Infractions: %" PRIx64 ", Events: %" PRIx64 ", TCP Close: %s\n", infractions, events_generated,
-       tcp_close ? "True" : "False");
+    fprintf(output, "Infractions: %" PRIx64 ", Events: %" PRIx64 ", TCP Close: %s\n", infractions.get_raw(),
+       events_generated, tcp_close ? "True" : "False");
     fprintf(output, "Interface to old clients. http_mask = %x.\n", http_mask);
     for (int i=0; i < HTTP_BUFFER_MAX; i++) {
         if ((1 << i) & http_mask) Field(http_buffer[i].length, http_buffer[i].buf).print(output, http_buffer_name[i]);
index 28f0d17a0ac94c46362ad7e44bea7b6306779d1a..4b3579276a73454999e3aa7a97b990433b1a7e02 100644 (file)
@@ -25,6 +25,7 @@
 #include "nhttp_field.h"
 #include "nhttp_flow_data.h"
 #include "nhttp_transaction.h"
+#include "nhttp_infractions.h"
 
 //-------------------------------------------------------------------------
 // NHttpMsgSection class
@@ -66,7 +67,7 @@ protected:
     const bool tcp_close;
     ScratchPad scratch_pad;
 
-    uint64_t infractions;
+    NHttpInfractions infractions;
     uint64_t events_generated = 0;
     NHttpEnums::VersionId version_id;
     NHttpEnums::MethodId method_id;
index 19862226f38655c9c5b11a4d9a52bb495dac6d43..70da47c0cba3c7e94172acd85ab750b05091344b 100644 (file)
@@ -43,13 +43,13 @@ void NHttpMsgStart::derive_version_id() {
     }
     if (version.length != 8) {
         version_id = VERS__PROBLEMATIC;
-        infractions |= INF_BADVERSION;
+        infractions += INF_BADVERSION;
         return;
     }
 
     if (memcmp(version.start, "HTTP/", 5) || (version.start[6] != '.')) {
         version_id = VERS__PROBLEMATIC;
-        infractions |= INF_BADVERSION;
+        infractions += INF_BADVERSION;
     }
     else if ((version.start[5] == '1') && (version.start[7] == '1')) {
         version_id = VERS_1_1;
@@ -63,11 +63,11 @@ void NHttpMsgStart::derive_version_id() {
     else if ((version.start[5] >= '0') && (version.start[5] <= '9') &&
              (version.start[7] >= '0') && (version.start[7] <= '9')) {
         version_id = VERS__OTHER;
-        infractions |= INF_UNKNOWNVERSION;
+        infractions += INF_UNKNOWNVERSION;
     }
     else {
         version_id = VERS__PROBLEMATIC;
-        infractions |= INF_BADVERSION;
+        infractions += INF_BADVERSION;
     }
 }
 
index add1f18ce3163daa74ada0c1538370f38c9506ce..de4c2d37267aa275118907353d2fa1e333021716 100644 (file)
@@ -51,7 +51,7 @@ void NHttpMsgStatus::parse_start_line() {
     // Eventually we may need to cater to certain format errors, but for now exact match or treat as error.
     // HTTP/X.Y<SP>###<SP><text>
     if ((start_line.length < 13) || (start_line.start[8] != ' ') || (start_line.start[12] != ' ')) {
-        infractions |= INF_BADSTATLINE;
+        infractions += INF_BADSTATLINE;
         return;
     }
     version.start = start_line.start;
@@ -63,7 +63,7 @@ void NHttpMsgStatus::parse_start_line() {
     for (int32_t k = 0; k < reason_phrase.length; k++) {
         if ((reason_phrase.start[k] <= 31) || (reason_phrase.start[k] >= 127)) {
             // Illegal character in reason phrase
-            infractions |= INF_BADPHRASE;
+            infractions += INF_BADPHRASE;
             break;
         }
     }
@@ -82,13 +82,13 @@ void NHttpMsgStatus::derive_status_code_num() {
 
     if ((status_code.start[0] < '0') || (status_code.start[0] > '9') || (status_code.start[1] < '0') || (status_code.start[1] > '9') ||
        (status_code.start[2] < '0') || (status_code.start[2] > '9')) {
-        infractions |= INF_BADSTATCODE;
+        infractions += INF_BADSTATCODE;
         status_code_num = STAT_PROBLEMATIC;
         return;
     }
     status_code_num = (status_code.start[0] - '0') * 100 + (status_code.start[1] - '0') * 10 + (status_code.start[2] - '0');
     if ((status_code_num < 100) || (status_code_num > 599)) {
-        infractions |= INF_BADSTATCODE;
+        infractions += INF_BADSTATCODE;
     }
 }
 
@@ -110,7 +110,7 @@ void NHttpMsgStatus::update_flow() {
         session_data->type_expected[source_id] = SEC_CLOSED;
         session_data->half_reset(source_id);
     }
-    else if (infractions & disaster_mask) {
+    else if (infractions && disaster_mask) {
         session_data->type_expected[source_id] = SEC_ABORT;
         session_data->half_reset(source_id);
     }
index b3524bd139710c23bce18cf47a2f91c4720831de..7149aff716478486c54658dcc3cb6ad765d3d772 100644 (file)
@@ -30,7 +30,7 @@ using namespace NHttpEnums;
 // 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 norm_decimal_integer(const uint8_t* in_buf, int32_t in_length, uint8_t* out_buf, uint64_t& infractions, const void *) {
+int32_t norm_decimal_integer(const uint8_t* in_buf, int32_t in_length, uint8_t* out_buf, NHttpInfractions& infractions, const void *) {
     // Limited to 18 decimal digits, not including leading zeros, to fit comfortably into int64_t
     int64_t total = 0;
     int non_leading_zeros = 0;
@@ -38,11 +38,11 @@ int32_t norm_decimal_integer(const uint8_t* in_buf, int32_t in_length, uint8_t*
         int value = in_buf[k] - '0';
         if (non_leading_zeros || (value != 0)) non_leading_zeros++;
         if (non_leading_zeros > 18) {
-            infractions |= INF_BADHEADERDATA;
+            infractions += INF_BADHEADERDATA;
             return STAT_PROBLEMATIC;
         }
         if ((value < 0) || (value > 9)) {
-            infractions |= INF_BADHEADERDATA;
+            infractions += INF_BADHEADERDATA;
             return STAT_PROBLEMATIC;
         }
         total = total*10 + value;
@@ -52,7 +52,7 @@ int32_t norm_decimal_integer(const uint8_t* in_buf, int32_t in_length, uint8_t*
 }
 
 
-int32_t norm_to_lower(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t&, const void *) {
+int32_t norm_to_lower(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, NHttpInfractions&, const void *) {
     for (int32_t k=0; k < in_length; k++) {
         out_buf[k] = ((in_buf[k] < 'A') || (in_buf[k] > 'Z')) ? in_buf[k] : in_buf[k] - ('A' - 'a');
     }
@@ -60,12 +60,14 @@ int32_t norm_to_lower(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf
 }
 
 
-int32_t norm_str_code(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t&, const void *table) {
+int32_t norm_str_code(const uint8_t* in_buf, int32_t in_length, uint8_t* out_buf, NHttpInfractions&,
+   const void* table) {
     ((int64_t*)out_buf)[0] = str_to_code(in_buf, in_length, (const StrCode*)table);
     return sizeof(int64_t);
 }
 
-int32_t norm_seq_str_code(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t&, const void *table) {
+int32_t norm_seq_str_code(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, NHttpInfractions&,
+   const void *table) {
     int32_t num_codes = 0;
     const uint8_t* start = in_buf;
     while (true) {
@@ -80,7 +82,7 @@ int32_t norm_seq_str_code(const uint8_t* in_buf, int32_t in_length, uint8_t *out
 }
 
 // Remove all space and tab characters (known as LWS or linear white space in the RFC)
-int32_t norm_remove_lws(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t&, const void *) {
+int32_t norm_remove_lws(const uint8_t* in_buf, int32_t in_length, uint8_t* out_buf, NHttpInfractions&, const void*) {
     int32_t length = 0;
     for (int32_t k = 0; k < in_length; k++) {
         if ((in_buf[k] != ' ') && (in_buf[k] != '\t')) out_buf[length++] = in_buf[k];
index dc7e97b7dfd8a7cde62b9410085ed903f79e3515..f8b2f782920ddb498583685534786b50770696c2 100644 (file)
 #ifndef NHTTP_NORMALIZERS_H
 #define NHTTP_NORMALIZERS_H
 
-int32_t norm_decimal_integer(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* not_used);
-int32_t norm_to_lower(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* not_used);
-int32_t norm_str_code(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*);
-int32_t norm_seq_str_code(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void*);
-int32_t norm_remove_lws(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* not_used);
+#include "nhttp_infractions.h"
+
+int32_t norm_decimal_integer(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, const void* not_used);
+int32_t norm_to_lower(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, const void* not_used);
+int32_t norm_str_code(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, const void*);
+int32_t norm_seq_str_code(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, const void*);
+int32_t norm_remove_lws(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, const void* not_used);
 
 #endif
 
index 0612f127680ac176070005a65bdea6eca5e06a89..8098b86972bb71dac3a2fc6ab7e332d1fbf461c2 100644 (file)
@@ -32,7 +32,8 @@ ScanResult NHttpStartSplitter::split(const uint8_t* buffer, uint32_t length) {
                     num_crlf++;
                     continue;
                 }
-                else { // FIXIT-M there needs to be an event for this
+                else {
+                    infractions += INF_TOOMUCHLEADINGWS;
                     return SCAN_ABORT;
                 }
             }
index 4e2a8b74b75f809c32efe8488f347f50df013416..4bc8ef9cbb8354755f272649fd11c2cee50ccac1 100644 (file)
@@ -24,6 +24,7 @@
 #include <assert.h>
 
 #include "nhttp_enum.h"
+#include "nhttp_infractions.h"
 
 //-------------------------------------------------------------------------
 // NHttpSplitter class
@@ -39,11 +40,12 @@ public:
     virtual uint32_t get_num_excess() const { return 0; };
     virtual bool get_zero_chunk() const { return false; };
     virtual bool partial_ok() const { return true; };
-
+    NHttpInfractions get_infractions() const { return infractions; }
 protected:
     uint32_t octets_seen = 0; // number of octets processed by previous split() calls that returned NOTFOUND
     uint32_t num_crlf = 0;
     uint32_t num_flush = 0;
+    NHttpInfractions infractions;
 };
 
 class NHttpStartSplitter : public NHttpSplitter {
index b661bafa155ca375bb8a39438010bf2efe81087f..97009c28b9e63584a976ee7bdaa960e0d92b38b1 100644 (file)
@@ -32,7 +32,7 @@ using namespace NHttpEnums;
 
 // Convenience function. All the housekeeping that must be done before we can return FLUSH to stream.
 void NHttpStreamSplitter::prepare_flush(NHttpFlowData* session_data, uint32_t* flush_offset, SectionType section_type,
-      bool tcp_close, uint64_t infractions, uint32_t num_octets, uint32_t length, uint32_t num_excess,
+      bool tcp_close, const NHttpInfractions& infractions, uint32_t num_octets, uint32_t length, uint32_t num_excess,
       bool zero_chunk) {
     session_data->section_type[source_id] = section_type;
     session_data->num_excess[source_id] = num_excess;
@@ -156,14 +156,15 @@ StreamSplitter::Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* dat
             }
             if (tcp_close) {
                 if (splitter->partial_ok()) {
-                    prepare_flush(session_data, flush_offset, type, true, INF_TRUNCATED, length, length,
-                       splitter->get_num_excess(), splitter->get_zero_chunk());
+                    prepare_flush(session_data, flush_offset, type, true, splitter->get_infractions() += INF_TRUNCATED,
+                       length, length, splitter->get_num_excess(), splitter->get_zero_chunk());
                     delete splitter;
                     splitter = nullptr;
                     return StreamSplitter::FLUSH;
                 }
                 else {
-                    prepare_flush(session_data, flush_offset, SEC_DISCARD, true, 0, length, length, 0, false);
+                    prepare_flush(session_data, flush_offset, SEC_DISCARD, true, splitter->get_infractions(), length,
+                       length, 0, false);
                     delete splitter;
                     splitter = nullptr;
                     return StreamSplitter::FLUSH;
@@ -185,8 +186,8 @@ StreamSplitter::Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* dat
           case SCAN_DISCARD:
           case SCAN_DISCARD_CONTINUE: {
             const uint32_t flush_octets = splitter->get_num_flush();
-            prepare_flush(session_data, flush_offset, SEC_DISCARD, tcp_close && (flush_octets >= length), 0,
-               flush_octets, length, 0, false);
+            prepare_flush(session_data, flush_offset, SEC_DISCARD, tcp_close && (flush_octets >= length),
+               splitter->get_infractions(), flush_octets, length, 0, false);
             if (split_result == SCAN_DISCARD) {
                 delete splitter;
                 splitter = nullptr;
@@ -195,8 +196,9 @@ StreamSplitter::Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* dat
           }
           case SCAN_FOUND: {
             const uint32_t flush_octets = splitter->get_num_flush();
-            prepare_flush(session_data, flush_offset, type, tcp_close && (flush_octets == length), 0,
-               flush_octets, length, splitter->get_num_excess(), splitter->get_zero_chunk());
+            prepare_flush(session_data, flush_offset, type, tcp_close && (flush_octets == length),
+               splitter->get_infractions(), flush_octets, length, splitter->get_num_excess(),
+               splitter->get_zero_chunk());
             delete splitter;
             splitter = nullptr;
             if ((type == SEC_REQUEST) || (type == SEC_STATUS)) {
@@ -212,7 +214,7 @@ StreamSplitter::Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* dat
       }
       case SEC_BODY: {
         prepare_flush(session_data, flush_offset, SEC_BODY,
-           tcp_close && (length <= session_data->data_length[source_id]), 0,
+           tcp_close && (length <= session_data->data_length[source_id]), NHttpInfractions(),
            session_data->data_length[source_id], length, 0, false);
         return StreamSplitter::FLUSH;
       }
@@ -312,7 +314,7 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned total,
             // zero_chunk == true) flushes accumulated chunks.
 
             // infractions for each aggregated small chunk are accumulated here and then restored before processing
-            session_data->chunk_infractions[source_id] |= session_data->infractions[source_id];
+            session_data->chunk_infractions[source_id] += session_data->infractions[source_id];
 
             // FIXIT-M this implementation of the zero-length chunk is temporary until stream can support a zero-
             // octet flush.
@@ -333,7 +335,7 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned total,
             }
             paf_max = DATABLOCKSIZE;
             session_data->infractions[source_id] = session_data->chunk_infractions[source_id];
-            session_data->chunk_infractions[source_id] = 0;
+            session_data->chunk_infractions[source_id] = NHttpInfractions();
             send_to_detection = my_inspector->process(chunk_buffer, total_chunk_len, flow, source_id, true);
             if (session_data->zero_chunk[source_id]) {
                 // zero-length chunk is not visible to inspector. Transition to trailer must be handled here.
index 6c6f63b2856666c225c02634f5e8162fb3562b01..aa757b6fce34e1bbfcb24709691447caa60313b3 100644 (file)
@@ -40,7 +40,7 @@ public:
     unsigned max() override { return NHttpTestManager::use_test_input() ? NHttpEnums::DATABLOCKSIZE : paf_max; };
 private:
     void prepare_flush(NHttpFlowData* session_data, uint32_t* flush_offset, NHttpEnums::SectionType section_type,
-       bool tcp_close, uint64_t infractions, uint32_t num_octets, uint32_t length, uint32_t num_excess,
+       bool tcp_close, const NHttpInfractions& infractions, uint32_t num_octets, uint32_t length, uint32_t num_excess,
        bool zero_chunk);
     NHttpSplitter* get_splitter(NHttpEnums::SectionType type) const;
 
index 7c1d44867d4b59a9906bbe982fddcf0de1b80728..ac265977f047c52c1396db41a10078f12c546b2e 100644 (file)
@@ -84,7 +84,7 @@ void NHttpUri::parse_uri() {
             abs_path.start = uri.start + k;
         }
         else {
-            format_infractions |= INF_BADURI;
+            format_infractions += INF_BADURI;
             uri_type = URI__PROBLEMATIC;
             scheme.length = STAT_PROBLEMATIC;
             authority.length = STAT_PROBLEMATIC;
@@ -105,7 +105,7 @@ SchemeId NHttpUri::get_scheme_id() {
     // Normalize scheme name to lower case for matching purposes
     uint8_t *lower_scheme;
     if ((lower_scheme = scratch_pad.request(scheme.length)) == nullptr) {
-        scheme_infractions |= INF_NOSCRATCH;
+        scheme_infractions += INF_NOSCRATCH;
         scheme_id = SCH__INSUFMEMORY;
         return scheme_id;
     }
@@ -175,7 +175,7 @@ int32_t NHttpUri::get_port_value() {
         port_value = port_value * 10 + (port.start[k] - '0');
         if ((port.start[k] < '0') || (port.start[k] > '9') || (port_value > 65535))
         {
-            port_infractions |= INF_BADPORT;
+            port_infractions += INF_BADPORT;
             port_value = STAT_PROBLEMATIC;
             break;
         }
@@ -248,7 +248,8 @@ const Field& NHttpUri::get_norm_legacy() {
     }
 
     // We can reuse the raw URI for the normalized URI unless at least one part of the URI has been normalized
-    if ((host_infractions == 0) && (path_infractions == 0) && (query_infractions == 0) && (fragment_infractions == 0)) {
+    if ((host_infractions.none_found()) && (path_infractions.none_found()) && (query_infractions.none_found()) &&
+       (fragment_infractions.none_found())) {
         legacy_norm.start = uri.start;
         legacy_norm.length = uri.length;
         return legacy_norm;
index 7e0221ca817651fbc83d0ceaaca637e8fc11f4c1..7c7f660b6f8695c552e87cf10718bc51f8b7ebca 100644 (file)
@@ -25,6 +25,7 @@
 #include "nhttp_str_to_code.h"
 #include "nhttp_uri_norm.h"
 #include "nhttp_field.h"
+#include "nhttp_infractions.h"
 
 //-------------------------------------------------------------------------
 // NHttpUri class
@@ -45,15 +46,15 @@ public:
     const Field& get_query() { parse_abs_path(); return query; };
     const Field& get_fragment() { parse_abs_path(); return fragment; };
 
-    uint64_t get_format_infractions() { parse_uri(); return format_infractions; };
-    uint64_t get_scheme_infractions() { get_scheme_id(); return scheme_infractions; };
-    uint64_t get_host_infractions() { get_norm_host(); return host_infractions; };
-    uint64_t get_port_infractions() { get_port_value(); return port_infractions; };
-    uint64_t get_path_infractions() { get_norm_path(); return path_infractions; };
-    uint64_t get_query_infractions() { get_norm_query(); return query_infractions; };
-    uint64_t get_fragment_infractions() { get_norm_fragment(); return fragment_infractions; };
-    uint64_t get_uri_infractions() { return get_format_infractions() | get_scheme_infractions() | get_host_infractions() |
-       get_port_infractions() | get_path_infractions() | get_query_infractions() | get_fragment_infractions(); };
+    NHttpInfractions get_format_infractions() { parse_uri(); return format_infractions; };
+    NHttpInfractions get_scheme_infractions() { get_scheme_id(); return scheme_infractions; };
+    NHttpInfractions get_host_infractions() { get_norm_host(); return host_infractions; };
+    NHttpInfractions get_port_infractions() { get_port_value(); return port_infractions; };
+    NHttpInfractions get_path_infractions() { get_norm_path(); return path_infractions; };
+    NHttpInfractions get_query_infractions() { get_norm_query(); return query_infractions; };
+    NHttpInfractions get_fragment_infractions() { get_norm_fragment(); return fragment_infractions; };
+    NHttpInfractions get_uri_infractions() { return get_format_infractions() + get_scheme_infractions() + get_host_infractions() +
+       get_port_infractions() + get_path_infractions() + get_query_infractions() + get_fragment_infractions(); };
 
     NHttpEnums::SchemeId get_scheme_id();
     const Field& get_norm_host();
@@ -78,13 +79,13 @@ private:
     Field query;
     Field fragment;
 
-    uint64_t format_infractions = 0;
-    uint64_t scheme_infractions = 0;
-    uint64_t host_infractions = 0;
-    uint64_t port_infractions = 0;
-    uint64_t path_infractions = 0;
-    uint64_t query_infractions = 0;
-    uint64_t fragment_infractions = 0;
+    NHttpInfractions format_infractions;
+    NHttpInfractions scheme_infractions;
+    NHttpInfractions host_infractions;
+    NHttpInfractions port_infractions;
+    NHttpInfractions path_infractions;
+    NHttpInfractions query_infractions;
+    NHttpInfractions fragment_infractions;
 
     NHttpEnums::UriType uri_type = NHttpEnums::URI__NOTCOMPUTE;
     NHttpEnums::SchemeId scheme_id = NHttpEnums::SCH__NOTCOMPUTE;
index 1b1b998d06cd100836666688a3eacf6d355b45d1..554d7cddc365e3243cae68a4af414539fde9f5c0 100644 (file)
@@ -26,7 +26,8 @@
 
 using namespace NHttpEnums;
 
-void UriNormalizer::normalize(const Field &input, Field &result, bool do_path, ScratchPad &scratch_pad, uint64_t &infractions) {
+void UriNormalizer::normalize(const Field &input, Field &result, bool do_path, ScratchPad &scratch_pad,
+   NHttpInfractions &infractions) {
     if (result.length != STAT_NOTCOMPUTE) return;
     assert (input.length >= 0);
 
@@ -65,27 +66,28 @@ void UriNormalizer::normalize(const Field &input, Field &result, bool do_path, S
     result.length = data_length;
 }
 
-bool UriNormalizer::no_path_check(const uint8_t* in_buf, int32_t in_length, uint64_t& infractions) {
+bool UriNormalizer::no_path_check(const uint8_t* in_buf, int32_t in_length, NHttpInfractions& infractions) {
     for (int32_t k = 0; k < in_length; k++) {
         if ((uri_char[in_buf[k]] == CHAR_NORMAL) || (uri_char[in_buf[k]] == CHAR_PATH)) continue;
-        infractions |= INF_URINEEDNORM;
+        infractions += INF_URINEEDNORM;
         return false;
     }
     return true;
 }
 
-bool UriNormalizer::path_check(const uint8_t* in_buf, int32_t in_length, uint64_t& infractions) {
+bool UriNormalizer::path_check(const uint8_t* in_buf, int32_t in_length, NHttpInfractions& infractions) {
     for (int32_t k = 0; k < in_length; k++) {
         // FIXIT-P Periods are common and most don't need to be normalized. Need a better test.
         if (uri_char[in_buf[k]] == CHAR_NORMAL) continue;
         if ((in_buf[k] == '/') && ((k == 0) || (in_buf[k-1] != '/'))) continue;
-        infractions |= INF_URINEEDNORM;
+        infractions += INF_URINEEDNORM;
         return false;
     }
     return true;
 }
 
-int32_t UriNormalizer::norm_char_clean(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t& infractions, const void *) {
+int32_t UriNormalizer::norm_char_clean(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf,
+   NHttpInfractions& infractions, const void *) {
     int32_t length = 0;
     for (int32_t k = 0; k < in_length; k++) {
         switch (uri_char[in_buf[k]]) {
@@ -94,11 +96,11 @@ int32_t UriNormalizer::norm_char_clean(const uint8_t* in_buf, int32_t in_length,
             out_buf[length++] = in_buf[k];
             break;
           case CHAR_INVALID:
-            infractions |= INF_URIBADCHAR;
+            infractions += INF_URIBADCHAR;
             out_buf[length++] = in_buf[k];
             break;
           case CHAR_EIGHTBIT:
-            infractions |= INF_URI8BITCHAR;
+            infractions += INF_URI8BITCHAR;
             out_buf[length++] = in_buf[k];
             break;
           case CHAR_PERCENT:
@@ -107,32 +109,32 @@ int32_t UriNormalizer::norm_char_clean(const uint8_t* in_buf, int32_t in_length,
                     uint8_t value = as_hex[in_buf[k+1]] * 16 + as_hex[in_buf[k+2]];
                     if (good_percent[value]) {
                         // Normal % escape of an ASCII special character that is supposed to be escaped
-                        infractions |= INF_URIPERCENTNORMAL;
+                        infractions += INF_URIPERCENTNORMAL;
                         out_buf[length++] = '%';
                     }
                     else {
                         // Suspicious % escape of an ASCII character that does not need to be escaped
-                        infractions |= INF_URIPERCENTASCII;
-                        if (uri_char[value] == CHAR_INVALID) infractions |= INF_URIBADCHAR;
+                        infractions += INF_URIPERCENTASCII;
+                        if (uri_char[value] == CHAR_INVALID) infractions += INF_URIBADCHAR;
                         out_buf[length++] = value;
                         k += 2;
                     }
                 }
                 else {
                     // UTF-8 decoding not implemented yet
-                    infractions |= INF_URIPERCENTUTF8;
+                    infractions += INF_URIPERCENTUTF8;
                     out_buf[length++] = '%';
                 }
             }
             else if ((k+5 < in_length) && (in_buf[k+1] == 'u') && (as_hex[in_buf[k+2]] != -1) && (as_hex[in_buf[k+3]] != -1)
                && (as_hex[in_buf[k+4]] != -1) && (as_hex[in_buf[k+5]] != -1)) {
                 // 'u' UTF-16 decoding not implemented yet
-                infractions |= INF_URIPERCENTUCODE;
+                infractions += INF_URIPERCENTUCODE;
                 out_buf[length++] = '%';
             }
             else {
                 // Don't recognize it
-                infractions |= INF_URIPERCENTOTHER;
+                infractions += INF_URIPERCENTOTHER;
                 out_buf[length++] = '%';
             }
             break;
@@ -142,19 +144,21 @@ int32_t UriNormalizer::norm_char_clean(const uint8_t* in_buf, int32_t in_length,
 }
 
 // Convert URI backslashes to slashes
-int32_t UriNormalizer::norm_backslash(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t& infractions, const void *) {
+int32_t UriNormalizer::norm_backslash(const uint8_t* in_buf, int32_t in_length, uint8_t* out_buf,
+   NHttpInfractions& infractions, const void*) {
     for (int32_t k = 0; k < in_length; k++) {
         if (in_buf[k] != '\\') out_buf[k] = in_buf[k];
         else {
             out_buf[k] = '/';
-            infractions |= INF_URIBACKSLASH;
+            infractions += INF_URIBACKSLASH;
         }
     }
     return in_length;
 }
 
 // Caution: worst case output length is one greater than input length
-int32_t UriNormalizer::norm_path_clean(const uint8_t* in_buf, int32_t in_length, uint8_t *out_buf, uint64_t& infractions, const void *) {
+int32_t UriNormalizer::norm_path_clean(const uint8_t* in_buf, int32_t in_length, uint8_t* out_buf,
+   NHttpInfractions& infractions, const void*) {
     int32_t length = 0;
     // It simplifies the code that handles /./ and /../ to pretend there is an extra '/' after the buffer.
     // Avoids making a special case of URIs that end in . or ..
@@ -166,17 +170,17 @@ int32_t UriNormalizer::norm_path_clean(const uint8_t* in_buf, int32_t in_length,
         }
         // Ignore this slash if it directly follows another slash
         else if ((k < in_length) && (length >= 1) && (out_buf[length-1] == '/')) {
-            infractions |= INF_URIMULTISLASH;
+            infractions += INF_URIMULTISLASH;
         }
         // This slash is the end of a /./ pattern, ignore this slash and remove the period from the output
         else if ((length >= 2) && (out_buf[length-1] == '.') && (out_buf[length-2] == '/')) {
-            infractions |= INF_URISLASHDOT;
+            infractions += INF_URISLASHDOT;
             length -= 1;
         }
         // This slash is the end of a /../ pattern, normalization depends on whether there is a previous directory that
         // we can remove
         else if ((length >= 3) && (out_buf[length-1] == '.') && (out_buf[length-2] == '.') && (out_buf[length-3] == '/')) {
-            infractions |= INF_URISLASHDOTDOT;
+            infractions += INF_URISLASHDOTDOT;
             // Traversing above the root of the absolute path. A path of the form /../../../foo/bar/whatever cannot be
             // further normalized. Instead of taking away a directory we leave the .. and write out the new slash.
             // This code can write out the pretend slash after the end of the buffer. That is intentional so that the
@@ -184,7 +188,7 @@ int32_t UriNormalizer::norm_path_clean(const uint8_t* in_buf, int32_t in_length,
             if ( (length == 3) ||
                 ((length >= 6) && (out_buf[length-4] == '.') && (out_buf[length-5] == '.') && (out_buf[length-6] == '/')))
             {
-                infractions |= INF_URIROOTTRAV;
+                infractions += INF_URIROOTTRAV;
                 out_buf[length++] = '/';
             }
             // Remove the previous directory from the output. "/foo/bar/../" becomes "/foo/"
index 462bd74997902ee782929778c557d45ab6c2ef85..aaaa4e3c8babf37e7a6d6af8eb5c4cf5ce2ac478 100644 (file)
 
 #include "nhttp_scratch_pad.h"
 #include "nhttp_field.h"
+#include "nhttp_infractions.h"
 
 class UriNormalizer {
 public:
-    static void normalize(const Field &input, Field &result, bool do_path, ScratchPad &scratch_pad, uint64_t &infractions);
+    static void normalize(const Field &input, Field &result, bool do_path, ScratchPad &scratch_pad,
+       NHttpInfractions &infractions);
 
 private:
     static const NHttpEnums::CharAction uri_char[256];
     static const bool good_percent[256];
 
-    static bool no_path_check(const uint8_t* in_buf, int32_t in_length, uint64_t& infractions);
-    static bool path_check(const uint8_t* in_buf, int32_t in_length, uint64_t& infractions);
+    static bool no_path_check(const uint8_t* in_buf, int32_t in_length, NHttpInfractions& infractions);
+    static bool path_check(const uint8_t* in_buf, int32_t in_length, NHttpInfractions& infractions);
 
-    static int32_t norm_char_clean(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* not_used);
-    static int32_t norm_backslash(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* not_used);
-    static int32_t norm_path_clean(const uint8_t*, int32_t, uint8_t*, uint64_t&, const void* not_used);
+    static int32_t norm_char_clean(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, const void* not_used);
+    static int32_t norm_backslash(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, const void* not_used);
+    static int32_t norm_path_clean(const uint8_t*, int32_t, uint8_t*, NHttpInfractions&, const void* not_used);
 };
 
 #endif