From: Russ Combs (rucombs) Date: Wed, 16 Dec 2015 11:09:48 +0000 (-0500) Subject: Merge pull request #194 in SNORT/snort3 from nhttp30C to master X-Git-Tag: 3.0.0-233~674 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5d84bb8883ebe259d413a2e79cf6dbfb8d065d2f;p=thirdparty%2Fsnort3.git Merge pull request #194 in SNORT/snort3 from nhttp30C to master Squashed commit of the following: commit f6bbe467682a6269af7ebbe9ce124b2010d2f152 Author: Tom Peters Date: Tue Dec 15 16:39:54 2015 -0500 cmake fix commit b62e8b4430330b6ffc01d5bfdb91dc2a06b8d78a Author: Tom Peters Date: Wed Nov 11 17:47:18 2015 -0500 NHI IPS rule options --- diff --git a/src/service_inspectors/nhttp_inspect/CMakeLists.txt b/src/service_inspectors/nhttp_inspect/CMakeLists.txt index 37088181e..153d82928 100644 --- a/src/service_inspectors/nhttp_inspect/CMakeLists.txt +++ b/src/service_inspectors/nhttp_inspect/CMakeLists.txt @@ -64,3 +64,6 @@ if (STATIC_INSPECTORS) else(STATIC_INSPECTORS) add_shared_library(nhttp_inspect inspectors ${FILE_LIST}) endif(STATIC_INSPECTORS) + +add_shared_library(nhttp_inspect_opt inspectors ips_nhttp.cc ips_nhttp.h) + diff --git a/src/service_inspectors/nhttp_inspect/Makefile.am b/src/service_inspectors/nhttp_inspect/Makefile.am index c6bc8496f..004548890 100644 --- a/src/service_inspectors/nhttp_inspect/Makefile.am +++ b/src/service_inspectors/nhttp_inspect/Makefile.am @@ -44,5 +44,12 @@ libnhttp_inspect_la_LDFLAGS = -export-dynamic -shared libnhttp_inspect_la_SOURCES = $(file_list) endif +optlibdir = $(pkglibdir)/inspectors + +optlib_LTLIBRARIES = libnhttp_inspect_opt.la +libnhttp_inspect_opt_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO +libnhttp_inspect_opt_la_LDFLAGS = -export-dynamic -shared +libnhttp_inspect_opt_la_SOURCES = ips_nhttp.cc ips_nhttp.h + AM_CXXFLAGS = @AM_CXXFLAGS@ diff --git a/src/service_inspectors/nhttp_inspect/ips_nhttp.cc b/src/service_inspectors/nhttp_inspect/ips_nhttp.cc new file mode 100644 index 000000000..ba45e5329 --- /dev/null +++ b/src/service_inspectors/nhttp_inspect/ips_nhttp.cc @@ -0,0 +1,863 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015 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. +//-------------------------------------------------------------------------- +// ips_nhttp.cc author Tom Peters + +#include + +#include "protocols/packet.h" +#include "flow/flow.h" +#include "detection/detection_defines.h" +#include "framework/cursor.h" + +#include "nhttp_inspect.h" +#include "nhttp_msg_head_shared.h" +#include "ips_nhttp.h" + +using namespace NHttpEnums; + +THREAD_LOCAL std::array NHttpCursorModule::http_ps; + +bool NHttpCursorModule::begin(const char*, int, SnortConfig*) +{ + para_list.reset(); + sub_id = 0; + switch (buffer_index) + { + case NHTTP_BUFFER_URI: + case NHTTP_BUFFER_RAW_URI: + case NHTTP_BUFFER_STAT_CODE: + case NHTTP_BUFFER_STAT_MSG: + case NHTTP_BUFFER_VERSION: + case NHTTP_BUFFER_METHOD: + inspect_section = IS_START; + break; + case NHTTP_BUFFER_HEADER: + case NHTTP_BUFFER_RAW_HEADER: + case NHTTP_BUFFER_COOKIE: + case NHTTP_BUFFER_RAW_COOKIE: + inspect_section = IS_HEADER; + break; + case NHTTP_BUFFER_CLIENT_BODY: + inspect_section = IS_BODY; + break; + case NHTTP_BUFFER_TRAILER: + case NHTTP_BUFFER_RAW_TRAILER: + inspect_section = IS_TRAILER; + break; + default: + assert(false); + } + return true; +} + +bool NHttpCursorModule::set(const char*, Value& v, SnortConfig*) +{ + if (v.is("field")) + { + if (sub_id != 0) + ParseError("Only specify one header field to match"); + para_list.field = v.get_string(); + const int32_t name_size = (para_list.field.size() <= MAX_FIELD_NAME_LENGTH) ? + para_list.field.size() : MAX_FIELD_NAME_LENGTH; + uint8_t lower_name[MAX_FIELD_NAME_LENGTH]; + for (int32_t k=0; k < name_size; k++) + { + lower_name[k] = ((para_list.field[k] < 'A') || (para_list.field[k] > 'Z')) ? + para_list.field[k] : para_list.field[k] - ('A' - 'a'); + } + sub_id = str_to_code(lower_name, name_size, NHttpMsgHeadShared::header_list); + if (sub_id == STAT_OTHER) + ParseError("Unrecognized header field name"); + } + else if (v.is("with_header")) + { + para_list.with_header = true; + inspect_section = IS_HEADER; + } + else if (v.is("with_body")) + { + para_list.with_body = true; + inspect_section = IS_BODY; + } + else if (v.is("with_trailer")) + { + para_list.with_trailer = true; + inspect_section = IS_TRAILER; + } + else if (v.is("scheme")) + { + para_list.scheme = true; + sub_id = UC_SCHEME; + } + else if (v.is("host")) + { + para_list.host = true; + sub_id = UC_HOST; + } + else if (v.is("port")) + { + para_list.port = true; + sub_id = UC_PORT; + } + else if (v.is("path")) + { + para_list.path = true; + sub_id = UC_PATH; + } + else if (v.is("query")) + { + para_list.query = true; + sub_id = UC_QUERY; + } + else if (v.is("fragment")) + { + para_list.fragment = true; + sub_id = UC_FRAGMENT; + } + else + { + return false; + } + return true; +} + +bool NHttpCursorModule::end(const char*, int, SnortConfig*) +{ + // Check for option conflicts + if (para_list.with_header + para_list.with_body + para_list.with_trailer > 1) + ParseError("Only specify one with_ option. Use the one that happens last."); + if (para_list.scheme + para_list.host + para_list.port + para_list.path + para_list.query + + para_list.fragment > 1) + ParseError("Only specify one part of the URI"); + return true; +} + +void NHttpCursorModule::NHttpRuleParaList::reset() +{ + field.clear(); + with_header = false; + with_body = false; + with_trailer = false; + scheme = false; + host = false; + port = false; + path = false; + query = false; + fragment = false; +} + +int NHttpIpsOption::eval(Cursor& c, Packet* p) +{ + Profile profile(NHttpCursorModule::http_ps[psi]); + + if (!p->flow || !p->flow->gadget) + return DETECTION_OPTION_NO_MATCH; + + if (NHttpInspect::get_latest_is() != inspect_section) + return DETECTION_OPTION_NO_MATCH; + + InspectionBuffer hb; + + if (! ((NHttpInspect*)(p->flow->gadget))->get_buf((unsigned)buffer_index, sub_id, nullptr, hb)) + return DETECTION_OPTION_NO_MATCH; + + c.set(key, hb.data, hb.len); + + return DETECTION_OPTION_MATCH; +} + +//------------------------------------------------------------------------- +// http_uri +//------------------------------------------------------------------------- + +static const Parameter http_uri_params[] = +{ + { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message headers" }, + { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message body" }, + { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message trailers" }, + { "scheme", Parameter::PT_IMPLIED, nullptr, nullptr, + "match against scheme section of URI only" }, + { "host", Parameter::PT_IMPLIED, nullptr, nullptr, + "match against host section of URI only" }, + { "port", Parameter::PT_IMPLIED, nullptr, nullptr, + "match against port section of URI only" }, + { "path", Parameter::PT_IMPLIED, nullptr, nullptr, + "match against path section of URI only" }, + { "query", Parameter::PT_IMPLIED, nullptr, nullptr, + "match against query section of URI only" }, + { "fragment", Parameter::PT_IMPLIED, nullptr, nullptr, + "match against fragment section of URI only" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#undef IPS_OPT +#define IPS_OPT "http_uri" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the normalized URI buffer" + +static Module* uri_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_URI, CAT_SET_KEY, PSI_URI, + http_uri_params); +} + +static const IpsApi uri_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + uri_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_client_body +//------------------------------------------------------------------------- + +#undef IPS_OPT +#define IPS_OPT "http_client_body" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the request body" + +static Module* client_body_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_CLIENT_BODY, CAT_SET_BODY, + PSI_CLIENT_BODY); +} + +static const IpsApi client_body_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + client_body_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_method +//------------------------------------------------------------------------- + +static const Parameter http_method_params[] = +{ + { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message headers" }, + { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message body" }, + { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message trailers" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#undef IPS_OPT +#define IPS_OPT "http_method" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the HTTP request method" + +static Module* method_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_METHOD, CAT_SET_OTHER, PSI_METHOD, + http_method_params); +} + +static const IpsApi method_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + method_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_cookie +//------------------------------------------------------------------------- + +static const Parameter http_cookie_params[] = +{ + { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message body" }, + { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message trailers" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#undef IPS_OPT +#define IPS_OPT "http_cookie" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the HTTP cookie" + +static Module* cookie_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_COOKIE, CAT_SET_OTHER, PSI_COOKIE, + http_cookie_params); +} + +static const IpsApi cookie_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + cookie_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_stat_code +//------------------------------------------------------------------------- + +static const Parameter http_stat_code_params[] = +{ + { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message headers" }, + { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message body" }, + { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message trailers" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#undef IPS_OPT +#define IPS_OPT "http_stat_code" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the HTTP status code" + +static Module* stat_code_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_STAT_CODE, CAT_SET_OTHER, + PSI_STAT_CODE, http_stat_code_params); +} + +static const IpsApi stat_code_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + stat_code_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_stat_msg +//------------------------------------------------------------------------- + +static const Parameter http_stat_msg_params[] = +{ + { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message headers" }, + { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message body" }, + { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message trailers" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#undef IPS_OPT +#define IPS_OPT "http_stat_msg" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the HTTP status message" + +static Module* stat_msg_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_STAT_MSG, CAT_SET_OTHER, + PSI_STAT_MSG, http_stat_msg_params); +} + +static const IpsApi stat_msg_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + stat_msg_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_raw_uri +//------------------------------------------------------------------------- + +static const Parameter http_raw_uri_params[] = +{ + { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message headers" }, + { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message body" }, + { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message trailers" }, + { "scheme", Parameter::PT_IMPLIED, nullptr, nullptr, + "match against scheme section of URI only" }, + { "host", Parameter::PT_IMPLIED, nullptr, nullptr, + "match against host section of URI only" }, + { "port", Parameter::PT_IMPLIED, nullptr, nullptr, + "match against port section of URI only" }, + { "path", Parameter::PT_IMPLIED, nullptr, nullptr, + "match against path section of URI only" }, + { "query", Parameter::PT_IMPLIED, nullptr, nullptr, + "match against query section of URI only" }, + { "fragment", Parameter::PT_IMPLIED, nullptr, nullptr, + "match against fragment section of URI only" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#undef IPS_OPT +#define IPS_OPT "http_raw_uri" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the unnormalized URI" + +static Module* raw_uri_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_RAW_URI, CAT_SET_OTHER, + PSI_RAW_URI, http_raw_uri_params); +} + +static const IpsApi raw_uri_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + raw_uri_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_raw_header +//------------------------------------------------------------------------- + +static const Parameter http_raw_header_params[] = +{ + { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message body" }, + { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message trailers" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#undef IPS_OPT +#define IPS_OPT "http_raw_header" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the unnormalized headers" + +static Module* raw_header_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_RAW_HEADER, CAT_SET_OTHER, + PSI_RAW_HEADER, http_raw_header_params); +} + +static const IpsApi raw_header_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + raw_header_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_raw_cookie +//------------------------------------------------------------------------- + +static const Parameter http_raw_cookie_params[] = +{ + { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message body" }, + { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message trailers" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#undef IPS_OPT +#define IPS_OPT "http_raw_cookie" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the unnormalized cookie" + +static Module* raw_cookie_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_RAW_COOKIE, CAT_SET_OTHER, + PSI_RAW_COOKIE, http_raw_cookie_params); +} + +static const IpsApi raw_cookie_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + raw_cookie_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_version +//------------------------------------------------------------------------- + +static const Parameter http_version_params[] = +{ + { "with_header", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message headers" }, + { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message body" }, + { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message trailers" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#undef IPS_OPT +#define IPS_OPT "http_version" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the version buffer" + +static Module* version_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_VERSION, CAT_SET_OTHER, + PSI_VERSION, http_version_params); +} + +static const IpsApi version_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + version_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_header +//------------------------------------------------------------------------- + +// FIXIT-M add match_unknown option to look at HEAD__UNKNOWN. +// FIXIT-M if http_header is the fast pattern buffer and the content to be matched appears in the +// normalized field but not in the raw field detection will fail. + +static const Parameter http_header_params[] = +{ + { "with_body", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message body" }, + { "with_trailer", Parameter::PT_IMPLIED, nullptr, nullptr, + "Parts of this rule examine HTTP message trailers" }, + { "field", Parameter::PT_STRING, nullptr, nullptr, + "Restrict to given header. Header name is case insensitive." }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#undef IPS_OPT +#define IPS_OPT "http_header" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the normalized headers" + +static Module* header_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_HEADER, CAT_SET_HEADER, + PSI_HEADER, http_header_params); +} + +static const IpsApi header_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + header_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_trailer +//------------------------------------------------------------------------- + +static const Parameter http_trailer_params[] = +{ + { "field", Parameter::PT_STRING, nullptr, nullptr, "restrict to given trailer" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } +}; + +#undef IPS_OPT +#define IPS_OPT "http_trailer" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the normalized trailers" + +static Module* trailer_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_TRAILER, CAT_SET_OTHER, + PSI_TRAILER, http_trailer_params); +} + +static const IpsApi trailer_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + trailer_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// http_raw_trailer +//------------------------------------------------------------------------- + +#undef IPS_OPT +#define IPS_OPT "http_raw_trailer" +#undef IPS_HELP +#define IPS_HELP "rule option to set the detection cursor to the unnormalized trailers" + +static Module* raw_trailer_mod_ctor() +{ + return new NHttpCursorModule(IPS_OPT, IPS_HELP, NHTTP_BUFFER_RAW_TRAILER, CAT_SET_OTHER, + PSI_RAW_TRAILER); +} + +static const IpsApi raw_trailer_api = +{ + { + PT_IPS_OPTION, + sizeof(IpsApi), + IPSAPI_VERSION, + 1, + API_RESERVED, + API_OPTIONS, + IPS_OPT, + IPS_HELP, + raw_trailer_mod_ctor, + NHttpCursorModule::mod_dtor + }, + OPT_TYPE_DETECTION, + 0, PROTO_BIT__TCP, + nullptr, + nullptr, + nullptr, + nullptr, + NHttpIpsOption::opt_ctor, + NHttpIpsOption::opt_dtor, + nullptr +}; + +//------------------------------------------------------------------------- +// plugins +//------------------------------------------------------------------------- + +SO_PUBLIC const BaseApi* snort_plugins[] = +{ + &uri_api.base, + &client_body_api.base, + &method_api.base, + &cookie_api.base, + &stat_code_api.base, + &stat_msg_api.base, + &raw_uri_api.base, + &raw_header_api.base, + &raw_cookie_api.base, + &version_api.base, + &header_api.base, + &trailer_api.base, + &raw_trailer_api.base, + nullptr +}; + diff --git a/src/service_inspectors/nhttp_inspect/ips_nhttp.h b/src/service_inspectors/nhttp_inspect/ips_nhttp.h new file mode 100644 index 000000000..564cad283 --- /dev/null +++ b/src/service_inspectors/nhttp_inspect/ips_nhttp.h @@ -0,0 +1,108 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015 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. +//-------------------------------------------------------------------------- +// ips_nhttp.h author Tom Peters + +#ifndef IPS_NHTTP_H +#define IPS_NHTTP_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "main/snort_types.h" +#include "profiler/profiler.h" +#include "framework/ips_option.h" +#include "framework/module.h" + +#include "nhttp_enum.h" + +enum PsIdx { PSI_URI, PSI_CLIENT_BODY, PSI_METHOD, PSI_COOKIE, PSI_STAT_CODE, PSI_STAT_MSG, + PSI_RAW_URI, PSI_RAW_HEADER, PSI_RAW_COOKIE, PSI_HEADER, PSI_VERSION, PSI_TRAILER, + PSI_RAW_TRAILER, PSI_MAX }; + +class NHttpCursorModule : public Module +{ +public: + NHttpCursorModule(const char* key_, const char* help, NHttpEnums::NHTTP_BUFFER buffer_index_, + CursorActionType cat_, PsIdx psi_) : Module(key_, help), key(key_), + buffer_index(buffer_index_), cat(cat_), psi(psi_) {} + NHttpCursorModule(const char* key_, const char* help, NHttpEnums::NHTTP_BUFFER buffer_index_, + CursorActionType cat_, PsIdx psi_, const Parameter params[]) : Module(key_, help, params), + key(key_), buffer_index(buffer_index_), cat(cat_), psi(psi_) {} + ProfileStats* get_profile() const override { return &http_ps[psi]; } + static void mod_dtor(Module* m) { delete m; } + bool begin(const char*, int, SnortConfig*) override; + bool set(const char*, Value&, SnortConfig*) override; + bool end(const char*, int, SnortConfig*) override; + +private: + friend class NHttpIpsOption; + static THREAD_LOCAL std::array http_ps; + + struct NHttpRuleParaList + { + public: + std::string field; // provide buffer containing specific header field + bool with_header; // provide buffer with a later section than it appears in + bool with_body; + bool with_trailer; + bool scheme; // provide buffer with one of the six URI subcomponents + bool host; + bool port; + bool path; + bool query; + bool fragment; + + void reset(); + }; + + const char* const key; + const NHttpEnums::NHTTP_BUFFER buffer_index; + const CursorActionType cat; + const PsIdx psi; + + NHttpRuleParaList para_list; + NHttpEnums::InspectSection inspect_section; + unsigned sub_id; +}; + +class NHttpIpsOption : public IpsOption +{ +public: + NHttpIpsOption(const NHttpCursorModule* cm) : IpsOption(cm->key), key(cm->key), + buffer_index(cm->buffer_index), cat(cm->cat), psi(cm->psi), + inspect_section(cm->inspect_section), sub_id(cm->sub_id) {} + CursorActionType get_cursor_type() const override { return cat; } + int eval(Cursor&, Packet*) override; + static IpsOption* opt_ctor(Module* m, OptTreeNode*) + { return new NHttpIpsOption((NHttpCursorModule*)m); } + static void opt_dtor(IpsOption* p) { delete p; } +private: + const char* const key; + const NHttpEnums::NHTTP_BUFFER buffer_index; + const CursorActionType cat; + const PsIdx psi; + const NHttpEnums::InspectSection inspect_section; + const unsigned sub_id; +}; + +#endif + diff --git a/src/service_inspectors/nhttp_inspect/nhttp_api.cc b/src/service_inspectors/nhttp_inspect/nhttp_api.cc index cb10a5ee9..d2b06830e 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_api.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_api.cc @@ -45,6 +45,9 @@ const char* NHttpApi::legacy_buffers[] = "http_stat_code", "http_stat_msg", "http_uri", + "http_version", + "http_trailer", + "http_raw_trailer", nullptr }; @@ -72,8 +75,8 @@ const InspectApi NHttpApi::nhttp_api = NHttpApi::nhttp_tterm, NHttpApi::nhttp_ctor, NHttpApi::nhttp_dtor, - nullptr, // ssn - nullptr // reset + nullptr, + nullptr }; #ifdef BUILDING_SO diff --git a/src/service_inspectors/nhttp_inspect/nhttp_api.h b/src/service_inspectors/nhttp_inspect/nhttp_api.h index e92c17a6d..d1fc7f600 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_api.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_api.h @@ -25,6 +25,7 @@ #include "framework/inspector.h" #include "nhttp_module.h" +#include "nhttp_flow_data.h" class NHttpApi { diff --git a/src/service_inspectors/nhttp_inspect/nhttp_enum.h b/src/service_inspectors/nhttp_inspect/nhttp_enum.h index 23a7fcb31..8fec1726c 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_enum.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_enum.h @@ -33,6 +33,7 @@ static const int FINAL_GZIP_BLOCK_SIZE = 2304; // compromise value, too big caus static const uint32_t NHTTP_GID = 219; static const int GZIP_WINDOWBITS = 31; static const int DEFLATE_WINDOWBITS = 15; +static const int MAX_FIELD_NAME_LENGTH = 100; // Field status codes for when no valid value is present in length or integer value. Positive // values are actual length or field value. @@ -49,9 +50,11 @@ enum SectionType { SEC_DISCARD = -19, SEC_ABORT = -18, SEC__NOTCOMPUTE=-14, SEC_ SEC_BODY_OLD }; // Message buffers available to clients +// This enum must remain synchronized with legacy_buffers[] enum NHTTP_BUFFER { NHTTP_BUFFER_CLIENT_BODY = 1, NHTTP_BUFFER_COOKIE, NHTTP_BUFFER_HEADER, NHTTP_BUFFER_METHOD, NHTTP_BUFFER_RAW_COOKIE, NHTTP_BUFFER_RAW_HEADER, NHTTP_BUFFER_RAW_URI, - NHTTP_BUFFER_STAT_CODE, NHTTP_BUFFER_STAT_MSG, NHTTP_BUFFER_URI, NHTTP_BUFFER_MAX }; + NHTTP_BUFFER_STAT_CODE, NHTTP_BUFFER_STAT_MSG, NHTTP_BUFFER_URI, NHTTP_BUFFER_VERSION, + NHTTP_BUFFER_TRAILER, NHTTP_BUFFER_RAW_TRAILER, NHTTP_BUFFER_MAX }; // Result of scanning by splitter enum ScanResult { SCAN_NOTFOUND, SCAN_FOUND, SCAN_FOUND_PIECE, SCAN_DISCARD, SCAN_DISCARD_PIECE, @@ -89,6 +92,12 @@ enum SchemeId { SCH__NOSOURCE=-16, SCH__NOTCOMPUTE=-14, SCH__INSUFMEMORY=-13, SC // Body compression tpyes enum CompressId { CMP_NONE=2, CMP_GZIP, CMP_DEFLATE }; +// Message section in which an IPS option provides the buffer +enum InspectSection { IS_NONE, IS_START, IS_HEADER, IS_BODY, IS_TRAILER }; + +// Part of the URI to be provided +enum UriComponent { UC_SCHEME = 1, UC_HOST, UC_PORT, UC_PATH, UC_QUERY, UC_FRAGMENT }; + // Every header we have ever heard of enum HeaderId { HEAD__NOTCOMPUTE=-14, HEAD__INSUFMEMORY=-13, HEAD__PROBLEMATIC=-12, HEAD__NOTPRESENT=-11, HEAD__OTHER=1, HEAD_CACHE_CONTROL, HEAD_CONNECTION, HEAD_DATE, diff --git a/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc b/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc index e6a4a25ea..7bcbdd123 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc @@ -22,6 +22,7 @@ #include #include +#include "main/snort_types.h" #include "stream/stream_api.h" #include "nhttp_enum.h" @@ -55,21 +56,18 @@ NHttpInspect::NHttpInspect(NHttpParaList params_) : params(params_) THREAD_LOCAL uint8_t NHttpInspect::body_buffer[MAX_OCTETS]; -THREAD_LOCAL NHttpMsgSection* NHttpInspect::latest_section = nullptr; +SO_PUBLIC THREAD_LOCAL NHttpMsgSection* NHttpInspect::latest_section = nullptr; bool NHttpInspect::get_buf(InspectionBuffer::Type ibt, Packet*, InspectionBuffer& b) { - switch ( ibt ) + switch (ibt) { case InspectionBuffer::IBT_KEY: - return get_buf(NHTTP_BUFFER_URI, nullptr, b); - + return get_buf(NHTTP_BUFFER_URI, 0, nullptr, b); case InspectionBuffer::IBT_HEADER: - return get_buf(NHTTP_BUFFER_HEADER, nullptr, b); - + return get_buf(NHTTP_BUFFER_HEADER, 0, nullptr, b); case InspectionBuffer::IBT_BODY: - return get_buf(NHTTP_BUFFER_CLIENT_BODY, nullptr, b); - + return get_buf(NHTTP_BUFFER_CLIENT_BODY, 0, nullptr, b); default: return false; } @@ -77,16 +75,23 @@ bool NHttpInspect::get_buf(InspectionBuffer::Type ibt, Packet*, InspectionBuffer bool NHttpInspect::get_buf(unsigned id, Packet*, InspectionBuffer& b) { + return get_buf(id, 0, nullptr, b); +} + +SO_PUBLIC bool NHttpInspect::get_buf(unsigned id, unsigned sub_id, Packet*, InspectionBuffer& b) +{ + // FIXIT-L some day we should add support for accessing the request headers, trailers, and + // version from the response side of the transaction. if (latest_section == nullptr) return false; - const Field& legacy = latest_section->get_legacy(id); + const Field& buffer = latest_section->get_classic_buffer(id, sub_id); - if (legacy.length <= 0) + if (buffer.length <= 0) return false; - b.data = legacy.start; - b.len = legacy.length; + b.data = buffer.start; + b.len = buffer.length; return true; } diff --git a/src/service_inspectors/nhttp_inspect/nhttp_inspect.h b/src/service_inspectors/nhttp_inspect/nhttp_inspect.h index 3d1bd8090..93bd6a2eb 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_inspect.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_inspect.h @@ -29,10 +29,10 @@ #include "nhttp_enum.h" #include "nhttp_field.h" #include "nhttp_module.h" +#include "nhttp_msg_section.h" #include "nhttp_stream_splitter.h" class NHttpApi; -class NHttpMsgSection; class NHttpInspect : public Inspector { @@ -41,8 +41,9 @@ public: NHttpInspect(NHttpParaList params_); - bool get_buf(InspectionBuffer::Type, Packet*, InspectionBuffer&) override; - bool get_buf(unsigned, Packet*, InspectionBuffer&) override; + bool get_buf(InspectionBuffer::Type ibt, Packet*, InspectionBuffer& b) override; + bool get_buf(unsigned id, Packet*, InspectionBuffer& b) override; + bool get_buf(unsigned id, unsigned sub_id, Packet*, InspectionBuffer& b); bool configure(SnortConfig*) override { return true; } void show(SnortConfig*) override { LogMessage("NHttpInspect\n"); } void eval(Packet*) override { } @@ -54,6 +55,8 @@ public: { return new NHttpStreamSplitter(is_client_to_server, this); } + static NHttpEnums::InspectSection get_latest_is() { return (latest_section != nullptr) ? + latest_section->get_inspection_section() : NHttpEnums::IS_NONE; } private: friend NHttpApi; friend NHttpStreamSplitter; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc index d5a99fb51..e9dc3fbba 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_body.cc @@ -27,6 +27,7 @@ #include "mime/file_mime_process.h" #include "nhttp_enum.h" +#include "nhttp_api.h" #include "nhttp_msg_request.h" #include "nhttp_msg_body.h" @@ -127,3 +128,18 @@ void NHttpMsgBody::do_file_processing() } } +#ifdef REG_TEST +// Common elements of print_section() for body sections +void NHttpMsgBody::print_body_section(FILE* output) +{ + detect_data.print(output, "Detect data"); + get_classic_buffer(NHTTP_BUFFER_CLIENT_BODY, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_CLIENT_BODY-1]); + if (g_file_data.len > 0) + { + Field(g_file_data.len, g_file_data.data).print(output, "file_data"); + } + NHttpMsgSection::print_message_wrapup(output); +} +#endif + diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_body.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_body.h index 978adb417..1b23c5f15 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_body.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_body.h @@ -32,6 +32,8 @@ class NHttpMsgBody : public NHttpMsgSection public: void analyze() override; const Field& get_detect_buf() const override { return detect_data; } + NHttpEnums::InspectSection get_inspection_section() const override + { return NHttpEnums::IS_BODY; } protected: NHttpMsgBody(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_, @@ -42,6 +44,10 @@ protected: int64_t body_octets; Field detect_data; Field file_data; + +#ifdef REG_TEST + void print_body_section(FILE* output); +#endif }; #endif diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_body_chunk.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_body_chunk.cc index c3e5293f4..cb636524f 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_body_chunk.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_body_chunk.cc @@ -56,8 +56,7 @@ void NHttpMsgBodyChunk::print_section(FILE* output) { NHttpMsgSection::print_message_title(output, "chunked body"); fprintf(output, "Cumulative octets %" PRIi64 "\n", body_octets); - detect_data.print(output, "Detect data"); - NHttpMsgSection::print_message_wrapup(output); + print_body_section(output); } #endif diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_body_cl.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_body_cl.cc index 434aaf177..63989a348 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_body_cl.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_body_cl.cc @@ -58,8 +58,7 @@ void NHttpMsgBodyCl::print_section(FILE* output) NHttpMsgSection::print_message_title(output, "Content-Length body"); fprintf(output, "Content-Length %" PRIi64 ", octets seen %" PRIi64 "\n", data_length, body_octets); - detect_data.print(output, "Detect data"); - NHttpMsgSection::print_message_wrapup(output); + print_body_section(output); } #endif diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_body_old.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_body_old.cc index 8d78173d9..4e989572b 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_body_old.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_body_old.cc @@ -45,10 +45,9 @@ void NHttpMsgBodyOld::update_flow() #ifdef REG_TEST void NHttpMsgBodyOld::print_section(FILE* output) { - NHttpMsgSection::print_message_title(output, "Old-style body"); + NHttpMsgSection::print_message_title(output, "old-style body"); fprintf(output, "octets seen %" PRIi64 "\n", body_octets); - detect_data.print(output, "Detect data"); - NHttpMsgSection::print_message_wrapup(output); + print_body_section(output); } #endif diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.h index 5a74afaf5..cb4b363eb 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_head_shared.h @@ -45,6 +45,11 @@ public: const Field& get_header_value_norm(NHttpEnums::HeaderId header_id); int get_header_count(NHttpEnums::HeaderId header_id) const; + // Tables of header field names and header value names + static const StrCode header_list[]; + static const StrCode trans_code_list[]; + static const StrCode content_code_list[]; + protected: NHttpMsgHeadShared(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_, NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_, @@ -64,11 +69,6 @@ protected: // Master table of known header fields and their normalization strategies. static const HeaderNormalizer* const header_norms[]; - // Tables of header field names and header value names - static const StrCode header_list[]; - static const StrCode trans_code_list[]; - static const StrCode content_code_list[]; - void parse_header_block(); uint32_t find_header_end(const uint8_t* buffer, int32_t length, int& num_seps); void parse_header_lines(); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc index 60ba63147..5b87294a7 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc @@ -26,6 +26,7 @@ #include "file_api/file_service.h" #include "file_api/file_flows.h" +#include "nhttp_api.h" #include "nhttp_msg_request.h" #include "nhttp_msg_header.h" @@ -215,6 +216,14 @@ void NHttpMsgHeader::print_section(FILE* output) { NHttpMsgSection::print_message_title(output, "header"); NHttpMsgHeadShared::print_headers(output); + get_classic_buffer(NHTTP_BUFFER_COOKIE, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_COOKIE-1]); + get_classic_buffer(NHTTP_BUFFER_HEADER, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_HEADER-1]); + get_classic_buffer(NHTTP_BUFFER_RAW_COOKIE, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_RAW_COOKIE-1]); + get_classic_buffer(NHTTP_BUFFER_RAW_HEADER, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_RAW_HEADER-1]); NHttpMsgSection::print_message_wrapup(output); } #endif diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_header.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_header.h index c559d0446..42741d911 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_header.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_header.h @@ -35,6 +35,8 @@ public: NHttpMsgHeader(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_, NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_, const NHttpParaList* params_); + NHttpEnums::InspectSection get_inspection_section() const override + { return NHttpEnums::IS_HEADER; } void update_flow() override; private: // Dummy configurations to support MIME processing diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc index 769939ed2..52f7669b0 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_request.cc @@ -25,6 +25,7 @@ #include "detection/detection_util.h" #include "nhttp_enum.h" +#include "nhttp_api.h" #include "nhttp_msg_request.h" #include "nhttp_msg_header.h" @@ -192,6 +193,14 @@ void NHttpMsgRequest::print_section(FILE* output) uri->get_fragment().print(output, "Fragment"); uri->get_norm_fragment().print(output, "Normalized Fragment"); } + get_classic_buffer(NHTTP_BUFFER_METHOD, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_METHOD-1]); + get_classic_buffer(NHTTP_BUFFER_RAW_URI, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_RAW_URI-1]); + get_classic_buffer(NHTTP_BUFFER_URI, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_URI-1]); + get_classic_buffer(NHTTP_BUFFER_VERSION, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_VERSION-1]); NHttpMsgSection::print_message_wrapup(output); } diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_request.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_request.h index ccc310285..d83c6831d 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_request.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_request.h @@ -42,6 +42,7 @@ public: const Field& get_method() { return method; } const Field& get_uri(); const Field& get_uri_norm_legacy(); + NHttpUri* get_nhttp_uri() { return uri; } #ifdef REG_TEST void print_section(FILE* output) override; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc index 896d8116a..16332690c 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.cc @@ -23,11 +23,12 @@ #include "nhttp_enum.h" #include "nhttp_transaction.h" -#include "nhttp_api.h" #include "nhttp_msg_section.h" #include "nhttp_msg_request.h" #include "nhttp_msg_status.h" #include "nhttp_msg_head_shared.h" +#include "nhttp_msg_header.h" +#include "nhttp_msg_trailer.h" #include "nhttp_msg_body.h" using namespace NHttpEnums; @@ -78,10 +79,9 @@ void NHttpMsgSection::update_depth() const } } -const Field& NHttpMsgSection::get_legacy(unsigned buffer_id) +const Field& NHttpMsgSection::get_classic_buffer(unsigned id, unsigned sub_id) { - // When current section is trailers, that is what will be used for header and cookie buffers. - switch (buffer_id) + switch (id) { case NHTTP_BUFFER_CLIENT_BODY: { @@ -96,16 +96,24 @@ const Field& NHttpMsgSection::get_legacy(unsigned buffer_id) // Currently "normalization" is aggregation of multiple cookies. That is correct for raw // cookies and all there is for normalized cookies. { - NHttpMsgHeadShared* header = transaction->get_latest_header(source_id); + NHttpMsgHeader* header = transaction->get_header(source_id); if (header == nullptr) return Field::FIELD_NULL; HeaderId cookie_head = (source_id == SRC_CLIENT) ? HEAD_COOKIE : HEAD_SET_COOKIE; return header->get_header_value_norm(cookie_head); } case NHTTP_BUFFER_HEADER: + case NHTTP_BUFFER_TRAILER: { - NHttpMsgHeadShared* header = transaction->get_latest_header(source_id); - return (header != nullptr) ? header->get_headers() : Field::FIELD_NULL; + // FIXIT-L Someday want to be able to return field name or raw field value + NHttpMsgHeadShared* const header = (id == NHTTP_BUFFER_HEADER) ? + (NHttpMsgHeadShared*)transaction->get_header(source_id) : + (NHttpMsgHeadShared*)transaction->get_trailer(source_id); + if (header == nullptr) + return Field::FIELD_NULL; + if (sub_id == 0) + return header->get_headers(); + return header->get_header_value_norm((HeaderId)sub_id); } case NHTTP_BUFFER_METHOD: { @@ -114,14 +122,9 @@ const Field& NHttpMsgSection::get_legacy(unsigned buffer_id) } case NHTTP_BUFFER_RAW_HEADER: { - NHttpMsgHeadShared* header = transaction->get_latest_header(source_id); + NHttpMsgHeader* header = transaction->get_header(source_id); return (header != nullptr) ? header->get_headers() : Field::FIELD_NULL; } - case NHTTP_BUFFER_RAW_URI: - { - NHttpMsgRequest* request = transaction->get_request(); - return (request != nullptr) ? request->get_uri() : Field::FIELD_NULL; - } case NHTTP_BUFFER_STAT_CODE: { NHttpMsgStatus* status = transaction->get_status(); @@ -132,10 +135,46 @@ const Field& NHttpMsgSection::get_legacy(unsigned buffer_id) NHttpMsgStatus* status = transaction->get_status(); return (status != nullptr) ? status->get_reason_phrase() : Field::FIELD_NULL; } + case NHTTP_BUFFER_RAW_URI: case NHTTP_BUFFER_URI: { + const bool raw = (id == NHTTP_BUFFER_RAW_URI); NHttpMsgRequest* request = transaction->get_request(); - return (request != nullptr) ? request->get_uri_norm_legacy() : Field::FIELD_NULL; + if (request == nullptr) + return Field::FIELD_NULL; + if (sub_id == 0) + return raw ? request->get_uri() : request->get_uri_norm_legacy(); + NHttpUri* const uri = request->get_nhttp_uri(); + if (uri == nullptr) + return Field::FIELD_NULL; + switch ((UriComponent)sub_id) + { + case UC_SCHEME: + return uri->get_scheme(); + case UC_HOST: + return raw ? uri->get_host() : uri->get_norm_host(); + case UC_PORT: + return uri->get_port(); + case UC_PATH: + return raw ? uri->get_path() : uri->get_norm_path(); + case UC_QUERY: + return raw ? uri->get_query() : uri->get_norm_query(); + case UC_FRAGMENT: + return raw ? uri->get_fragment() : uri->get_norm_fragment(); + } + assert(false); + return Field::FIELD_NULL; + } + case NHTTP_BUFFER_VERSION: + { + NHttpMsgStart* start = (source_id == SRC_CLIENT) ? + (NHttpMsgStart*)transaction->get_request() : (NHttpMsgStart*)transaction->get_status(); + return (start != nullptr) ? start->get_version() : Field::FIELD_NULL; + } + case NHTTP_BUFFER_RAW_TRAILER: + { + NHttpMsgTrailer* trailer = transaction->get_trailer(source_id); + return (trailer != nullptr) ? trailer->get_headers() : Field::FIELD_NULL; } default: assert(false); @@ -153,17 +192,9 @@ void NHttpMsgSection::print_message_title(FILE* output, const char* title) const void NHttpMsgSection::print_message_wrapup(FILE* output) { - fprintf(output, "Infractions: %016" PRIx64 " %016" PRIx64 ", Events: %016" PRIx64 " %016" PRIx64 ", TCP Close: %s\n", - infractions.get_raw2(), infractions.get_raw(), events.get_raw2(), events.get_raw(), tcp_close ? "True" : "False"); - for (unsigned k=1; k < NHTTP_BUFFER_MAX; k++) - { - get_legacy(k).print(output, NHttpApi::legacy_buffers[k-1]); - } - if (g_file_data.len > 0) - { - Field(g_file_data.len, g_file_data.data).print(output, "file_data"); - } - fprintf(output, "\n"); + fprintf(output, "Infractions: %016" PRIx64 " %016" PRIx64 ", Events: %016" PRIx64 " %016" + PRIx64 ", TCP Close: %s\n\n", infractions.get_raw2(), infractions.get_raw(), + events.get_raw2(), events.get_raw(), tcp_close ? "True" : "False"); session_data->show(output); fprintf(output, "\n"); } diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h index 61ee79281..4a8058dcc 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_section.h @@ -38,6 +38,7 @@ class NHttpMsgSection { public: virtual ~NHttpMsgSection() { if (delete_msg_on_destruct) delete[] msg_text.start; } + virtual NHttpEnums::InspectSection get_inspection_section() const = 0; // Minimum necessary processing for every message virtual void analyze() = 0; @@ -45,7 +46,7 @@ public: // Manages the splitter and communication between message sections virtual void update_flow() = 0; - const Field& get_legacy(unsigned buffer_id); + const Field& get_classic_buffer(unsigned id, unsigned sub_id); // Provide buffer to be sent to detection virtual const Field& get_detect_buf() const { return msg_text; } diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_start.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_start.h index bc44952d6..e36a9bdbe 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_start.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_start.h @@ -31,6 +31,9 @@ class NHttpMsgStart : public NHttpMsgSection { public: void analyze() override; + const Field& get_version() const { return version; } + NHttpEnums::InspectSection get_inspection_section() const override + { return NHttpEnums::IS_START; } protected: NHttpMsgStart(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_, diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc index d147ec06f..357f72f54 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_status.cc @@ -25,6 +25,7 @@ #include "detection/detection_util.h" #include "nhttp_enum.h" +#include "nhttp_api.h" #include "nhttp_msg_status.h" #include "nhttp_msg_header.h" @@ -170,6 +171,12 @@ void NHttpMsgStatus::print_section(FILE* output) fprintf(output, "Version Id: %d\n", version_id); fprintf(output, "Status Code Num: %d\n", status_code_num); reason_phrase.print(output, "Reason Phrase"); + get_classic_buffer(NHTTP_BUFFER_STAT_CODE, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_STAT_CODE-1]); + get_classic_buffer(NHTTP_BUFFER_STAT_MSG, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_STAT_MSG-1]); + get_classic_buffer(NHTTP_BUFFER_VERSION, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_VERSION-1]); NHttpMsgSection::print_message_wrapup(output); } #endif diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc index 9f8517970..7059ee247 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.cc @@ -24,6 +24,7 @@ #include "detection/detection_util.h" #include "nhttp_enum.h" +#include "nhttp_api.h" #include "nhttp_msg_trailer.h" using namespace NHttpEnums; @@ -49,6 +50,10 @@ void NHttpMsgTrailer::print_section(FILE* output) { NHttpMsgSection::print_message_title(output, "trailer"); NHttpMsgHeadShared::print_headers(output); + get_classic_buffer(NHTTP_BUFFER_TRAILER, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_TRAILER-1]); + get_classic_buffer(NHTTP_BUFFER_RAW_TRAILER, 0).print(output, + NHttpApi::legacy_buffers[NHTTP_BUFFER_RAW_TRAILER-1]); NHttpMsgSection::print_message_wrapup(output); } #endif diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.h index 71d26f4e7..8bc46a1c0 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_trailer.h @@ -32,6 +32,8 @@ public: NHttpMsgTrailer(const uint8_t* buffer, const uint16_t buf_size, NHttpFlowData* session_data_, NHttpEnums::SourceId source_id_, bool buf_owner, Flow* flow_, const NHttpParaList* params_); + NHttpEnums::InspectSection get_inspection_section() const override + { return NHttpEnums::IS_TRAILER; } void update_flow() override; #ifdef REG_TEST diff --git a/src/service_inspectors/nhttp_inspect/nhttp_str_to_code.cc b/src/service_inspectors/nhttp_inspect/nhttp_str_to_code.cc index 7dc65db50..6b64704ad 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_str_to_code.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_str_to_code.cc @@ -19,11 +19,13 @@ #include +#include "main/snort_types.h" + #include "nhttp_enum.h" #include "nhttp_str_to_code.h" // Need to replace this simple algorithm for better performance FIXIT-P -int32_t str_to_code(const uint8_t* text, const int32_t text_len, const StrCode table[]) +SO_PUBLIC int32_t str_to_code(const uint8_t* text, const int32_t text_len, const StrCode table[]) { for (int32_t k=0; table[k].name != nullptr; k++) { diff --git a/src/service_inspectors/nhttp_inspect/nhttp_tables.cc b/src/service_inspectors/nhttp_inspect/nhttp_tables.cc index 3cf403d3b..839a45a7b 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_tables.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_tables.cc @@ -101,7 +101,7 @@ const StrCode NHttpUri::scheme_list[] = { 0, nullptr } }; -const StrCode NHttpMsgHeadShared::header_list[] = +SO_PUBLIC const StrCode NHttpMsgHeadShared::header_list[] = { { HEAD_CACHE_CONTROL, "cache-control" }, { HEAD_CONNECTION, "connection" }, diff --git a/src/service_inspectors/nhttp_inspect/nhttp_transaction.h b/src/service_inspectors/nhttp_inspect/nhttp_transaction.h index 00fb88ff5..64c1b8b55 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_transaction.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_transaction.h @@ -56,13 +56,6 @@ public: NHttpMsgBody* get_body() const { return latest_body; } void set_body(NHttpMsgBody* latest_body_) { latest_body = latest_body_; } - // Convenience method - NHttpMsgHeadShared* get_latest_header(NHttpEnums::SourceId source_id) - { - return (trailer[source_id] != nullptr) ? (NHttpMsgHeadShared*)trailer[source_id] : - (NHttpMsgHeadShared*)header[source_id]; - } - private: NHttpTransaction() = default;