]> git.ipfire.org Git - thirdparty/suricata-update.git/commitdiff
-D, --data-dir to change the data directory
authorJason Ish <ish@unx.ca>
Thu, 7 Dec 2017 13:18:06 +0000 (07:18 -0600)
committerJason Ish <ish@unx.ca>
Thu, 7 Dec 2017 22:16:40 +0000 (16:16 -0600)
By default /var/lib/suricata is used. But for various reasons
including permissions and testing it can be useful to change
this.

The data directory serves as the prefix for suricata-update
work directories, including rules/ and update/sources, and
update/cache.

Addresses issue:
https://redmine.openinfosecfoundation.org/issues/2334

suricata/update/config.py
suricata/update/main.py
suricata/update/sources.py
tests/docker-centos-7/run.sh

index 2190d887b99391b16e17a02edb13cf418a14e0a4..7aa99eadedadfab8541d0f8a17887c2cb4493628 100644 (file)
@@ -22,10 +22,16 @@ import yaml
 
 logger = logging.getLogger()
 
-DEFAULT_STATE_DIRECTORY = "/var/lib/suricata"
+DEFAULT_DATA_DIRECTORY = "/var/lib/suricata"
+
+# Cache directory - relative to the data directory.
+CACHE_DIRECTORY = os.path.join("update", "cache")
+
+# Source directory - relative to the data directory.
+SOURCE_DIRECTORY = os.path.join("update", "sources")
 
 # Configuration keys.
-STATE_DIRECTORY_KEY = "state-directory"
+DATA_DIRECTORY_KEY = "data-directory"
 CACHE_DIRECTORY_KEY = "cache-directory"
 IGNORE_KEY = "ignore"
 DISABLE_CONF_KEY = "disable-conf"
@@ -33,6 +39,7 @@ ENABLE_CONF_KEY = "enable-conf"
 MODIFY_CONF_KEY = "modify-conf"
 DROP_CONF_KEY = "drop-conf"
 LOCAL_CONF_KEY = "local"
+OUTPUT_KEY = "output"
 
 DEFAULT_UPDATE_YAML_PATH = "/etc/suricata/update.yaml"
 
@@ -64,12 +71,18 @@ def get(key):
     return None
 
 def set_state_dir(directory):
-    _config[STATE_DIRECTORY_KEY] = directory
+    _config[DATA_DIRECTORY_KEY] = directory
 
 def get_state_dir():
-    if STATE_DIRECTORY_KEY in _config:
-        return _config[STATE_DIRECTORY_KEY]
-    return DEFAULT_STATE_DIRECTORY
+    """Get the data directory. This is more of the Suricata state
+    directory than a specific Suricata-Update directory, and is used
+    as the root directory for Suricata-Update data.
+    """
+    if os.getenv("DATA_DIRECTORY"):
+        return os.getenv("DATA_DIRECTORY")
+    if DATA_DIRECTORY_KEY in _config:
+        return _config[DATA_DIRECTORY_KEY]
+    return DEFAULT_DATA_DIRECTORY
 
 def set_cache_dir(directory):
     """Set an alternate cache directory."""
@@ -79,7 +92,13 @@ def get_cache_dir():
     """Get the cache directory."""
     if CACHE_DIRECTORY_KEY in _config:
         return _config[CACHE_DIRECTORY_KEY]
-    return os.path.join(_args.output, ".cache")
+    return os.path.join(get_state_dir(), CACHE_DIRECTORY)
+
+def get_output_dir():
+    """Get the rule output directory."""
+    if OUTPUT_KEY in _config:
+        return _config[OUTPUT_KEY]
+    return os.path.join(get_state_dir(), "rules")
 
 def args():
     """Return sthe parsed argument object."""
@@ -119,7 +138,7 @@ def init(args):
             for local in args.local:
                 logger.debug("Adding local ruleset to config: %s", local)
                 _config[LOCAL_CONF_KEY].append(local)
-        elif arg == "data_dir":
+        elif arg == "data_dir" and args.data_dir:
             logger.debug("Setting data directory to %s", args.data_dir)
             _config[DATA_DIRECTORY_KEY] = args.data_dir
         elif getattr(args, arg):
index 141ffa6dafe66c64f9450b445a130f79bc62e0e8..113ba533a12c341be482cf9b1472502fc0e8955b 100644 (file)
@@ -823,7 +823,7 @@ def test_suricata(suricata_path):
         if not config.get("no-merge"):
             if not suricata.update.engine.test_configuration(
                     suricata_path, os.path.join(
-                        config.get("output"), DEFAULT_OUTPUT_RULE_FILENAME)):
+                        config.get_output_dir(), DEFAULT_OUTPUT_RULE_FILENAME)):
                 return False
         else:
             if not suricata.update.engine.test_configuration(
@@ -944,9 +944,6 @@ def _main():
     if len(sys.argv) == 1 or sys.argv[1].startswith("-"):
         sys.argv.insert(1, "update")
 
-    # Support the Python argparse style of configuration file.
-    parser = argparse.ArgumentParser()
-
     # Arguments that are common to all sub-commands.
     common_parser = argparse.ArgumentParser(add_help=False)
     common_parser.add_argument(
@@ -959,8 +956,13 @@ def _main():
         "-q", "--quiet", action="store_true", default=False,
         help="Be quiet, warning and error messages only")
     common_parser.add_argument(
-        "-o", "--output", metavar="<directory>", dest="output",
-        default="/var/lib/suricata/rules", help="Directory to write rules to")
+        "-D", "--data-dir", metavar="<directory>", dest="data_dir",
+        help="Data directory (default: /var/lib/suricata)")
+
+    # Create the root parser with the common_parser as a parent,
+    # allowing the common options to be specified before or after the
+    # sub-command.
+    parser = argparse.ArgumentParser(parents=[common_parser])
 
     subparsers = parser.add_subparsers(dest="subcommand", metavar="<command>")
 
