From: Russ Combs (rucombs) Date: Tue, 1 Mar 2016 22:55:43 +0000 (-0500) Subject: Merge pull request #307 in SNORT/snort3 from nhttp38 to master X-Git-Tag: 3.0.0-233~565 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f3ac5ff96dece888f93011109a0f79db48c64d54;p=thirdparty%2Fsnort3.git Merge pull request #307 in SNORT/snort3 from nhttp38 to master Squashed commit of the following: commit 18c6399ec8cbeaf354b4a07515fe437adc730626 Author: Tom Peters Date: Tue Mar 1 17:21:19 2016 -0500 code review comment commit 6c41887b194bf5d53b125f81b32c324ecab4029e Author: Tom Peters Date: Tue Mar 1 15:41:55 2016 -0500 code review change commit 03859f8b3a1d1be2fda77acdd78195f9b5e51f47 Author: Tom Peters Date: Mon Feb 15 11:36:52 2016 -0500 NHI basic URI normalization with configuration options --- diff --git a/.gitignore b/.gitignore index 57ef5424d..8ee77c533 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,7 @@ doc/snort_manual.text doc/snort_manual.tgz doc/snort_manual.xml doc/version.txt +extra/m4/*.m4 extra/rule.xxd extra/snort_examples-1.0.tar.gz install-sh diff --git a/src/service_inspectors/nhttp_inspect/CMakeLists.txt b/src/service_inspectors/nhttp_inspect/CMakeLists.txt index 71484325d..afa2f9724 100644 --- a/src/service_inspectors/nhttp_inspect/CMakeLists.txt +++ b/src/service_inspectors/nhttp_inspect/CMakeLists.txt @@ -36,7 +36,6 @@ set (FILE_LIST nhttp_str_to_code.h nhttp_api.cc nhttp_api.h nhttp_tables.cc - nhttp_uri_tables.cc nhttp_module.cc nhttp_module.h nhttp_test_input.cc diff --git a/src/service_inspectors/nhttp_inspect/Makefile.am b/src/service_inspectors/nhttp_inspect/Makefile.am index 7f1b39b44..0d25febbb 100644 --- a/src/service_inspectors/nhttp_inspect/Makefile.am +++ b/src/service_inspectors/nhttp_inspect/Makefile.am @@ -19,7 +19,6 @@ nhttp_normalizers.cc nhttp_normalizers.h \ nhttp_str_to_code.cc nhttp_str_to_code.h \ nhttp_api.cc nhttp_api.h \ nhttp_tables.cc \ -nhttp_uri_tables.cc \ nhttp_module.cc nhttp_module.h \ nhttp_test_input.cc nhttp_test_input.h \ nhttp_flow_data.cc nhttp_flow_data.h \ diff --git a/src/service_inspectors/nhttp_inspect/nhttp_enum.h b/src/service_inspectors/nhttp_inspect/nhttp_enum.h index fe4d4bbc5..740c74cae 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_enum.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_enum.h @@ -130,8 +130,8 @@ enum Infraction INF_BAD_URI, INF_ZERO_NINE_REQ, INF_ZERO_NINE_CONTINUE, - INF_URI_PERCENT_NORMAL, - INF_URI_PERCENT_ASCII, + INF_NOT_USED_2, + INF_URI_PERCENT_UNRESERVED, INF_URI_PERCENT_UTF8, INF_URI_PERCENT_UCODE, INF_URI_PERCENT_OTHER, @@ -177,7 +177,7 @@ enum Infraction }; // Types of character for URI scanning -enum CharAction { CHAR_NORMAL=2, CHAR_PERCENT, CHAR_PATH, CHAR_INVALID, CHAR_EIGHTBIT }; +enum CharAction { CHAR_NORMAL=2, CHAR_PERCENT, CHAR_PATH, CHAR_EIGHTBIT, CHAR_SUBSTIT }; // Transfer codings enum Transcoding { TRANSCODE__OTHER=1, TRANSCODE_CHUNKED, TRANSCODE_GZIP, TRANSCODE_DEFLATE, diff --git a/src/service_inspectors/nhttp_inspect/nhttp_module.cc b/src/service_inspectors/nhttp_inspect/nhttp_module.cc index a23946ed6..70a906e56 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_module.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_module.cc @@ -20,8 +20,11 @@ #include #include +#include "nhttp_uri_norm.h" #include "nhttp_module.h" +using namespace NHttpEnums; + const Parameter NHttpModule::nhttp_params[] = { { "request_depth", Parameter::PT_INT, "-1:", "-1", @@ -29,6 +32,17 @@ const Parameter NHttpModule::nhttp_params[] = { "response_depth", Parameter::PT_INT, "-1:", "-1", "maximum response message body bytes to examine (-1 no limit)" }, { "unzip", Parameter::PT_BOOL, nullptr, "true", "decompress gzip and deflate message bodies" }, + { "bad_characters", Parameter::PT_BIT_LIST, "255", nullptr, + "alert when any of specified bytes are present in URI after percent decoding" }, + { "ignore_unreserved", Parameter::PT_STRING, "(optional)", nullptr, + "do not alert when the specified unreserved characters are percent-encoded in a URI." + "Unreserved characters are 0-9, a-z, A-Z, period, underscore, tilde, and minus." }, + { "backslash_to_slash", Parameter::PT_BOOL, nullptr, "false", + "replace \\ with / when normalizing URIs" }, + { "plus_to_space", Parameter::PT_BOOL, nullptr, "true", + "replace + with when normalizing URIs" }, + { "simplify_path", Parameter::PT_BOOL, nullptr, "true", + "reduce URI directory path to simplest form" }, #ifdef REG_TEST { "test_input", Parameter::PT_BOOL, nullptr, "false", "read HTTP messages from text file" }, { "test_output", Parameter::PT_BOOL, nullptr, "false", "print out HTTP section data" }, @@ -57,6 +71,34 @@ bool NHttpModule::set(const char*, Value& val, SnortConfig*) { params.unzip = val.get_bool(); } + else if (val.is("bad_characters")) + { + val.get_bits(params.uri_param.bad_characters); + } + else if (val.is("ignore_unreserved")) + { + const char* ignore = val.get_string(); + while (*ignore != '\0') + { + params.uri_param.unreserved_char[*(ignore++)] = false; + } + } + else if (val.is("backslash_to_slash")) + { + params.uri_param.backslash_to_slash = val.get_bool(); + params.uri_param.uri_char['\\'] = val.get_bool() ? CHAR_SUBSTIT : CHAR_NORMAL; + } + else if (val.is("plus_to_space")) + { + params.uri_param.plus_to_space = val.get_bool(); + params.uri_param.uri_char['+'] = val.get_bool() ? CHAR_SUBSTIT : CHAR_NORMAL; + } + else if (val.is("simplify_path")) + { + params.uri_param.simplify_path = val.get_bool(); + params.uri_param.uri_char['/'] = val.get_bool() ? CHAR_PATH : CHAR_NORMAL; + params.uri_param.uri_char['.'] = val.get_bool() ? CHAR_PATH : CHAR_NORMAL; + } #ifdef REG_TEST else if (val.is("test_input")) { @@ -78,3 +120,62 @@ bool NHttpModule::set(const char*, Value& val, SnortConfig*) return true; } +// Some values in these tables may be changed by configuration parameters. +NHttpParaList::UriParam::UriParam() : + // Characters that should not be percent-encoded + // 0-9, a-z, A-Z, tilde, period, underscore, and minus + // Initializer string for std::bitset is in reverse order. The first character is element 255 + // and the last is element 0. + unreserved_char { std::string( + "00000000" "00000000" "00000000" "00000000" + "00000000" "00000000" "00000000" "00000000" + "00000000" "00000000" "00000000" "00000000" + "00000000" "00000000" "00000000" "00000000" + "01000111" "11111111" "11111111" "11111110" + "10000111" "11111111" "11111111" "11111110" + "00000011" "11111111" "01100000" "00000000" + "00000000" "00000000" "00000000" "00000000" ) }, + + uri_char { + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_PERCENT, CHAR_NORMAL, CHAR_NORMAL, + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_SUBSTIT, CHAR_NORMAL, CHAR_NORMAL, CHAR_PATH, CHAR_PATH, + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_PATH, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, + + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, + CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT + } +{} + diff --git a/src/service_inspectors/nhttp_inspect/nhttp_module.h b/src/service_inspectors/nhttp_inspect/nhttp_module.h index 4ef87d22c..d4c3fd10a 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_module.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_module.h @@ -20,6 +20,9 @@ #ifndef NHTTP_MODULE_H #define NHTTP_MODULE_H +#include +#include + #include "framework/module.h" #include "nhttp_enum.h" @@ -33,6 +36,19 @@ public: long request_depth; long response_depth; bool unzip; + struct UriParam + { + public: + UriParam(); + + bool backslash_to_slash; + bool plus_to_space; + bool simplify_path; + std::bitset<256> bad_characters; + std::bitset<256> unreserved_char; + NHttpEnums::CharAction uri_char[256]; + }; + UriParam uri_param; #ifdef REG_TEST bool test_input; bool test_output; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc index b353e6098..6e212e220 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc @@ -137,7 +137,8 @@ void NHttpMsgBody::do_file_processing() const Field& NHttpMsgBody::get_classic_client_body() { - return classic_normalize(detect_data, classic_client_body, classic_client_body_alloc); + return classic_normalize(detect_data, classic_client_body, classic_client_body_alloc, + params->uri_param); } #ifdef REG_TEST diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.cc index 65d5a2ef1..dd162d952 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.cc @@ -283,7 +283,7 @@ const Field& NHttpMsgHeadShared::get_classic_raw_header() const Field& NHttpMsgHeadShared::get_classic_norm_header() { return classic_normalize(get_classic_raw_header(), classic_norm_header, - classic_norm_header_alloc); + classic_norm_header_alloc, params->uri_param); } const Field& NHttpMsgHeadShared::get_classic_raw_cookie() @@ -295,7 +295,7 @@ const Field& NHttpMsgHeadShared::get_classic_raw_cookie() const Field& NHttpMsgHeadShared::get_classic_norm_cookie() { return classic_normalize(get_classic_raw_cookie(), classic_norm_cookie, - classic_norm_cookie_alloc); + classic_norm_cookie_alloc, params->uri_param); } const Field& NHttpMsgHeadShared::get_header_value_norm(HeaderId header_id) diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc index e8447e8cf..74009df65 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc @@ -83,7 +83,7 @@ void NHttpMsgRequest::parse_start_line() if (first_end < last_begin) { uri = new NHttpUri(start_line.start + first_end + 1, last_begin - first_end - 1, - method_id, infractions, events); + method_id, params->uri_param, infractions, events); } else { @@ -115,7 +115,7 @@ bool NHttpMsgRequest::handle_zero_nine() int32_t uri_end; for (uri_end = start_line.length - 1; is_sp_tab[start_line.start[uri_end]]; uri_end--); uri = new NHttpUri(start_line.start + uri_begin, uri_end - uri_begin + 1, method_id, - infractions, events); + params->uri_param, infractions, events); } else { diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc index 700ee0232..d87ecb437 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc @@ -79,18 +79,19 @@ void NHttpMsgSection::update_depth() const } } -const Field& NHttpMsgSection::classic_normalize(const Field& raw, Field& norm, bool& norm_alloc) +const Field& NHttpMsgSection::classic_normalize(const Field& raw, Field& norm, bool& norm_alloc, + const NHttpParaList::UriParam& uri_param) { if (norm.length != STAT_NOT_COMPUTE) return norm; - if ((raw.length <= 0) || !UriNormalizer::need_norm_path(raw)) + if ((raw.length <= 0) || !UriNormalizer::classic_need_norm(raw, true, uri_param)) { norm.set(raw); return norm; } uint8_t* buffer = new uint8_t[raw.length + UriNormalizer::URI_NORM_EXPANSION]; - UriNormalizer::classic_normalize(raw, norm, buffer); + UriNormalizer::classic_normalize(raw, norm, buffer, uri_param); norm_alloc = true; return norm; } diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h index d64a14101..d005336ec 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h @@ -82,7 +82,8 @@ protected: // Convenience methods shared by multiple subclasses void update_depth() const; - static const Field& classic_normalize(const Field& raw, Field& norm, bool& norm_alloc); + static const Field& classic_normalize(const Field& raw, Field& norm, bool& norm_alloc, + const NHttpParaList::UriParam& uri_param); #ifdef REG_TEST void print_section_title(FILE* output, const char* title) const; void print_section_wrapup(FILE* output) const; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_uri.cc b/src/service_inspectors/nhttp_inspect/nhttp_uri.cc index c080c1fa6..fe579f571 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_uri.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_uri.cc @@ -155,9 +155,6 @@ void NHttpUri::parse_abs_path() void NHttpUri::normalize() { - // FIXIT-P generating the normalized URI components directly into the normalized classic buffer - // would save a lot of memory and some copying. - // Divide the URI up into its six components: scheme, host, port, path, query, and fragment parse_uri(); parse_authority(); @@ -166,13 +163,15 @@ void NHttpUri::normalize() // Almost all HTTP requests are honest and rarely need expensive normalization processing. We // do a quick scan for red flags and only perform normalization if something comes up. // Otherwise we set the normalized fields to point at the raw values. - if ((host.length > 0) && UriNormalizer::need_norm_no_path(host)) + if ((host.length > 0) && UriNormalizer::need_norm(host, false, uri_param, infractions, events)) infractions += INF_URI_NEED_NORM_HOST; - if ((path.length > 0) && UriNormalizer::need_norm_path(path)) + if ((path.length > 0) && UriNormalizer::need_norm(path, true, uri_param, infractions, events)) infractions += INF_URI_NEED_NORM_PATH; - if ((query.length > 0) && UriNormalizer::need_norm_no_path(query)) + if ((query.length > 0) && UriNormalizer::need_norm(query, false, uri_param, infractions, + events)) infractions += INF_URI_NEED_NORM_QUERY; - if ((fragment.length > 0) && UriNormalizer::need_norm_no_path(fragment)) + if ((fragment.length > 0) && UriNormalizer::need_norm(fragment, false, uri_param, infractions, + events)) infractions += INF_URI_NEED_NORM_FRAGMENT; if (!((infractions & INF_URI_NEED_NORM_PATH) || (infractions & INF_URI_NEED_NORM_HOST) || @@ -200,7 +199,8 @@ void NHttpUri::normalize() if (host.length > 0) { if (infractions & INF_URI_NEED_NORM_HOST) - UriNormalizer::normalize(host, host_norm, false, current, infractions, events); + UriNormalizer::normalize(host, host_norm, false, current, uri_param, infractions, + events); else { // The host component is not changing but other parts of the URI are being normalized. @@ -222,7 +222,8 @@ void NHttpUri::normalize() if (path.length > 0) { if (infractions & INF_URI_NEED_NORM_PATH) - UriNormalizer::normalize(path, path_norm, true, current, infractions, events); + UriNormalizer::normalize(path, path_norm, true, current, uri_param, infractions, + events); else { memcpy(current, path.start, path.length); @@ -235,7 +236,8 @@ void NHttpUri::normalize() memcpy(current, "?", 1); current += 1; if (infractions & INF_URI_NEED_NORM_QUERY) - UriNormalizer::normalize(query, query_norm, false, current, infractions, events); + UriNormalizer::normalize(query, query_norm, false, current, uri_param, infractions, + events); else { memcpy(current, query.start, query.length); @@ -248,7 +250,8 @@ void NHttpUri::normalize() memcpy(current, "#", 1); current += 1; if (infractions & INF_URI_NEED_NORM_FRAGMENT) - UriNormalizer::normalize(fragment, fragment_norm, false, current, infractions, events); + UriNormalizer::normalize(fragment, fragment_norm, false, current, uri_param, + infractions, events); else { memcpy(current, fragment.start, fragment.length); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_uri.h b/src/service_inspectors/nhttp_inspect/nhttp_uri.h index 89f264370..dfd835e05 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_uri.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_uri.h @@ -21,6 +21,7 @@ #define NHTTP_URI_H #include "nhttp_str_to_code.h" +#include "nhttp_module.h" #include "nhttp_uri_norm.h" #include "nhttp_field.h" #include "nhttp_infractions.h" @@ -33,9 +34,11 @@ class NHttpUri { public: - NHttpUri(const uint8_t* start, int32_t length, NHttpEnums::MethodId method, - NHttpInfractions& infractions_, NHttpEventGen& events_) : - uri(length, start), method_id(method), infractions(infractions_), events(events_) + NHttpUri(const uint8_t* start, int32_t length, NHttpEnums::MethodId method_id_, + const NHttpParaList::UriParam& uri_param_, NHttpInfractions& infractions_, + NHttpEventGen& events_) : + uri(length, start), method_id(method_id_), uri_param(uri_param_), + infractions(infractions_), events(events_) { normalize(); } ~NHttpUri(); const Field& get_uri() const { return uri; } @@ -58,6 +61,7 @@ public: private: const Field uri; const NHttpEnums::MethodId method_id; + const NHttpParaList::UriParam& uri_param; NHttpInfractions& infractions; NHttpEventGen& events; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_uri_norm.cc b/src/service_inspectors/nhttp_inspect/nhttp_uri_norm.cc index 6fd54ba59..c34337f1a 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_uri_norm.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_uri_norm.cc @@ -19,6 +19,7 @@ #include #include +#include #include "nhttp_enum.h" #include "nhttp_uri_norm.h" @@ -26,143 +27,185 @@ using namespace NHttpEnums; void UriNormalizer::normalize(const Field& input, Field& result, bool do_path, uint8_t* buffer, - NHttpInfractions& infractions, NHttpEventGen& events) + const NHttpParaList::UriParam& uri_param, NHttpInfractions& infractions, NHttpEventGen& events) { - // Normalize character escape sequences - int32_t data_length = norm_char_clean(input.start, input.length, buffer, infractions, events); + // Normalize percent encodings and similar escape sequences + int32_t data_length = norm_char_clean(input, buffer, uri_param, infractions, events); + + detect_bad_char(Field(data_length, buffer), uri_param, infractions, events); + + norm_substitute(buffer, data_length, uri_param, infractions, events); // Normalize path directory traversals - if (do_path) + if (do_path && uri_param.simplify_path) { - norm_backslash(buffer, data_length, infractions, events); data_length = norm_path_clean(buffer, data_length, infractions, events); } result.set(data_length, buffer); } -bool UriNormalizer::need_norm_no_path(const Field& uri_component) +bool UriNormalizer::need_norm(const Field& uri_component, bool do_path, + const NHttpParaList::UriParam& uri_param, NHttpInfractions& infractions, NHttpEventGen& events) +{ + bool need_it; + if (do_path && uri_param.simplify_path) + need_it = need_norm_path(uri_component, uri_param); + else + need_it = need_norm_no_path(uri_component, uri_param); + + if (!need_it) + { + // Since we are not going to normalize we need to check for bad characters now + detect_bad_char(uri_component, uri_param, infractions, events); + } + + return need_it; +} + +bool UriNormalizer::need_norm_no_path(const Field& uri_component, + const NHttpParaList::UriParam& uri_param) { const int32_t& length = uri_component.length; const uint8_t* const & buf = uri_component.start; for (int32_t k = 0; k < length; k++) { - if ((uri_char[buf[k]] == CHAR_NORMAL) || (uri_char[buf[k]] == CHAR_PATH)) - continue; - return true; + if ((uri_param.uri_char[buf[k]] == CHAR_PERCENT) || + (uri_param.uri_char[buf[k]] == CHAR_SUBSTIT)) + return true; } return false; } -bool UriNormalizer::need_norm_path(const Field& uri_component) +bool UriNormalizer::need_norm_path(const Field& uri_component, + const NHttpParaList::UriParam& uri_param) { const int32_t& length = uri_component.length; const uint8_t* const & buf = uri_component.start; for (int32_t k = 0; k < length; k++) { - if (uri_char[buf[k]] == CHAR_NORMAL) - continue; - if ((buf[k] == '/') && ((k == 0) || (buf[k-1] != '/'))) - continue; - if ( (buf[k] == '.') && - ((k == 0) || (uri_char[buf[k-1]] == CHAR_NORMAL)) && - ((k == length-1) || (uri_char[buf[k+1]] == CHAR_NORMAL))) + switch (uri_param.uri_char[buf[k]]) + { + case CHAR_NORMAL: + case CHAR_EIGHTBIT: continue; - return true; + case CHAR_PERCENT: + case CHAR_SUBSTIT: + return true; + case CHAR_PATH: + if (buf[k] == '/') + { + // slash is safe if not preceded by another slash + if ((k == 0) || (buf[k-1] != '/')) + continue; + return true; + } + else if (buf[k] == '.') + { + // period is safe if not preceded or followed by another path character + if (((k == 0) || (uri_param.uri_char[buf[k-1]] != CHAR_PATH)) && + ((k == length-1) || (uri_param.uri_char[buf[k+1]] != CHAR_PATH))) + continue; + return true; + } + else + { + return true; + } + } } return false; } -int32_t UriNormalizer::norm_char_clean(const uint8_t* in_buf, int32_t in_length, uint8_t* out_buf, - NHttpInfractions& infractions, NHttpEventGen& events) +int32_t UriNormalizer::norm_char_clean(const Field& input, uint8_t* out_buf, + const NHttpParaList::UriParam& uri_param, NHttpInfractions& infractions, NHttpEventGen& events) { int32_t length = 0; - for (int32_t k = 0; k < in_length; k++) + for (int32_t k = 0; k < input.length; k++) { - switch (uri_char[in_buf[k]]) + switch (uri_param.uri_char[input.start[k]]) { case CHAR_NORMAL: case CHAR_PATH: - out_buf[length++] = in_buf[k]; - break; - case CHAR_INVALID: - infractions += INF_URI_BAD_CHAR; - events.create_event(EVENT_NON_RFC_CHAR); - out_buf[length++] = in_buf[k]; - break; case CHAR_EIGHTBIT: - infractions += INF_URI_8BIT_CHAR; - events.create_event(EVENT_BARE_BYTE); - out_buf[length++] = in_buf[k]; + case CHAR_SUBSTIT: + out_buf[length++] = input.start[k]; break; case CHAR_PERCENT: - if ((k+2 < in_length) && (as_hex[in_buf[k+1]] != -1) && (as_hex[in_buf[k+2]] != -1)) + if ((k+2 < input.length) && (as_hex[input.start[k+1]] != -1) && + (as_hex[input.start[k+2]] != -1)) { - if (as_hex[in_buf[k+1]] <= 7) - { - uint8_t value = as_hex[in_buf[k+1]] * 16 + as_hex[in_buf[k+2]]; - if (good_percent[value]) - { - // Normal % escape of an ASCII special character that is supposed to be - // escaped - infractions += INF_URI_PERCENT_NORMAL; - out_buf[length++] = '%'; - } - else - { - // Suspicious % escape of an ASCII character that does not need to be - // escaped - infractions += INF_URI_PERCENT_ASCII; - events.create_event(EVENT_ASCII); - if (uri_char[value] == CHAR_INVALID) - { - infractions += INF_URI_BAD_CHAR; - events.create_event(EVENT_NON_RFC_CHAR); - } - out_buf[length++] = value; - k += 2; - } - } - else - { - // UTF-8 decoding not implemented yet - infractions += INF_URI_PERCENT_UTF8; - events.create_event(EVENT_UTF_8); - out_buf[length++] = '%'; - } + // %hh => hex value + out_buf[length++] = as_hex[input.start[k+1]] * 16 + as_hex[input.start[k+2]]; + k += 2; } - 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)) + else if ((k+1 < input.length) && (input.start[k+1] == '%')) { - // 'u' UTF-16 decoding not implemented yet - infractions += INF_URI_PERCENT_UCODE; - events.create_event(EVENT_U_ENCODE); + // %% => % out_buf[length++] = '%'; + k += 1; } else { - // Don't recognize it - infractions += INF_URI_PERCENT_OTHER; + // don't recognize, pass through for now (FIXIT-H unfinished feature) out_buf[length++] = '%'; } + + // The result of percent decoding should not be an "unreserved" character. That's a + // strong clue someone is hiding something. + if (uri_param.unreserved_char[out_buf[length-1]]) + { + infractions += INF_URI_PERCENT_UNRESERVED; + events.create_event(EVENT_ASCII); + } break; } } return length; } -// Convert URI backslashes to slashes -void UriNormalizer::norm_backslash(uint8_t* buf, int32_t length, NHttpInfractions& infractions, - NHttpEventGen& events) +void UriNormalizer::detect_bad_char(const Field& uri_component, + const NHttpParaList::UriParam& uri_param, NHttpInfractions& infractions, NHttpEventGen& events) { - for (int32_t k = 0; k < length; k++) + // If the bad character detection feature is not configured we quit + if (uri_param.bad_characters.count() == 0) + return; + + for (int32_t k = 0; k < uri_component.length; k++) + { + if (uri_param.bad_characters[uri_component.start[k]]) + { + infractions += INF_URI_BAD_CHAR; + events.create_event(EVENT_NON_RFC_CHAR); + return; + } + } +} + +// Replace backslash with slash and plus with space +void UriNormalizer::norm_substitute(uint8_t* buf, int32_t length, + const NHttpParaList::UriParam& uri_param, NHttpInfractions& infractions, NHttpEventGen& events) +{ + if (uri_param.backslash_to_slash) + { + for (int32_t k = 0; k < length; k++) + { + if (buf[k] == '\\') + { + buf[k] = '/'; + infractions += INF_URI_BACKSLASH; + events.create_event(EVENT_IIS_BACKSLASH); + } + } + } + if (uri_param.plus_to_space) { - if (buf[k] == '\\') + for (int32_t k = 0; k < length; k++) { - buf[k] = '/'; - infractions += INF_URI_BACKSLASH; - events.create_event(EVENT_IIS_BACKSLASH); + if (buf[k] == '+') + { + buf[k] = ' '; + } } } } @@ -236,7 +279,8 @@ int32_t UriNormalizer::norm_path_clean(uint8_t* buf, const int32_t in_length, } // Provide traditional URI-style normalization for buffers that usually are not URIs -void UriNormalizer::classic_normalize(const Field& input, Field& result, uint8_t* buffer) +void UriNormalizer::classic_normalize(const Field& input, Field& result, uint8_t* buffer, + const NHttpParaList::UriParam& uri_param) { // The requirements for generating events related to these normalizations are unclear. It // definitely doesn't seem right to generate standard URI events. For now we won't generate @@ -247,28 +291,36 @@ void UriNormalizer::classic_normalize(const Field& input, Field& result, uint8_t // infraction logic with legacy problems. The following centralizes all the messiness here so // that we can conveniently modify it as requirements are better understood. - class NHttpDummyEventGen : public NHttpEventGen - { - void create_event(NHttpEnums::EventSid) override {} - }; - NHttpInfractions unused; NHttpDummyEventGen dummy_ev; // Normalize character escape sequences - int32_t data_length = norm_char_clean(input.start, input.length, buffer, unused, dummy_ev); + int32_t data_length = norm_char_clean(input, buffer, uri_param, unused, dummy_ev); - // Normalize path directory traversals - // Find the leading slash if there is one - int32_t uri_offset; - for (uri_offset = 0; (uri_offset < data_length) && (buffer[uri_offset] != '/'); uri_offset++); - if (uri_offset < data_length) + if (uri_param.simplify_path) { - norm_backslash(buffer + uri_offset, data_length - uri_offset, unused, dummy_ev); - data_length = uri_offset + - norm_path_clean(buffer + uri_offset, data_length - uri_offset, unused, dummy_ev); + // Normalize path directory traversals + // Find the leading slash if there is one + uint8_t* first_slash = (uint8_t*)memchr(buffer, '/', data_length); + if (first_slash != nullptr) + { + const int32_t uri_offset = first_slash - buffer; + norm_substitute(buffer + uri_offset, data_length - uri_offset, uri_param, unused, + dummy_ev); + data_length = uri_offset + + norm_path_clean(buffer + uri_offset, data_length - uri_offset, unused, dummy_ev); + } } result.set(data_length, buffer); } +bool UriNormalizer::classic_need_norm(const Field& uri_component, bool do_path, + const NHttpParaList::UriParam& uri_param) +{ + NHttpInfractions unused; + NHttpDummyEventGen dummy_ev; + + return need_norm(uri_component, do_path, uri_param, unused, dummy_ev); +} + diff --git a/src/service_inspectors/nhttp_inspect/nhttp_uri_norm.h b/src/service_inspectors/nhttp_inspect/nhttp_uri_norm.h index 2d2ba8728..6a3ba4888 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_uri_norm.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_uri_norm.h @@ -21,6 +21,7 @@ #define NHTTP_URI_NORM_H #include "nhttp_field.h" +#include "nhttp_module.h" #include "nhttp_infractions.h" #include "nhttp_event_gen.h" @@ -29,22 +30,39 @@ class UriNormalizer public: static const unsigned URI_NORM_EXPANSION = 1; + static bool need_norm(const Field& uri_component, bool do_path, + const NHttpParaList::UriParam& uri_param, NHttpInfractions& infractions, + NHttpEventGen& events); static void normalize(const Field& input, Field& result, bool do_path, uint8_t* buffer, - NHttpInfractions& infractions, NHttpEventGen& events); - static bool need_norm_path(const Field& uri_component); - static bool need_norm_no_path(const Field& uri_component); - static void classic_normalize(const Field& input, Field& result, uint8_t* buffer); + const NHttpParaList::UriParam& uri_param, NHttpInfractions& infractions, + NHttpEventGen& events); + static bool classic_need_norm(const Field& uri_component, bool do_path, + const NHttpParaList::UriParam& uri_param); + static void classic_normalize(const Field& input, Field& result, uint8_t* buffer, + const NHttpParaList::UriParam& uri_param); private: - static const NHttpEnums::CharAction uri_char[256]; - static const bool good_percent[256]; - - static int32_t norm_char_clean(const uint8_t* in_buf, int32_t in_length, uint8_t* out_buf, - NHttpInfractions& infractions, NHttpEventGen& events); - static void norm_backslash(uint8_t* buf, int32_t length, NHttpInfractions& infractions, + static bool need_norm_path(const Field& uri_component, + const NHttpParaList::UriParam& uri_param); + static bool need_norm_no_path(const Field& uri_component, + const NHttpParaList::UriParam& uri_param); + static int32_t norm_char_clean(const Field& input, uint8_t* out_buf, + const NHttpParaList::UriParam& uri_param, NHttpInfractions& infractions, + NHttpEventGen& events); + static void norm_substitute(uint8_t* buf, int32_t length, + const NHttpParaList::UriParam& uri_param, NHttpInfractions& infractions, NHttpEventGen& events); static int32_t norm_path_clean(uint8_t* buf, const int32_t in_length, NHttpInfractions& infractions, NHttpEventGen& events); + static void detect_bad_char(const Field& uri_component, + const NHttpParaList::UriParam& uri_param, NHttpInfractions& infractions, + NHttpEventGen& events); + + // An artifice used by the classic normalization methods to disable event generation + class NHttpDummyEventGen : public NHttpEventGen + { + void create_event(NHttpEnums::EventSid) override {} + }; }; #endif diff --git a/src/service_inspectors/nhttp_inspect/nhttp_uri_tables.cc b/src/service_inspectors/nhttp_inspect/nhttp_uri_tables.cc deleted file mode 100644 index a61961227..000000000 --- a/src/service_inspectors/nhttp_inspect/nhttp_uri_tables.cc +++ /dev/null @@ -1,97 +0,0 @@ -//-------------------------------------------------------------------------- -// Copyright (C) 2014-2016 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_uri_tables.cc author Tom Peters - -#include -#include - -#include "nhttp_enum.h" -#include "nhttp_uri_norm.h" - -using namespace NHttpEnums; - -const CharAction UriNormalizer::uri_char[256] = -{ - CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, - CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, - CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, - CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, CHAR_INVALID, - - CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_PERCENT, CHAR_NORMAL, CHAR_NORMAL, - CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_PATH, CHAR_PATH, - CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, - CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, - - CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, - CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, - CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, - CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_PATH, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, - - CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, - CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, - CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, - CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_NORMAL, CHAR_INVALID, - - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, - CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT, CHAR_EIGHTBIT -}; - -const bool UriNormalizer::good_percent[256] = -{ - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, true, false, true, false, false, - - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false -}; -