From 34fd319a4c8ff91cbf263f2eef5f6255bf2a9b1c Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 16 Nov 2023 16:19:23 -0600 Subject: [PATCH] python: remove python implementation of suricatasc/suricatactl --- python/Makefile.am | 19 +- python/bin/suricatactl | 39 ---- python/bin/suricatasc | 100 --------- python/suricata/ctl/__init__.py | 0 python/suricata/ctl/filestore.py | 129 ------------ python/suricata/ctl/loghandler.py | 81 ------- python/suricata/ctl/main.py | 46 ---- python/suricata/ctl/test_filestore.py | 18 -- python/suricata/sc/__init__.py | 1 - python/suricata/sc/specs.py | 228 -------------------- python/suricata/sc/suricatasc.py | 293 -------------------------- python/suricatasc/__init__.py | 1 - 12 files changed, 2 insertions(+), 953 deletions(-) delete mode 100755 python/bin/suricatactl delete mode 100755 python/bin/suricatasc delete mode 100644 python/suricata/ctl/__init__.py delete mode 100644 python/suricata/ctl/filestore.py delete mode 100644 python/suricata/ctl/loghandler.py delete mode 100644 python/suricata/ctl/main.py delete mode 100644 python/suricata/ctl/test_filestore.py delete mode 100644 python/suricata/sc/__init__.py delete mode 100644 python/suricata/sc/specs.py delete mode 100644 python/suricata/sc/suricatasc.py delete mode 100644 python/suricatasc/__init__.py diff --git a/python/Makefile.am b/python/Makefile.am index f34f4e430341..32bf43f825a8 100644 --- a/python/Makefile.am +++ b/python/Makefile.am @@ -1,28 +1,13 @@ LIBS = \ suricata/__init__.py \ - suricata/config/__init__.py \ - suricata/ctl/__init__.py \ - suricata/ctl/filestore.py \ - suricata/ctl/loghandler.py \ - suricata/ctl/main.py \ - suricata/ctl/test_filestore.py \ - suricata/sc/__init__.py \ - suricata/sc/specs.py \ - suricata/sc/suricatasc.py \ - suricatasc/__init__.py + suricata/config/__init__.py -EXTRA_DIST = $(LIBS) bin suricata/config/defaults.py +EXTRA_DIST = $(LIBS) suricata/config/defaults.py if HAVE_PYTHON install-exec-local: install -d -m 0755 "$(DESTDIR)$(prefix)/lib/suricata/python/suricata/config" - install -d -m 0755 "$(DESTDIR)$(prefix)/lib/suricata/python/suricata/ctl" - install -d -m 0755 "$(DESTDIR)$(prefix)/lib/suricata/python/suricata/sc" - install -d -m 0755 "$(DESTDIR)$(prefix)/lib/suricata/python/suricatasc" - for src in $(LIBS); do \ - install -m 0644 $(srcdir)/$$src "$(DESTDIR)$(prefix)/lib/suricata/python/$$src"; \ - done install suricata/config/defaults.py \ "$(DESTDIR)$(prefix)/lib/suricata/python/suricata/config/defaults.py" diff --git a/python/bin/suricatactl b/python/bin/suricatactl deleted file mode 100755 index 27805891e34d..000000000000 --- a/python/bin/suricatactl +++ /dev/null @@ -1,39 +0,0 @@ -#! /usr/bin/env python -# -# Copyright (C) 2017-2022 Open Information Security Foundation -# -# You can copy, redistribute or modify this Program under the terms of -# the GNU General Public License version 2 as published by the Free -# Software Foundation. -# -# 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 -# version 2 along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. - -import sys -import os -import site - -exec_dir = os.path.dirname(__file__) - -if os.path.exists(os.path.join(exec_dir, "..", "suricata", "ctl", "main.py")): - # Looks like we're running from the development directory. - sys.path.insert(0, ".") -else: - # Check if the Python modules are installed in the Suricata installation - # prefix. - version_info = sys.version_info - pyver = "%d.%d" % (version_info.major, version_info.minor) - path = os.path.realpath(os.path.join( - exec_dir, "..", "lib", "suricata", "python", "suricata")) - if os.path.exists(path): - sys.path.insert(0, os.path.dirname(path)) - -from suricata.ctl.main import main -sys.exit(main()) diff --git a/python/bin/suricatasc b/python/bin/suricatasc deleted file mode 100755 index d090f856f54d..000000000000 --- a/python/bin/suricatasc +++ /dev/null @@ -1,100 +0,0 @@ -#! /usr/bin/env python -# -# Copyright(C) 2013-2023 Open Information Security Foundation -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2 of the 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. - -from __future__ import print_function - -import sys -import os -import argparse - -# Find the Python libdir. -exec_dir = os.path.dirname(__file__) -if os.path.exists(os.path.join(exec_dir, "..", "suricata", "ctl", "main.py")): - # Looks like we're running from the development directory. - sys.path.insert(0, ".") -else: - # Check if the Python modules are installed in the Suricata installation - # prefix. - version_info = sys.version_info - pyver = "%d.%d" % (version_info.major, version_info.minor) - path = os.path.realpath(os.path.join( - exec_dir, "..", "lib", "suricata", "python", "suricata")) - if os.path.exists(path): - sys.path.insert(0, os.path.dirname(path)) - -from suricata.sc import * - -try: - from suricata.config import defaults - has_defaults = True -except: - has_defaults = False - -parser = argparse.ArgumentParser(prog='suricatasc', description='Client for Suricata unix socket') -parser.add_argument('-v', '--verbose', action='store_const', const=True, help='verbose output (including JSON dump)') -parser.add_argument('-c', '--command', default=None, help='execute on single command and return JSON') -parser.add_argument('socket', metavar='socket', nargs='?', help='socket file to connect to', default=None) -args = parser.parse_args() - -if args.socket != None: - SOCKET_PATH = args.socket -elif has_defaults: - SOCKET_PATH = os.path.join(defaults.localstatedir, "suricata-command.socket") -else: - print("Unable to determine path to suricata-command.socket.", file=sys.stderr) - sys.exit(1) - -sc = SuricataSC(SOCKET_PATH, verbose=args.verbose) -try: - sc.connect() -except SuricataNetException as err: - print("Unable to connect to socket %s: %s" % (SOCKET_PATH, err), file=sys.stderr) - sys.exit(1) -except SuricataReturnException as err: - print("Unable to negotiate version with server: %s" % (err), file=sys.stderr) - sys.exit(1) - -if args.command: - try: - (command, arguments) = sc.parse_command(args.command) - except SuricataCommandException as err: - print(err.value) - sys.exit(1) - try: - res = sc.send_command(command, arguments) - except (SuricataCommandException, SuricataReturnException) as err: - print(err.value) - sys.exit(1) - print(json.dumps(res)) - sc.close() - if res['return'] == 'OK': - sys.exit(0) - else: - sys.exit(1) - -try: - sc.interactive() -except SuricataNetException as err: - print("Communication error: %s" % (err)) - sys.exit(1) -except SuricataReturnException as err: - print("Invalid return from server: %s" % (err)) - sys.exit(1) - -print("[+] Quit command client") - -sc.close() diff --git a/python/suricata/ctl/__init__.py b/python/suricata/ctl/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/python/suricata/ctl/filestore.py b/python/suricata/ctl/filestore.py deleted file mode 100644 index 2901f597e2f9..000000000000 --- a/python/suricata/ctl/filestore.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright (C) 2018 Open Information Security Foundation -# -# You can copy, redistribute or modify this Program under the terms of -# the GNU General Public License version 2 as published by the Free -# Software Foundation. - -# 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 -# version 2 along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. - -from __future__ import print_function - -import sys -import os -import os.path -import time -import re -import logging - -logger = logging.getLogger("filestore") - - -class InvalidAgeFormatError(Exception): - pass - - -def register_args(parser): - subparser = parser.add_subparsers(help="sub-command help") - prune_parser = subparser.add_parser("prune", - help="Remove files in specified directory older than specified age") - required_args = prune_parser.add_argument_group("required arguments") - required_args.add_argument("-d", "--directory", - help="filestore directory", required=True) - required_args.add_argument("--age", - help="prune files older than age, units: s, m, h, d") - prune_parser.add_argument( - "-n", "--dry-run", action="store_true", default=False, - help="only print what would happen") - prune_parser.add_argument( - "-v", "--verbose", action="store_true", - default=False, help="increase verbosity") - prune_parser.add_argument( - "-q", "--quiet", action="store_true", default=False, - help="be quiet, log warnings and errors only") - prune_parser.set_defaults(func=prune) - - -def is_fileinfo(path): - return path.endswith(".json") - - -def parse_age(age): - matched_age = re.match(r"(\d+)\s*(\w+)", age) - if not matched_age: - raise InvalidAgeFormatError(age) - val = int(matched_age.group(1)) - unit = matched_age.group(2) - ts_units = ["s", "m", "h", "d"] - try: - idx = ts_units.index(unit) - except ValueError: - raise InvalidAgeFormatError("bad unit: %s" % (unit)) - multiplier = 60 ** idx if idx != 3 else 24 * 60 ** 2 - return val * multiplier - - -def get_filesize(path): - return os.stat(path).st_size - - -def remove_file(path, dry_run): - size = 0 - size += get_filesize(path) - if not dry_run: - os.unlink(path) - return size - - -def set_logger_level(args): - if args.verbose: - logger.setLevel(logging.DEBUG) - if args.quiet: - logger.setLevel(logging.WARNING) - - -def perform_sanity_checks(args): - set_logger_level(args) - err_msg = { - "directory": "filestore directory must be provided", - "age": "no age provided, nothing to do", - } - for val, msg in err_msg.items(): - if not getattr(args, val): - print("Error: {}".format(msg), file=sys.stderr) - sys.exit(1) - required_dirs = ["tmp", "00", "ff"] - for required_dir in required_dirs: - if not os.path.exists(os.path.join(args.directory, required_dir)): - logger.error("Provided directory is not a filestore directory") - sys.exit(1) - - -def prune(args): - perform_sanity_checks(args) - age = parse_age(args.age) - now = time.time() - size = 0 - count = 0 - - for dirpath, dirnames, filenames in os.walk(args.directory, topdown=True): - # Do not go into the tmp directory. - if "tmp" in dirnames: - dirnames.remove("tmp") - for filename in filenames: - path = os.path.join(dirpath, filename) - mtime = os.path.getmtime(path) - this_age = now - mtime - if this_age > age: - logger.debug("Deleting %s; age=%ds", path, this_age) - size += remove_file(path, args.dry_run) - count += 1 - logger.info("Removed %d files; %d bytes.", count, size) - return 0 diff --git a/python/suricata/ctl/loghandler.py b/python/suricata/ctl/loghandler.py deleted file mode 100644 index 553b896fd1de..000000000000 --- a/python/suricata/ctl/loghandler.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (C) 2017 Open Information Security Foundation -# Copyright (c) 2016 Jason Ish -# -# You can copy, redistribute or modify this Program under the terms of -# the GNU General Public License version 2 as published by the Free -# Software Foundation. -# -# 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 -# version 2 along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. - -import logging -import time - -GREEN = "\x1b[32m" -BLUE = "\x1b[34m" -REDB = "\x1b[1;31m" -YELLOW = "\x1b[33m" -RED = "\x1b[31m" -YELLOWB = "\x1b[1;33m" -ORANGE = "\x1b[38;5;208m" -RESET = "\x1b[0m" - -# A list of secrets that will be replaced in the log output. -secrets = {} - -def add_secret(secret, replacement): - """Register a secret to be masked. The secret will be replaced with: - - """ - secrets[str(secret)] = str(replacement) - -class SuriColourLogHandler(logging.StreamHandler): - """An alternative stream log handler that logs with Suricata inspired - log colours.""" - - @staticmethod - def format_time(record): - local_time = time.localtime(record.created) - formatted_time = "%d/%d/%d -- %02d:%02d:%02d" % (local_time.tm_mday, - local_time.tm_mon, - local_time.tm_year, - local_time.tm_hour, - local_time.tm_min, - local_time.tm_sec) - return "%s" % (formatted_time) - - def emit(self, record): - - if record.levelname == "ERROR": - level_prefix = REDB - message_prefix = REDB - elif record.levelname == "WARNING": - level_prefix = ORANGE - message_prefix = ORANGE - else: - level_prefix = YELLOW - message_prefix = "" - - self.stream.write("%s%s%s - <%s%s%s> -- %s%s%s\n" % ( - GREEN, - self.format_time(record), - RESET, - level_prefix, - record.levelname.title(), - RESET, - message_prefix, - self.mask_secrets(record.getMessage()), - RESET)) - - @staticmethod - def mask_secrets(msg): - for secret in secrets: - msg = msg.replace(secret, "<%s>" % secrets[secret]) - return msg diff --git a/python/suricata/ctl/main.py b/python/suricata/ctl/main.py deleted file mode 100644 index d51a5be61e1c..000000000000 --- a/python/suricata/ctl/main.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (C) 2018 Open Information Security Foundation -# -# You can copy, redistribute or modify this Program under the terms of -# the GNU General Public License version 2 as published by the Free -# Software Foundation. - -# 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 -# version 2 along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. - -import sys -import os -import argparse -import logging - -from suricata.ctl import filestore, loghandler - -def init_logger(): - """ Initialize logging, use colour if on a tty. """ - if os.isatty(sys.stderr.fileno()): - logger = logging.getLogger() - logger.setLevel(level=logging.INFO) - logger.addHandler(loghandler.SuriColourLogHandler()) - else: - logging.basicConfig( - level=logging.INFO, - format="%(asctime)s - <%(levelname)s> - %(message)s") - -def main(): - init_logger() - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(help='sub-command help') - fs_parser = subparsers.add_parser("filestore", help="Filestore related commands") - filestore.register_args(parser=fs_parser) - args = parser.parse_args() - try: - func = args.func - except AttributeError: - parser.error("too few arguments") - func(args) diff --git a/python/suricata/ctl/test_filestore.py b/python/suricata/ctl/test_filestore.py deleted file mode 100644 index 3bac1c6feb0f..000000000000 --- a/python/suricata/ctl/test_filestore.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import print_function - -import unittest - -from suricata.ctl import filestore - -class PruneTestCase(unittest.TestCase): - - def test_parse_age(self): - self.assertEqual(filestore.parse_age("1s"), 1) - self.assertEqual(filestore.parse_age("1m"), 60) - self.assertEqual(filestore.parse_age("1h"), 3600) - self.assertEqual(filestore.parse_age("1d"), 86400) - - with self.assertRaises(filestore.InvalidAgeFormatError): - filestore.parse_age("1") - with self.assertRaises(filestore.InvalidAgeFormatError): - filestore.parse_age("1y") diff --git a/python/suricata/sc/__init__.py b/python/suricata/sc/__init__.py deleted file mode 100644 index 976e1fc21756..000000000000 --- a/python/suricata/sc/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from suricata.sc.suricatasc import * diff --git a/python/suricata/sc/specs.py b/python/suricata/sc/specs.py deleted file mode 100644 index c7e045873303..000000000000 --- a/python/suricata/sc/specs.py +++ /dev/null @@ -1,228 +0,0 @@ -argsd = { - "pcap-file": [ - { - "name": "filename", - "required": 1, - }, - { - "name": "output-dir", - "required": 1, - }, - { - "name": "tenant", - "type": int, - "required": 0, - }, - { - "name": "continuous", - "required": 0, - }, - { - "name": "delete-when-done", - "required": 0, - }, - ], - "pcap-file-continuous": [ - { - "name": "filename", - "required": 1, - }, - { - "name": "output-dir", - "required": 1, - }, - { - "name": "continuous", - "val": True, - "required": 1, - }, - { - "name": "tenant", - "type": int, - "required": 0, - }, - { - "name": "delete-when-done", - "required": 0, - }, - ], - "iface-stat": [ - { - "name": "iface", - "required": 1, - }, - ], - "conf-get": [ - { - "name": "variable", - "required": 1, - } - ], - "unregister-tenant-handler": [ - { - "name": "id", - "type": int, - "required": 1, - }, - { - "name": "htype", - "required": 1, - }, - { - "name": "hargs", - "type": int, - "required": 0, - }, - ], - "register-tenant-handler": [ - { - "name": "id", - "type": int, - "required": 1, - }, - { - "name": "htype", - "required": 1, - }, - { - "name": "hargs", - "type": int, - "required": 0, - }, - ], - "unregister-tenant": [ - { - "name": "id", - "type": int, - "required": 1, - }, - ], - "register-tenant": [ - { - "name": "id", - "type": int, - "required": 1, - }, - { - "name": "filename", - "required": 1, - }, - ], - "reload-tenant": [ - { - "name": "id", - "type": int, - "required": 1, - }, - { - "name": "filename", - "required": 0, - }, - ], - "add-hostbit": [ - { - "name": "ipaddress", - "required": 1, - }, - { - "name": "hostbit", - "required": 1, - }, - { - "name": "expire", - "type": int, - "required": 1, - }, - ], - "remove-hostbit": [ - { - "name": "ipaddress", - "required": 1, - }, - { - "name": "hostbit", - "required": 1, - }, - ], - "list-hostbit": [ - { - "name": "ipaddress", - "required": 1, - }, - ], - "memcap-set": [ - { - "name": "config", - "required": 1, - }, - { - "name": "memcap", - "required": 1, - }, - ], - "memcap-show": [ - { - "name": "config", - "required": 1, - }, - ], - "dataset-add": [ - { - "name": "setname", - "required": 1, - }, - { - "name": "settype", - "required": 1, - }, - { - "name": "datavalue", - "required": 1, - }, - ], - "dataset-remove": [ - { - "name": "setname", - "required": 1, - }, - { - "name": "settype", - "required": 1, - }, - { - "name": "datavalue", - "required": 1, - }, - ], - "get-flow-stats-by-id": [ - { - "name": "flow_id", - "type": int, - "required": 1, - }, - ], - "dataset-clear": [ - { - "name": "setname", - "required": 1, - }, - { - "name": "settype", - "required": 1, - } - ], - "dataset-lookup": [ - { - "name": "setname", - "required": 1, - }, - { - "name": "settype", - "required": 1, - }, - { - "name": "datavalue", - "required": 1, - }, - ], - } diff --git a/python/suricata/sc/suricatasc.py b/python/suricata/sc/suricatasc.py deleted file mode 100644 index fc07037c3d22..000000000000 --- a/python/suricata/sc/suricatasc.py +++ /dev/null @@ -1,293 +0,0 @@ -# Copyright(C) 2012-2023 Open Information Security Foundation - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2 of the 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. - -try: - import simplejson as json -except ImportError: - import json -import readline -import select -import sys -from socket import AF_UNIX, error, socket -from inspect import currentframe - -from suricata.sc.specs import argsd - -SURICATASC_VERSION = "1.0" -VERSION = "0.2" -INC_SIZE = 1024 - - -def get_linenumber(): - cf = currentframe() - return cf.f_back.f_lineno - - -class SuricataException(Exception): - """ - Generic class for suricatasc exception - """ - def __init__(self, value): - super(SuricataException, self).__init__(value) - self.value = value - - def __str__(self): - return str(self.value) - - -class SuricataNetException(SuricataException): - """ - Exception raised when a network error occurs - """ - - -class SuricataCommandException(SuricataException): - """ - Exception raised when the command is incorrect - """ - - -class SuricataReturnException(SuricataException): - """ - Exception raised when return message is incorrect - """ - - -class SuricataCompleter: - def __init__(self, words): - self.words = words - self.generator = None - - def complete(self, text): - for word in self.words: - if word.startswith(text): - yield word - - def __call__(self, text, state): - if state == 0: - self.generator = self.complete(text) - try: - return next(self.generator) - except StopIteration: - return None - - -class SuricataSC: - def __init__(self, sck_path, verbose=False): - self.basic_commands = [ - "shutdown", - "quit", - "pcap-file-number", - "pcap-file-list", - "pcap-last-processed", - "pcap-interrupt", - "iface-list", - "reload-tenants", - ] - self.fn_commands = [ - "pcap-file", - "pcap-file-continuous", - "iface-stat", - "conf-get", - "unregister-tenant-handler", - "register-tenant-handler", - "unregister-tenant", - "register-tenant", - "reload-tenant", - "add-hostbit", - "remove-hostbit", - "list-hostbit", - "memcap-set", - "memcap-show", - "dataset-add", - "dataset-remove", - "get-flow-stats-by-id", - "dataset-clear", - "dataset-lookup", - ] - self.cmd_list = self.basic_commands + self.fn_commands - self.sck_path = sck_path - self.verbose = verbose - self.socket = socket(AF_UNIX) - - def json_recv(self): - cmdret = None - data = "" - while True: - if sys.version < '3': - received = self.socket.recv(INC_SIZE) - else: - received = self.socket.recv(INC_SIZE).decode('iso-8859-1') - - if not received: - break - - data += received - if data.endswith('\n'): - cmdret = json.loads(data) - break - return cmdret - - def send_command(self, command, arguments=None): - if command not in self.cmd_list and command != 'command-list': - raise SuricataCommandException("L{}: Command not found: {}".format(get_linenumber(), command)) - - cmdmsg = {} - cmdmsg['command'] = command - if arguments: - cmdmsg['arguments'] = arguments - if self.verbose: - print("SND: " + json.dumps(cmdmsg)) - cmdmsg_str = json.dumps(cmdmsg) + "\n" - if sys.version < '3': - self.socket.send(cmdmsg_str) - else: - self.socket.send(bytes(cmdmsg_str, 'iso-8859-1')) - - ready = select.select([self.socket], [], [], 600) - if ready[0]: - cmdret = self.json_recv() - else: - cmdret = None - if not cmdret: - raise SuricataReturnException("L{}: Unable to get message from server".format(get_linenumber)) - - if self.verbose: - print("RCV: "+ json.dumps(cmdret)) - - return cmdret - - def connect(self): - try: - if self.socket is None: - self.socket = socket(AF_UNIX) - self.socket.connect(self.sck_path) - except error as err: - raise SuricataNetException("L{}: {}".format(get_linenumber(), err)) - - self.socket.settimeout(10) - #send version - if self.verbose: - print("SND: " + json.dumps({"version": VERSION})) - if sys.version < '3': - self.socket.send(json.dumps({"version": VERSION})) - else: - self.socket.send(bytes(json.dumps({"version": VERSION}), 'iso-8859-1')) - - ready = select.select([self.socket], [], [], 600) - if ready[0]: - cmdret = self.json_recv() - else: - cmdret = None - - if not cmdret: - raise SuricataReturnException("L{}: Unable to get message from server".format(get_linenumber())) - - if self.verbose: - print("RCV: "+ json.dumps(cmdret)) - - if cmdret["return"] == "NOK": - raise SuricataReturnException("L{}: Error: {}".format(get_linenumber(), cmdret["message"])) - - cmdret = self.send_command("command-list") - - # we silently ignore NOK as this means server is old - if cmdret["return"] == "OK": - self.cmd_list = cmdret["message"]["commands"] - self.cmd_list.append("quit") - - def close(self): - self.socket.close() - self.socket = None - - def execute(self, command): - full_cmd = command.split() - cmd = full_cmd[0] - cmd_specs = argsd[cmd] - required_args_count = len([d["required"] for d in cmd_specs if d["required"] and not "val" in d]) - arguments = dict() - for c, spec in enumerate(cmd_specs, 1): - spec_type = str if "type" not in spec else spec["type"] - if spec["required"]: - if spec.get("val"): - arguments[spec["name"]] = spec_type(spec["val"]) - continue - try: - arguments[spec["name"]] = spec_type(full_cmd[c]) - except IndexError: - phrase = " at least" if required_args_count != len(cmd_specs) else "" - msg = "Missing arguments: expected{} {}".format(phrase, required_args_count) - raise SuricataCommandException("L{}: {}".format(get_linenumber(), msg)) - except ValueError as ve: - raise SuricataCommandException("L{}: Erroneous arguments: {}".format(get_linenumber(), ve)) - elif c < len(full_cmd): - arguments[spec["name"]] = spec_type(full_cmd[c]) - return cmd, arguments - - def parse_command(self, command): - arguments = None - cmd = command.split()[0] if command else None - if cmd in self.cmd_list: - if cmd in self.fn_commands: - cmd, arguments = getattr(self, "execute")(command=command) - else: - raise SuricataCommandException("L{}: Unknown command: {}".format(get_linenumber(), command)) - return cmd, arguments - - def interactive(self): - print("Command list: " + ", ".join(self.cmd_list)) - try: - readline.set_completer(SuricataCompleter(self.cmd_list)) - readline.set_completer_delims(";") - readline.parse_and_bind('tab: complete') - while True: - if sys.version < '3': - command = raw_input(">>> ").strip() - else: - command = input(">>> ").strip() - if command == "quit": - break - if len(command.strip()) == 0: - continue - try: - cmd, arguments = self.parse_command(command) - except SuricataCommandException as err: - print(err) - continue - try: - cmdret = self.send_command(cmd, arguments) - except IOError as err: - # try to reconnect and resend command - print("Connection lost, trying to reconnect") - try: - self.close() - self.connect() - except (SuricataNetException, SuricataReturnException) as err: - print(err.value) - continue - cmdret = self.send_command(cmd, arguments) - except (SuricataCommandException, SuricataReturnException) as err: - print("An exception occured: " + str(err.value)) - continue - #decode json message - if cmdret["return"] == "NOK": - print("Error:") - print(json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': '))) - else: - print("Success:") - print(json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': '))) - except KeyboardInterrupt: - print("[!] Interrupted") - sys.exit(0) diff --git a/python/suricatasc/__init__.py b/python/suricatasc/__init__.py deleted file mode 100644 index 28689843ca6c..000000000000 --- a/python/suricatasc/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from suricata.sc import *