@@ -968,6 +970,9 @@ def _main():
     update_parser = subparsers.add_parser(
         "update", add_help=False, parents=[common_parser])
 
+    update_parser.add_argument(
+        "-o", "--output", metavar="<directory>", dest="output",
+        help="Directory to write rules to")
     update_parser.add_argument("--suricata", metavar="<path>",
                                help="Path to Suricata program")
     update_parser.add_argument("--suricata-version", metavar="<version>",
@@ -1063,6 +1068,12 @@ def _main():
 
     args = parser.parse_args()
 
+    # Go verbose or quiet sooner than later.
+    if args.verbose:
+        logger.setLevel(logging.DEBUG)
+    if args.quiet:
+        logger.setLevel(logging.WARNING)
+
     try:
         config.init(args)
     except Exception as err:
@@ -1081,11 +1092,6 @@ def _main():
             logger.error("--%s not implemented", arg)
             return 1
 
-    if args.verbose:
-        logger.setLevel(logging.DEBUG)
-    if args.quiet:
-        logger.setLevel(logging.WARNING)
-
     logger.debug("This is suricata-update version %s (rev: %s); Python: %s" % (
         version, revision, sys.version.replace("\n", "- ")))
 
@@ -1278,43 +1284,40 @@ def _main():
     # Fixup flowbits.
     resolve_flowbits(rulemap, disabled_rules)
 
-    # Don't allow an empty output directory.
-    if not args.output:
-        logger.error("No output directory provided.")
-        return 1
-
     # Check that output directory exists.
-    if not os.path.exists(args.output):
+    if not os.path.exists(config.get_output_dir()):
         try:
-            os.makedirs(args.output, mode=0o770)
+            os.makedirs(config.get_output_dir(), mode=0o770)
         except Exception as err:
             logger.error(
                 "Output directory does not exist and could not be created: %s",
-                args.output)
+                config.get_output_dir())
             return 1
 
     # Check that output directory is writable.
-    if not os.access(args.output, os.W_OK):
-        logger.error("Output directory is not writable: %s", args.output)
+    if not os.access(config.get_output_dir(), os.W_OK):
+        logger.error(
+            "Output directory is not writable: %s", config.get_output_dir())
         return 1
 
     # Backup the output directory.
     logger.info("Backing up current rules.")
     backup_directory = util.mktempdir()
-    shutil.copytree(args.output, os.path.join(
+    shutil.copytree(config.get_output_dir(), os.path.join(
         backup_directory, "backup"), ignore=copytree_ignore_backup)
 
     if not args.no_merge:
         # The default, write out a merged file.
         output_filename = os.path.join(
-            args.output, DEFAULT_OUTPUT_RULE_FILENAME)
+            config.get_output_dir(), DEFAULT_OUTPUT_RULE_FILENAME)
         file_tracker.add(output_filename)
         write_merged(os.path.join(output_filename), rulemap)
     else:
         for filename in files:
             file_tracker.add(
-                os.path.join(args.output, os.path.basename(filename)))
-        write_to_directory(args.output, files, rulemap)
+                os.path.join(
+                    config.get_output_dir(), os.path.basename(filename)))
+        write_to_directory(config.get_output_dir(), files, rulemap)
 
     if args.yaml_fragment:
         file_tracker.add(args.yaml_fragment)
@@ -1338,7 +1341,8 @@ def _main():
     if not test_suricata(suricata_path):
         logger.error("Suricata test failed, aborting.")
         logger.error("Restoring previous rules.")
-        copytree(os.path.join(backup_directory, "backup"), args.output)
+        copytree(
+            os.path.join(backup_directory, "backup"), config.get_output_dir())
         return 1
 
     if not config.args().no_reload and config.get("reload-command"):
index 8acd44e190950db6cad002f5c3049667a78499f2..aa942d5b29e9324f756cad7c3c8bc03c96e4eba4 100644 (file)
@@ -32,14 +32,10 @@ logger = logging.getLogger()
 
 DEFAULT_SOURCE_INDEX_URL = "https://www.openinfosecfoundation.org/rules/index.yaml"
 SOURCE_INDEX_FILENAME = "index.yaml"
-DEFAULT_SOURCE_DIRECTORY = "/var/lib/suricata/update/sources"
 
 def get_source_directory():
     """Return the directory where source configuration files are kept."""
-    if os.getenv("SOURCE_DIRECTORY"):
-        return os.getenv("SOURCE_DIRECTORY")
-    else:
-        return DEFAULT_SOURCE_DIRECTORY
+    return os.path.join(config.get_state_dir(), config.SOURCE_DIRECTORY)
 
 def get_index_filename():
     return os.path.join(config.get_cache_dir(), SOURCE_INDEX_FILENAME)
index c4599b8352733c40067539e0a237122e250341b0..23e52f0c76da7ef9e093b17954ab40c551abf07e 100755 (executable)
@@ -12,7 +12,7 @@ test_commands() {
     test -e /var/lib/suricata/rules/suricata.rules
 
     suricata-update update-sources
-    test -e /var/lib/suricata/rules/.cache/index.yaml
+    test -e /var/lib/suricata/update/cache/index.yaml
 
     suricata-update enable-source oisf/trafficid
     test -e /var/lib/suricata/update/sources/et-open.yaml