# RUN SNORT
-First set up the environment:
+Here are some examples.
-```shell
-export SNORT_LUA_PATH=$my_path/etc/snort
-```
-
-Then give it a go:
-
-* Snort++ provides lots of help from the command line. Here are some examples:
+* Snort++ provides lots of help from the command line, including:
```shell
$my_path/bin/snort --help
Below is a minimal Snort configuration that is sufficient to block flows
based on a specific HTTP header:
- dir = os.getenv('SNORT_LUA_PATH')
-
- if ( not dir ) then
- dir = '.'
- end
-
- dofile(dir .. '/snort_defaults.lua')
-
-
- local_rules =
- [[
- block http ( msg:"openAppId: test content match for app http";
- content:"X-Header: malicious"; sid:18760; rev:4; )
- ]]
-
stream = { }
stream_tcp = { }
appid = { }
+ local_rules =
+ [[
+ block http ( msg:"openAppId: test content match for app http";
+ content:"X-Header: malicious"; sid:18760; rev:4; )
+ ]]
+
ips =
{
rules = local_rules,
Lua conf. Unknown symbols not in SNORT_IGNORE will cause warnings with
--warn-unknown or fatals with --warn-unknown --pedantic.
-* *SNORT_LUA_PATH*: an optional path where Snort can find supplemental conf
- files such as classification.lua.
-
* *SNORT_PROMPT*: the character sequence that is printed at startup,
shutdown, and in the shell. The default is the mini-pig: o")~ .
based but with syntax tweaks, so your 2.X rules must be fixed up. However,
snort2lua will help you convert your conf and rules to the new format.
-==== Environment
-
-SNORT_LUA_PATH must be set to load auxiliary configuration files if you use
-the default snort.lua. For example:
-
- export SNORT_LUA_PATH=$install_prefix/etc/snort
-
==== Command Line
A simple command line might look like this:
=== Running
-First set up the environment:
-
- export SNORT_LUA_PATH=$my_path/etc/snort/
-
-Then give it a go:
+Examples:
* Get some help:
is in your PATH.
-=== Environment
-
-SNORT_LUA_PATH is used by Snort to load supplemental configuration files.
-
- export SNORT_LUA_PATH=$my_path/etc/snort
-
-
=== Help
Print the help summary:
set (LUA_SCRIPTS
file_magic.lua
inline.lua
+ snort.lua
snort_defaults.lua
talos.lua
)
-configure_file(snort.lua.in
- snort.lua)
-
-install (FILES ${LUA_SCRIPTS} ${CMAKE_CURRENT_BINARY_DIR}/snort.lua
+install (FILES ${LUA_SCRIPTS}
DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}/snort"
)
-- many can be used with defaults w/o any explicit configuration.
-- use this conf as a template for your specific configuration.
--- 1. configure environment
--- 2. configure defaults
--- 3. configure inspection
--- 4. configure bindings
--- 5. configure performance
--- 6. configure detection
--- 7. configure filters
--- 8. configure outputs
--- 9. configure tweaks
+-- 1. configure defaults
+-- 2. configure inspection
+-- 3. configure bindings
+-- 4. configure performance
+-- 5. configure detection
+-- 6. configure filters
+-- 7. configure outputs
+-- 8. configure tweaks
---------------------------------------------------------------------------
--- 1. configure environment
----------------------------------------------------------------------------
-
--- given:
--- export DIR=/install/path
--- configure --prefix=$DIR
--- make install
-
--- then:
--- export SNORT_LUA_PATH=$DIR/etc/snort
-
--- this depends on SNORT_LUA_PATH
--- where to find other config files
-conf_dir = os.getenv('SNORT_LUA_PATH')
-
-if ( not conf_dir ) then
- conf_dir = '${CMAKE_INSTALL_FULL_SYSCONFDIR}/snort'
-end
-
----------------------------------------------------------------------------
--- 2. configure defaults
+-- 1. configure defaults
---------------------------------------------------------------------------
-- HOME_NET and EXTERNAL_NET must be set now
-- (leave as "any" in most situations)
EXTERNAL_NET = 'any'
-dofile(conf_dir .. '/snort_defaults.lua')
-dofile(conf_dir .. '/file_magic.lua')
+include 'snort_defaults.lua'
+include 'file_magic.lua'
---------------------------------------------------------------------------
--- 3. configure inspection
+-- 2. configure inspection
---------------------------------------------------------------------------
-- mod = { } uses internal defaults
--]]
---------------------------------------------------------------------------
--- 4. configure bindings
+-- 3. configure bindings
---------------------------------------------------------------------------
wizard = default_wizard
}
---------------------------------------------------------------------------
--- 5. configure performance
+-- 4. configure performance
---------------------------------------------------------------------------
-- use latency to monitor / enforce packet and rule thresholds
--perf_monitor = { }
---------------------------------------------------------------------------
--- 6. configure detection
+-- 5. configure detection
---------------------------------------------------------------------------
references = default_references
-- rewrite = { }
---------------------------------------------------------------------------
--- 7. configure filters
+-- 6. configure filters
---------------------------------------------------------------------------
-- below are examples of filters
--]]
---------------------------------------------------------------------------
--- 8. configure outputs
+-- 7. configure outputs
---------------------------------------------------------------------------
-- event logging
--file_log = { }
---------------------------------------------------------------------------
--- 9. configure tweaks
+-- 8. configure tweaks
---------------------------------------------------------------------------
if ( tweaks ~= nil ) then
if ( file_line )
snort::LogMessage(file, "%s: %s:%d %s\n", type, file_name, file_line, msg);
+
+ else if ( file_name )
+ snort::LogMessage(file, "%s: %s: %s\n", type, file_name, msg);
+
else
snort::LogMessage(file, "%s: %s\n", type, msg);
}
std::string include;
std::string rules;
+ std::string parse_from;
uint32_t var_id;
#include "main/policy.h"
#include "main/snort_config.h"
#include "managers/module_manager.h"
+#include "parser/parse_conf.h"
#include "parser/parser.h"
using namespace snort;
if (is_fatal)
FatalError("can't load %s: %s\n", file, lua_tostring(L, -1));
else
- {
ParseError("can't load %s: %s\n", file, lua_tostring(L, -1));
- return false;
- }
+ return false;
}
if ( tweaks and *tweaks )
{
lua_atpanic(lua, Shell::panic);
luaL_openlibs(lua);
- char pwd[PATH_MAX];
- parse_from = getcwd(pwd, sizeof(pwd));
-
if ( s )
- set_file(s);
+ file = s;
- loaded = false;
+ parse_from = get_parse_file();
+ loaded = false;
load_string(lua, ModuleManager::get_lua_bootstrap());
if ( load_defaults )
void Shell::set_file(const char* s)
{
- assert(file.empty());
-
- if ( s && s[0] != '/' && parsing_follows_files )
- {
- file += parse_from;
- file += '/';
- }
-
- file += s;
+ file = s;
}
void Shell::set_overrides(const char* s)
set_network_policy(pt->network);
}
- const char* base_name = push_relative_path(file.c_str());
- if(! config_lua(lua, base_name, overrides, sc->tweaks.c_str(), is_fatal))
+ std::string path = parse_from;
+ const char* code = get_config_file(file.c_str(), path);
+
+ if ( !code )
+ {
+ if ( is_fatal )
+ FatalError("can't find %s\n", file.c_str());
+ else
+ ParseError("can't find %s\n", file.c_str());
+ return false;
+ }
+
+ push_parse_location(code, path.c_str(), file.c_str(), 0);
+
+ if ( !config_lua(lua, path.c_str(), overrides, sc->tweaks.c_str(), is_fatal) )
return false;
set_default_policy(sc);
ModuleManager::set_config(nullptr);
loaded = true;
- pop_relative_path();
+ pop_parse_location();
return true;
}
const char* get_file() const
{ return file.c_str(); }
+ const char* get_from() const
+ { return parse_from.c_str(); }
+
bool get_loaded() const
{ return loaded; }
RUN_FLAG__READ = 0x00000001,
RUN_FLAG__DAEMON = 0x00000002,
RUN_FLAG__NO_PROMISCUOUS = 0x00000004,
- /* UNUSED 0x00000008 */
+ RUN_FLAG__NO_OVERRIDES = 0x00000008,
RUN_FLAG__INLINE = 0x00000010,
RUN_FLAG__STATIC_HASH = 0x00000020,
RUN_FLAG__INLINE_TEST = 0x00004000,
RUN_FLAG__PCAP_SHOW = 0x00008000,
- /* UNUSED 0x00010000 */
+ RUN_FLAG__SHOW_FILE_CODES = 0x00010000,
RUN_FLAG__PAUSE = 0x00020000,
RUN_FLAG__NO_PCRE = 0x00040000,
/* If stream is configured, the STATEFUL flag is set. This is
static bool inline_test_mode()
{ return snort::get_ips_policy()->policy_mode == POLICY_MODE__INLINE_TEST; }
+ static bool show_file_codes()
+ { return get_conf()->run_flags & RUN_FLAG__SHOW_FILE_CODES; }
+
+ static bool allow_overrides()
+ { return !(get_conf()->run_flags & RUN_FLAG__NO_OVERRIDES); }
+
static bool adaptor_inline_mode()
{ return get_conf()->run_flags & RUN_FLAG__INLINE; }
{ "--dirty-pig", Parameter::PT_IMPLIED, nullptr, nullptr,
"don't flush packets on shutdown" },
+ { "--disable-overrides", Parameter::PT_IMPLIED, nullptr, nullptr,
+ "do not first look for files relative to the working directory" },
+
{ "--dump-builtin-rules", Parameter::PT_STRING, "(optional)", nullptr,
"[<module prefix>] output stub rules for selected modules" },
"<count> pause after count packets", },
#endif
- { "--parsing-follows-files", Parameter::PT_IMPLIED, nullptr, nullptr,
- "parse relative paths from the perspective of the current configuration file" },
-
{ "--pcap-file", Parameter::PT_STRING, nullptr, nullptr,
"<file> file that contains a list of pcaps to read - read mode is implied" },
{ "--pedantic", Parameter::PT_IMPLIED, nullptr, nullptr,
"warnings are fatal" },
+#ifdef PIGLET
+ { "--piglet", Parameter::PT_IMPLIED, nullptr, nullptr,
+ "enable piglet test harness mode" },
+#endif
+
{ "--plugin-path", Parameter::PT_STRING, nullptr, nullptr,
"<path> where to find plugins" },
"enable the interactive command line", },
#endif
-#ifdef PIGLET
- { "--piglet", Parameter::PT_IMPLIED, nullptr, nullptr,
- "enable piglet test harness mode" },
-#endif
+ { "--show-file-codes", Parameter::PT_IMPLIED, nullptr, nullptr,
+ "indicate how files are located: A=absolute and W, F, C which are relative "
+ "to the working directory, including file, and config file respectively" },
{ "--show-plugins", Parameter::PT_IMPLIED, nullptr, nullptr,
"list module and plugin versions", },
else if ( v.is("--enable-inline-test") )
sc->run_flags |= RUN_FLAG__INLINE_TEST;
+ else if ( v.is("--disable-overrides") )
+ sc->run_flags |= RUN_FLAG__NO_OVERRIDES;
+
else if ( v.is("--gen-msg-map") )
dump_msg_map(sc, v.get_string());
sc->pkt_pause_cnt = v.get_uint64();
#endif
- else if ( v.is("--parsing-follows-files") )
- parsing_follows_files = true;
-
else if ( v.is("--pcap-file") )
{
Trough::add_source(Trough::SOURCE_FILE_LIST, v.get_string());
else if ( v.is("--pcap-show") )
sc->run_flags |= RUN_FLAG__PCAP_SHOW;
+#ifdef PIGLET
+ else if ( v.is("--piglet") )
+ sc->run_flags |= RUN_FLAG__PIGLET;
+#endif
+
else if ( v.is("--plugin-path") )
sc->set_plugin_path(v.get_string());
sc->run_flags |= RUN_FLAG__SHELL;
#endif
-#ifdef PIGLET
- else if ( v.is("--piglet") )
- sc->run_flags |= RUN_FLAG__PIGLET;
-#endif
+ else if ( v.is("--show-file-codes") )
+ sc->run_flags |= RUN_FLAG__SHOW_FILE_CODES;
else if ( v.is("--show-plugins") )
sc->logging_flags |= LOGGING_FLAG__SHOW_PLUGINS;
add_custom_command (
OUTPUT lua_plugffi.h snort_plugin.lua
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/ffi_wrap.sh ${CMAKE_CURRENT_SOURCE_DIR}/lua_plugin_defs.h > plugffi.lua
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/lua_wrap.sh ${CMAKE_CURRENT_SOURCE_DIR} plugffi > lua_plugffi.h
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/plugffi.lua ${CMAKE_CURRENT_BINARY_DIR}/snort_plugin.lua
)
#include <iostream>
#include <mutex>
#include <regex>
-#include <stack>
#include <string>
#include "framework/base_api.h"
bool set_number(const char* fqn, double val);
bool set_string(const char* fqn, const char* val);
bool set_alias(const char* from, const char* to);
+
+ const char* push_relative_path(const char* file);
+ void pop_relative_path();
}
//-------------------------------------------------------------------------
return set_value(fqn, v);
}
-struct DirStackItem
-{
- string previous_dir;
- string base_name;
-};
-
-static std::stack<DirStackItem> dir_stack;
-
SO_PUBLIC const char* push_relative_path(const char* file)
{
- if ( !parsing_follows_files )
- return file;
-
- dir_stack.push(DirStackItem());
- DirStackItem& dsi = dir_stack.top();
-
- char pwd[PATH_MAX];
-
- if ( getcwd(pwd, sizeof(pwd)) == nullptr )
- FatalError("Unable to determine process running directory\n");
-
- dsi.previous_dir = pwd;
-
- char* base_name_buf = snort_strdup(file);
- dsi.base_name = basename(base_name_buf);
- snort_free(base_name_buf);
-
- char* dir_name_buf = snort_strdup(file);
- char* dir_name = dirname(dir_name_buf);
-
- if ( chdir(dir_name) != 0 )
- FatalError("Unable to access %s\n", dir_name);
-
- snort_free(dir_name_buf);
-
- return dsi.base_name.c_str();
+ static std::string path;
+ path = "";
+ const char* code = get_config_file(file, path);
+ push_parse_location(code, path.c_str(), file);
+ return path.c_str();
}
SO_PUBLIC void pop_relative_path()
{
- if ( !parsing_follows_files )
- return;
-
- assert( !dir_stack.empty() );
-
- // We came from this directory, so it should still exist
- const char* prev_dir = dir_stack.top().previous_dir.c_str();
- if ( chdir(prev_dir) != 0 )
- FatalError("Unable to access %s\n", prev_dir);
-
- dir_stack.pop();
+ pop_parse_location();
}
+//-------------------------------------------------------------------------
+// private methods
+//-------------------------------------------------------------------------
+
static bool comp_mods(const ModHook* l, const ModHook* r)
{
const Module* lm = l->mod;
void ModuleManager::load_rules(SnortConfig* sc)
{
s_modules.sort(comp_gids);
- push_parse_location("builtin");
for ( auto p : s_modules )
{
r++;
}
}
- pop_parse_location();
}
void ModuleManager::dump_rules(const char* pfx)
};
}
-extern "C"
-{
- // returns the correct path component to use for referencing the file
- const char* push_relative_path(const char*);
- void pop_relative_path();
-}
-
#endif
#include "parse_conf.h"
+#include <limits.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <fstream>
#include <stack>
#include "log/messages.h"
#include "main/snort_config.h"
#include "managers/action_manager.h"
+#include "managers/module_manager.h"
#include "sfip/sf_vartable.h"
#include "target_based/snort_protocols.h"
#include "utils/util.h"
struct Location
{
+ const char* code;
+ std::string path;
std::string file;
unsigned line;
- Location(const char* s, unsigned u)
- { file = s; line = u; }
+ Location(const char* c, const char* p, const char* f, unsigned u)
+ { code = c; path = p; file = f; line = u; }
};
static std::stack<Location> files;
+const char* get_parse_file()
+{
+ if ( !files.empty() )
+ return files.top().path.c_str();
+
+ static char dir[PATH_MAX];
+
+ if ( !getcwd(dir, sizeof(dir)) )
+ return "";
+
+ return dir;
+}
+
void get_parse_location(const char*& file, unsigned& line)
{
if ( files.empty() )
line = loc.line;
}
-void push_parse_location(const char* file, unsigned line)
+static void print_parse_file(const char* msg, Location& loc)
{
- if ( !file )
+ if ( SnortConfig::show_file_codes() )
+ LogMessage("%s %s:%s:\n", msg, (loc.code ? loc.code : "?"), loc.file.c_str());
+
+ else
+ LogMessage("%s %s:\n", msg, loc.file.c_str());
+}
+
+void push_parse_location(
+ const char* code, const char* path, const char* file, unsigned line)
+{
+ if ( !path )
return;
- Location loc(file, line);
+ if ( !file )
+ file = path;
+
+ Location loc(code, path, file, line);
files.push(loc);
- LogMessage("Loading %s:\n", file);
+ print_parse_file("Loading", loc);
}
void pop_parse_location()
if ( !files.empty() )
{
Location& loc = files.top();
- LogMessage("Finished %s.\n", loc.file.c_str());
+ print_parse_file("Finished", loc);
files.pop();
}
}
void inc_parse_position()
{
+ if ( files.empty() )
+ return;
Location& loc = files.top();
++loc.line;
}
-void parse_include(SnortConfig* sc, const char* arg)
+static bool valid_file(const char* file, std::string& path)
{
- struct stat file_stat; /* for include path testing */
- arg = ExpandVars(sc, arg);
- char* fname = snort_strdup(arg);
+ path += '/';
+ path += file;
- /* Stat the file. If that fails, make it relative to the directory
- * that the top level snort configuration file was in */
- if ( stat(fname, &file_stat) == -1 && fname[0] != '/' )
- {
- const char* snort_conf_dir = get_snort_conf_dir();
+ struct stat s;
+ return stat(path.c_str(), &s) == 0;
+}
+
+static bool relative_to_parse_dir(const char* file, std::string& path)
+{
+ if ( !path.length() )
+ path = get_parse_file();
+ size_t idx = path.rfind('/');
+ if ( idx == std::string::npos )
+ idx = 0;
+ path.erase(idx);
+ return valid_file(file, path);
+}
- int path_len = strlen(snort_conf_dir) + strlen(arg) + 1;
- snort_free(fname);
+static bool relative_to_config_dir(const char* file, std::string& path)
+{
+ path = get_snort_conf_dir();
+ return valid_file(file, path);
+}
+
+static bool relative_to_working_dir(const char* file, std::string& path)
+{
+ char dir[PATH_MAX];
+ if ( !getcwd(dir, sizeof(dir)) )
+ return false;
+ path = dir;
+ return valid_file(file, path);
+}
+
+const char* get_config_file(const char* arg, std::string& file)
+{
+ bool absolute = (arg[0] == '/');
- fname = (char*)snort_calloc(path_len);
- snprintf(fname, path_len, "%s%s", snort_conf_dir, arg);
+ if ( absolute )
+ {
+ file = arg;
+ return "A";
}
+ std::string hint = file;
+
+ if ( SnortConfig::allow_overrides() and relative_to_working_dir(arg, file) )
+ return "W";
+
+ file = hint;
+
+ if ( relative_to_parse_dir(arg, file) )
+ return "F";
+
+ if ( relative_to_config_dir(arg, file) )
+ return "C";
- push_parse_location(fname);
- ParseConfigFile(sc, fname);
+ return nullptr;
+}
+
+void parse_include(SnortConfig* sc, const char* arg)
+{
+ assert(arg);
+ arg = ExpandVars(sc, arg);
+ std::string file;
+
+ const char* code = get_config_file(arg, file);
+
+ if ( !code )
+ {
+ ParseError("can't open %s\n", arg);
+ return;
+ }
+ push_parse_location(code, file.c_str(), arg);
+ ParseConfigFile(sc, file.c_str());
pop_parse_location();
- snort_free((char*)fname);
}
void ParseIpVar(SnortConfig* sc, const char* var, const char* val)
#ifndef PARSE_CONF_H
#define PARSE_CONF_H
+#include <string>
#include "detection/rules.h"
void parse_conf_init();
struct SnortConfig;
}
+const char* get_parse_file();
+
+// returns code or nullptr if not found, file holds abs path
+// file may hold original parse path on entry
+const char* get_config_file(const char* arg, std::string& file);
+
void ParseConfigFile(snort::SnortConfig*, const char* fname);
void ParseConfigString(snort::SnortConfig*, const char* str);
using namespace snort;
-bool parsing_follows_files = false;
-
static struct rule_index_map_t* ruleIndexMap = nullptr;
static std::string s_aux_rules;
if ( !fname || !*fname )
return false;
- push_parse_location(fname, 0);
bool success = sh->configure(sc, is_fatal);
- pop_parse_location();
return success;
}
ModuleManager::load_rules(sc);
const char* fname = p->include.c_str();
+ std::string file = p->parse_from;
if ( fname && *fname )
{
- push_parse_location(fname);
- ParseConfigFile(sc, fname);
+ const char* code = get_config_file(fname, file);
+ push_parse_location(code, file.c_str(), fname);
+ ParseConfigFile(sc, file.c_str());
pop_parse_location();
}
if ( !p->rules.empty() )
{
- push_parse_location("rules");
+ push_parse_location("C", file.c_str(), "rules");
ParseConfigString(sc, p->rules.c_str());
pop_parse_location();
}
if ( !idx && sc->stdin_rules )
{
LogMessage("Reading rules until EOF or a line starting with END\n");
- push_parse_location("stdin");
+ push_parse_location("C", get_snort_conf_dir(), "stdin");
parse_stream(std::cin, sc);
pop_parse_location();
}
void get_parse_location(const char*& name, unsigned& line);
// use line = 0 for lua to suppress line numbers for errors or warnings
-void push_parse_location(const char* name, unsigned line = 1);
+void push_parse_location(
+ const char* code, const char* path, const char* name = nullptr, unsigned line = 1);
void pop_parse_location();
void inc_parse_position();
PolicyId policyId;
};
-extern bool parsing_follows_files;
#endif