AC_DEFINE(SHELL, [1], [enable shell support])
fi
+AM_CONDITIONAL(ENABLE_SHELL, test "x$enable_shell" = "xyes")
+
AC_ARG_ENABLE(tsc-clock,
AS_HELP_STRING([--enable-tsc-clock],[use timestamp counter register clock (x86 only)]),
enable_tsc_clock="$enableval", enable_tsc_clock="no")
#include "piglet/piglet.h"
#endif
+#ifdef SHELL
+#include "main/control.h"
+#endif
+
//-------------------------------------------------------------------------
static bool exit_requested = false;
#ifdef SHELL
// FIXIT-M make these non-blocking
-// FIXIT-M allow at least 2 remote controls
// FIXIT-M bind to configured ip including INADDR_ANY
// (default is loopback if enabled)
// FIXIT-M block on asynchronous analyzer commands until they complete
static int listener = -1;
-static int local_control = STDIN_FILENO;
static int remote_control = -1;
static int socket_init()
static int socket_term()
{
- if ( remote_control >= 0 )
- close(remote_control);
+ Snort::delete_controls();
if ( listener >= 0 )
close(listener);
if ( remote_control < 0 )
return -1;
+ Snort::add_control(remote_control, false);
+
// FIXIT-L authenticate, use ssl ?
return 0;
}
-static void shell(int& fd)
+static void shell(int& fd, Shell* sh)
{
std::string rsp;
if ( !request.read(fd) )
return;
- SnortConfig* sc = snort_conf;
- sc->policy_map->get_shell()->execute(request.get(), rsp);
+ sh->execute(request.get(), rsp);
if ( rsp.size() )
request.respond(rsp.c_str());
request.show_prompt();
}
+static bool process_control_commands(fd_set& inputs)
+{
+ bool ret = false;
+
+ for(std::vector<ControlConn*>::iterator control =
+ Snort::get_controls().begin(); control != Snort::get_controls().end();)
+ {
+ int fd = (*control)->get_fd();
+ if ( FD_ISSET(fd, &inputs) )
+ {
+ shell(fd, (*control)->get_shell());
+ if( fd < 0 )
+ {
+ Snort::delete_control(control);
+ ret = false;
+ continue;
+ }
+ else
+ {
+ if ( (*control)->is_local_control() )
+ proc_stats.local_commands++;
+ else
+ proc_stats.remote_commands++;
+ ret = true;
+ }
+ }
+ ++control;
+ }
+ return ret;
+}
+
static bool service_users()
{
fd_set inputs;
FD_ZERO(&inputs);
int max_fd = -1;
+ bool ret = false;
- if ( shell_enabled and local_control >= 0 )
- {
- FD_SET(local_control, &inputs);
- max_fd = local_control;
- }
-
- if ( remote_control >= 0 )
+ for ( auto control : Snort::get_controls() )
{
- FD_SET(remote_control, &inputs);
- if ( remote_control > max_fd )
- max_fd = remote_control;
+ int fd = control->get_fd();
+ if ( fd >= 0 )
+ {
+ FD_SET(fd, &inputs);
+ if ( fd > max_fd )
+ max_fd = fd;
+ }
}
- // one remote at a time; the else prevents a new remote
- // from taking control from an existing remote
- else if ( listener >= 0 )
+ if ( listener >= 0 )
{
FD_SET(listener, &inputs);
if ( listener > max_fd )
if ( select(max_fd+1, &inputs, NULL, NULL, &timeout) > 0 )
{
- if ( FD_ISSET(local_control, &inputs) )
- {
- shell(local_control);
- proc_stats.local_commands++;
- return true;
- }
- else if ( FD_ISSET(remote_control, &inputs) )
- {
- shell(remote_control);
- proc_stats.remote_commands++;
- return true;
- }
- else if ( FD_ISSET(listener, &inputs) )
+ ret = process_control_commands(inputs);
+
+ if ( FD_ISSET(listener, &inputs) )
{
if ( !socket_conn() )
{
request.set(remote_control);
request.show_prompt();
- return true;
+ ret = true;
}
}
}
- return false;
+ return ret;
}
#endif
{
LogMessage("Entering command shell\n");
shell_enabled = true;
+ Snort::add_control(STDOUT_FILENO, true);
request.set(STDOUT_FILENO, "");
request.show_prompt();
}
set ( DEBUG_MSGS_SOURCES snort_debug.cc )
endif ( ENABLE_DEBUG_MSGS )
+if ( ENABLE_SHELL )
+ set ( SHELL_SOURCES control.cc control.h )
+endif ( ENABLE_SHELL )
+
add_library (main STATIC
analyzer.cc
analyzer.h
thread_config.cc
${DEBUG_MSGS_SOURCES}
${INCLUDES}
+ ${SHELL_SOURCES}
)
snort.h \
snort_config.cc \
snort_config.h \
+snort_module.cc \
+snort_module.h \
swapper.cc \
swapper.h \
+thread.cc \
thread_config.h \
thread_config.cc
libmain_a_SOURCES += snort_debug.cc
endif
+if ENABLE_SHELL
libmain_a_SOURCES += \
-snort_module.cc \
-snort_module.h \
-thread.cc
+control.cc \
+control.h
+endif
--- /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.
+//--------------------------------------------------------------------------
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "control.h"
+
+#include "managers/module_manager.h"
+#include "utils/util.h"
+#include "shell.h"
+
+using namespace std;
+
+//------------------------------------------------------------------------
+// control channel class
+// -----------------------------------------------------------------------
+
+ControlConn::ControlConn(int i, bool local)
+{
+ fd = i;
+ local_control = local;
+ sh = new Shell;
+ configure();
+}
+
+ControlConn::~ControlConn()
+{
+ if( !local_control )
+ close(fd);
+ delete sh;
+}
+
+void ControlConn::configure()
+{
+ ModuleManager::load_commands(sh);
+}
--- /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.
+//--------------------------------------------------------------------------
+
+#ifndef CONTROL_H
+#define CONTROL_H
+
+#include "main/snort_types.h"
+
+class ControlConn
+{
+public:
+ ControlConn(int fd, bool local_control);
+ ~ControlConn();
+
+ int get_fd() { return fd; }
+ class Shell* get_shell() { return sh; }
+ bool is_local_control() { return local_control; }
+ void configure();
+private:
+ int fd = -1;
+ bool local_control = false;
+ class Shell *sh;
+};
+
+#endif
+
#include "piglet_plugins/piglet_plugins.h"
#endif
+#ifdef SHELL
+#include "control.h"
+#endif
+
#include "build.h"
#include "snort_config.h"
#include "thread_config.h"
void Snort::cleanup()
{
+#ifdef SHELL
+ delete_controls();
+#endif
TimeStop();
SFDAQ::term();
sc->setup();
+#ifdef SHELL
+ reconfigure_controls();
+#endif
+
if ( !InspectorManager::configure(sc) )
{
parser_term(sc);
return verdict;
}
+
+#ifdef SHELL
+std::vector<ControlConn*> Snort::controls;
+
+void Snort::add_control(int fd, bool local)
+{
+ controls.push_back(new ControlConn(fd, local));
+}
+
+void Snort::delete_control(std::vector<ControlConn*>::iterator& control)
+{
+ delete *control;
+ control = controls.erase(control);
+}
+
+void Snort::reconfigure_controls()
+{
+ for ( auto control : controls )
+ {
+ control->configure();
+ }
+}
+
+std::vector<ControlConn*>& Snort::get_controls()
+{
+ return controls;
+}
+
+void Snort::delete_controls()
+{
+ for ( auto control : controls )
+ {
+ delete control;
+ }
+ controls.clear();
+}
+#endif
#define SNORT_H
// Snort is the top-level application class.
-
+#include <vector>
#include <daq_common.h>
#include "main/snort_types.h"
class Flow;
+class ControlConn;
struct Packet;
struct SnortConfig;
SO_PUBLIC static Packet* get_packet();
+#ifdef SHELL
+ static void add_control(int fd, bool local_control);
+ static void delete_control(std::vector<ControlConn*>::iterator& control);
+ static void reconfigure_controls();
+ static std::vector<ControlConn*>& get_controls();
+ static void delete_controls();
+#endif
+
private:
static void init(int, char**);
static void term();
static bool initializing;
static bool reloading;
static bool privileges_dropped;
+#ifdef SHELL
+ static std::vector<ControlConn*> controls;
+#endif
};
#endif
/* Need to do this after dynamic detection stuff is initialized, too */
IpsManager::verify(this);
- ModuleManager::load_commands(this);
+ ModuleManager::load_commands(policy_map->get_shell());
fpCreateFastPacketDetection(this);
}
cout << "no match" << endl;
}
-void ModuleManager::load_commands(SnortConfig* sc)
+void ModuleManager::load_commands(Shell* sh)
{
// FIXIT-L ideally only install commands from configured modules
// FIXIT-L install commands into working shell
- Shell* sh = sc->policy_map->get_shell();
for ( auto p : s_modules )
{
//-------------------------------------------------------------------------
struct SnortConfig;
+class Shell;
class ModuleManager
{
static void dump_rules(const char* = nullptr);
static void dump_defaults(const char* = nullptr);
- static void load_commands(SnortConfig*);
+ static void load_commands(Shell*);
static void load_rules(SnortConfig*);
static void set_config(SnortConfig*);