set (VERSION_MAJOR 3)
set (VERSION_MINOR 0)
set (VERSION_BUILD 0)
-set (VERSION_RELEASE a4)
set (VERSION
- "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_BUILD}-${VERSION_RELEASE}")
+ "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_BUILD}")
set (INCLUDE_SUFFIX "${CMAKE_PROJECT_NAME}")
set (INCLUDE_INSTALL_PATH "include/${INCLUDE_SUFFIX}")
# initialization
#--------------------------------------------------------------------------
-AC_INIT([snort],[3.0.0-a4],[snort-team@cisco.com])
+AC_INIT([snort],[3.0.0],[snort-team@cisco.com])
AC_PREREQ([2.69])
AC_CONFIG_SRCDIR([src/main.h])
* *enum*: a string selected from the given range
* *implied*: an IPS rule option that takes no value but means true
* *int*: a whole number in the given range
+* *interval*: a set of ints (see below)
* *ip4*: an IP4 address or CIDR
* *mac*: an ethernet address with the form 01:02:03:04:05:06
* *multi*: one or more space separated strings from the given range
there is no hard limit.
* bit_list is typically used to store a set of byte, port, or VLAN ID
values.
+* interval takes the form [operator]i, j<>k, or j<=>k where i,j,k are
+ integers and operator is one of =, !, != (same as !), <, <=, >, >=.
+ j<>k means j < int < k and j<=>k means j <= int <= k.
snort -c $my_path/etc/snort/snort.lua -r /path/to/my.pcap -A alert_full
+Capture separate stdout, stderr, and stdlog files (out has startup and
+shutdown output, err has warnings and errors, and log has alerts):
+
+ snort -c $my_path/etc/snort/snort.lua -r /path/to/my.pcap -A csv \
+ 1>out 2>err 3>log
+
Add or modify a configuration from the command line using the "--lua" option:
snort -c $my_path/etc/snort/snort.lua -r /path/to/my.pcap -A cmg \
// module
//-------------------------------------------------------------------------
+#define RANGE "1:"
+
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
"check if packet number is in given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
if ( !v.is("~range") )
return false;
- return data.validate(v.get_string(), "0:");
+ return data.validate(v.get_string(), RANGE);
}
//-------------------------------------------------------------------------
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "check if urgent offset is min<>max | <max | >min, range is " RANGE },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if tcp urgent offset is in given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
return true;
}
+// interval is a special case because we support a<>b and a<=>b for convenience.
+// if not for that, then dsize:1<>10; would be dsize:>1, <10; (2 parameters) but
+// that is the same as dsize:>1; dsize:<10; which is arguably easier to read and
+// not significantly worse performance and which we also, obviously, already
+// support. and note that <> and <=> are non-standard Snort-isms. so, we wind
+// up with a multivalued parameter which is best handled as a string. validation
+// must be done by the user. the advantage of using an interval instead of string
+// is that we can document the type in one place and the parameters can focus on
+// their actual, specific semantics instead of trying to explain the syntax. this
+// also ensures that an int-type range is not applied to a string.
+
+static bool valid_interval(Value&, const char*)
+{ return true; }
+
// FIXIT-L allow multiple , separated ranges
static bool valid_real(Value& v, const char* r)
{
// fall through
case PT_INT:
return valid_int(v, (const char*)range);
+ case PT_INTERVAL:
+ return valid_interval(v, (const char*)range);
case PT_REAL:
return valid_real(v, (const char*)range);
static const char* const pt2str[Parameter::PT_MAX] =
{
"table", "list", "dynamic",
- "bool", "int", "real", "port",
+ "bool", "int", "interval", "real", "port",
"string", "select", "multi", "enum",
"mac", "ip4", "addr",
"bit_list", "addr_list", "implied"
PT_DYNAMIC, // range is RangeQuery*
PT_BOOL, // if you are reading this, get more coffee
PT_INT, // signed 64 bits or less determined by range
+ PT_INTERVAL, // string that defines an interval, bounds within range
PT_REAL, // double
PT_PORT, // 0 to 64K-1 unless specified otherwise
PT_STRING, // any string less than len chars
// module
//-------------------------------------------------------------------------
+#define RANGE "0:"
+
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
"check if tcp ack value is 'value | min<>max | <max | >min'" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
if ( !v.is("~range") )
return false;
- return data.validate(v.get_string(), "0:");
+ return data.validate(v.get_string(), RANGE);
}
//-------------------------------------------------------------------------
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "len | min<>max | <max | >min, range is " RANGE },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check that lenght of current buffer is in given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "check if packet payload size is 'size | min<>max | <max | >min', range is " RANGE },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if packet payload size is in the given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "check if ip fragment offset value is 'value | min<>max | <max | >min', range is " RANGE },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if ip fragment offset is in given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "check if icmp id is 'id | min<>max | <max | >min', range is " RANGE },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if icmp id is in given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "check if icmp sequence number is 'seq | min<>max | <max | >min', range is " RANGE },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if icmp sequence number is in given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "check if ICMP code is 'code | min<>max | <max | >min', range is " RANGE },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if icmp code is in given range is" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
// module
//-------------------------------------------------------------------------
+#define RANGE "0:"
+
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "check if the IP ID is 'id | min<>max | <max | >min'" },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if the ip id is in the given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
if ( !v.is("~range") )
return false;
- return data.validate(v.get_string(), "0:");
+ return data.validate(v.get_string(), RANGE);
}
//-------------------------------------------------------------------------
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "check if icmp type is 'type | min<>max | <max | >min', range is " RANGE },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if icmp type is in given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
// module
//-------------------------------------------------------------------------
+#define RANGE "0:"
+
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "check if tcp sequence number value is 'value | min<>max | <max | >min'" },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if tcp sequence number is in given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
if ( !v.is("~range") )
return false;
- return data.validate(v.get_string(), "0:");
+ return data.validate(v.get_string(), RANGE);
}
//-------------------------------------------------------------------------
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "check if ip tos value is 'value | min<>max | <max | >min', range is " RANGE },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if ip tos is in given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "check if ip ttl field value is 'value | min<>max | <max | >min', range is " RANGE },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if ip ttl is in the given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "check if tcp window field size is 'size | min<>max | <max | >min', range is " RANGE },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if tcp window size is in given range" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
return ponew;
}
-/*
- *
- * Verify all rules in 'po' list are in 'po2' hash
- *
- * return 0 - OK
- * !0 - a rule in po is not in po2
- */
-static int _po2_include_po_rules(PortObject2* po2, PortObject* po)
-{
- SF_LNODE* rpos;
-
- /* get each rule in po */
- for ( int* pid = (int*)sflist_first(po->rule_list, &rpos);
- pid;
- pid = (int*)sflist_next(&rpos) )
- {
- /* find it in po2 */
- int* id = (int*)sfghash_find(po2->rule_hash, pid);
-
- /* make sure it's in po2 */
- if ( !id )
- return 1; /* error */
- }
-
- return 0;
-}
-
static int PortTableCompileMergePortObjects(PortTable* p)
{
DebugMessage(DEBUG_PORTLISTS, "***\n***Merging PortObjects->PortObjects2\n***\n");
return 0;
}
+#ifdef DEBUG
// consistency check - part 1
// make sure each port is only in one composite port object
-
static bool PortTableConsistencyCheck(PortTable* p)
{
std::unique_ptr<char[]> upA(new char[SFPO_MAX_PORTS]);
return true;
}
+/*
+ * Verify all rules in 'po' list are in 'po2' hash
+ * return 0 - OK; !0 - a rule in po is not in po2
+ */
+static int _po2_include_po_rules(PortObject2* po2, PortObject* po)
+{
+ SF_LNODE* rpos;
+
+ /* get each rule in po */
+ for ( int* pid = (int*)sflist_first(po->rule_list, &rpos);
+ pid;
+ pid = (int*)sflist_next(&rpos) )
+ {
+ /* find it in po2 */
+ int* id = (int*)sfghash_find(po2->rule_hash, pid);
+
+ /* make sure it's in po2 */
+ if ( !id )
+ return 1; /* error */
+ }
+
+ return 0;
+}
+
// consistency check - part 2
/*
* This phase checks the Input port object rules/ports against
return true;
}
+#endif
//-------------------------------------------------------------------------
// PortTable - public
DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS, "Done\n"); fflush(stdout); );
+#ifdef DEBUG
assert(PortTableConsistencyCheck(p));
assert(PortTableConsistencyCheck2(p));
+#endif
return 0;
}
// dce2_iface module
//-------------------------------------------------------------------------
+#define RANGE "0:"
+
static const Parameter s_params[] =
{
{ "uuid", Parameter::PT_STRING, nullptr, nullptr,
"match given dcerpc uuid" },
- { "version",Parameter::PT_STRING, nullptr, nullptr,
+ { "version",Parameter::PT_INTERVAL, RANGE, nullptr,
"interface version" },
{ "any_frag", Parameter::PT_IMPLIED, nullptr, nullptr,
"match on any fragment" },
bool Dce2IfaceModule::set(const char*, Value& v, SnortConfig*)
{
if ( v.is("version") )
- return version.validate(v.get_string(), "0:");
+ return version.validate(v.get_string(), RANGE);
else if ( v.is("any_frag") )
any_frag = true;
else if ( v.is("uuid") )
// stream_size module
//-------------------------------------------------------------------------
+#define RANGE "0:"
+
static const Parameter s_params[] =
{
- { "~range", Parameter::PT_STRING, nullptr, nullptr,
- "size for comparison" },
+ { "~range", Parameter::PT_INTERVAL, RANGE, nullptr,
+ "check if the stream size is in the given range" },
{ "~direction", Parameter::PT_ENUM, "either|to_server|to_client|both", nullptr,
"compare applies to the given direction(s)" },
bool SizeModule::set(const char*, Value& v, SnortConfig*)
{
if ( v.is("~range") )
- return ssod.validate(v.get_string(), "0:");
+ return ssod.validate(v.get_string(), RANGE);
else if ( v.is("~direction") )
direction = v.get_long();
{
namespace
{
- //FIXIT-L add when avaiable
+ //FIXIT-L add when available
static std::string header = "output sf_unified2: ";
template<std::string* header_text>
rule_convert_comma_list.cc
rule_dce_iface.cc
rule_dnp3_obj.cc
+ rule_dsize.cc
rule_file_data.cc
rule_http_encode.cc
rule_isdataat.cc
rule_convert_comma_list.cc \
rule_dce_iface.cc \
rule_dnp3_obj.cc \
+rule_dsize.cc \
rule_file_data.cc \
rule_http_encode.cc \
rule_isdataat.cc \
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2017-2017 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.
+//--------------------------------------------------------------------------
+// rule_dsize.cc author Russ Combs <rucombs@cisco.com>
+// (based on the amazing original work by Josh)
+
+#include <string>
+//#include <cstdlib>
+
+#include "conversion_state.h"
+#include "helpers/converter.h"
+#include "rule_states/rule_api.h"
+#include "helpers/s2l_util.h"
+
+namespace rules
+{
+namespace
+{
+class Dsize : public ConversionState
+{
+public:
+ Dsize(Converter& c) : ConversionState(c) { }
+ virtual ~Dsize() { }
+ virtual bool convert(std::istringstream& data);
+};
+} // namespace
+
+bool Dsize::convert(std::istringstream& data_stream)
+{
+ std::string args = util::get_rule_option_args(data_stream);
+ size_t ltgt = args.find("<>");
+
+ if ( ltgt != std::string::npos )
+ {
+ rule_api.add_comment("dsize: option change: '<>' --> '<=>'");
+ args.insert(ltgt+1, "=");
+ }
+ rule_api.add_option("dsize", args);
+ return set_next_rule_state(data_stream);
+}
+
+/**************************
+ ******* A P I ***********
+ **************************/
+
+static ConversionState* dsize_ctor(Converter& c)
+{ return new Dsize(c); }
+
+static const ConvertMap rule_dsize =
+{
+ "dsize",
+ dsize_ctor,
+};
+
+const ConvertMap* dsize_map = &rule_dsize;
+} // namespace rules
+
const ConvertMap* flowbits_map = &rule_flowbits;
/************************************
- ********* D S I Z E **************
- ************************************/
-
-static const std::string dsize = "dsize";
-static const ConvertMap rule_dsize =
-{
- dsize,
- unchanged_rule_ctor<& dsize>,
-};
-
-const ConvertMap* dsize_map = &rule_dsize;
-
-/************************************
- ********* D S I Z E **************
+ ************ FRABGITS ************
************************************/
static const std::string fragbits = "fragbits";