summaryrefslogtreecommitdiffstats
path: root/suricata/update/config.py
diff options
context:
space:
mode:
Diffstat (limited to 'suricata/update/config.py')
-rw-r--r--suricata/update/config.py266
1 files changed, 266 insertions, 0 deletions
diff --git a/suricata/update/config.py b/suricata/update/config.py
new file mode 100644
index 0000000..ad95996
--- /dev/null
+++ b/suricata/update/config.py
@@ -0,0 +1,266 @@
+# Copyright (C) 2017 Open Information Security Foundation
+# Copyright (c) 2015-2017 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 os.path
+import logging
+
+import yaml
+
+import suricata.update.engine
+from suricata.update.exceptions import ApplicationError
+
+try:
+ from suricata.config import defaults
+ has_defaults = True
+except:
+ has_defaults = False
+
+logger = logging.getLogger()
+
+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.
+DATA_DIRECTORY_KEY = "data-directory"
+CACHE_DIRECTORY_KEY = "cache-directory"
+IGNORE_KEY = "ignore"
+DISABLE_CONF_KEY = "disable-conf"
+ENABLE_CONF_KEY = "enable-conf"
+MODIFY_CONF_KEY = "modify-conf"
+DROP_CONF_KEY = "drop-conf"
+LOCAL_CONF_KEY = "local"
+OUTPUT_KEY = "output"
+DIST_RULE_DIRECTORY_KEY = "dist-rule-directory"
+
+if has_defaults:
+ DEFAULT_UPDATE_YAML_PATH = os.path.join(defaults.sysconfdir, "update.yaml")
+else:
+ DEFAULT_UPDATE_YAML_PATH = "/etc/suricata/update.yaml"
+
+DEFAULT_SURICATA_YAML_PATH = [
+ "/etc/suricata/suricata.yaml",
+ "/usr/local/etc/suricata/suricata.yaml",
+ "/etc/suricata/suricata-debian.yaml"
+]
+
+if has_defaults:
+ DEFAULT_DIST_RULE_PATH = [
+ defaults.datarulesdir,
+ "/etc/suricata/rules",
+ ]
+else:
+ DEFAULT_DIST_RULE_PATH = [
+ "/etc/suricata/rules",
+ ]
+
+DEFAULT_CONFIG = {
+ "sources": [],
+ LOCAL_CONF_KEY: [],
+
+ # The default file patterns to ignore.
+ "ignore": [
+ "*deleted.rules",
+ ],
+}
+
+_args = None
+_config = {}
+
+# The filename the config was read from, if any.
+filename = None
+
+def has(key):
+ """Return true if a configuration key exists."""
+ return key in _config
+
+def set(key, value):
+ """Set a configuration value."""
+ _config[key] = value
+
+def get(key):
+ """Get a configuration value."""
+ if key in _config:
+ return _config[key]
+ return None
+
+def set_state_dir(directory):
+ _config[DATA_DIRECTORY_KEY] = directory
+
+def get_state_dir():
+ """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."""
+ _config[CACHE_DIRECTORY_KEY] = directory
+
+def get_cache_dir():
+ """Get the cache directory."""
+ if CACHE_DIRECTORY_KEY in _config:
+ return _config[CACHE_DIRECTORY_KEY]
+ 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."""
+ return _args
+
+def get_arg(key):
+ key = key.replace("-", "_")
+ if hasattr(_args, key):
+ val = getattr(_args, key)
+ if val not in [[], None]:
+ return val
+ return None
+
+def init(args):
+ global _args
+ global filename
+
+ _args = args
+ _config.update(DEFAULT_CONFIG)
+
+ if args.config:
+ logger.info("Loading %s", args.config)
+ with open(args.config, "rb") as fileobj:
+ config = yaml.safe_load(fileobj)
+ if config:
+ _config.update(config)
+ filename = args.config
+ elif os.path.exists(DEFAULT_UPDATE_YAML_PATH):
+ logger.info("Loading %s", DEFAULT_UPDATE_YAML_PATH)
+ with open(DEFAULT_UPDATE_YAML_PATH, "rb") as fileobj:
+ config = yaml.safe_load(fileobj)
+ if config:
+ _config.update(config)
+ filename = DEFAULT_UPDATE_YAML_PATH
+
+ # Apply command line arguments to the config.
+ for arg in vars(args):
+ if arg == "local":
+ for local in args.local:
+ logger.debug("Adding local ruleset to config: %s", local)
+ _config[LOCAL_CONF_KEY].append(local)
+ 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) is not None:
+ key = arg.replace("_", "-")
+ val = getattr(args, arg)
+ logger.debug("Setting configuration value %s -> %s", key, val)
+ _config[key] = val
+
+ # Find and set the path to suricata if not provided.
+ if "suricata" in _config:
+ if not os.path.exists(_config["suricata"]):
+ raise ApplicationError(
+ "Configured path to suricata does not exist: %s" % (
+ _config["suricata"]))
+ else:
+ suricata_path = suricata.update.engine.get_path()
+ if not suricata_path:
+ logger.warning("No suricata application binary found on path.")
+ else:
+ _config["suricata"] = suricata_path
+
+ if "suricata" in _config:
+ build_info = suricata.update.engine.get_build_info(_config["suricata"])
+
+ # Set the first suricata.yaml to check for to the one in the
+ # --sysconfdir provided by build-info.
+ if not "suricata_conf" in _config and "sysconfdir" in build_info:
+ DEFAULT_SURICATA_YAML_PATH.insert(
+ 0, os.path.join(
+ build_info["sysconfdir"], "suricata/suricata.yaml"))
+
+ # Amend the path to look for Suricata provided rules based on
+ # the build info. As we are inserting at the front, put the
+ # highest priority path last.
+ if "sysconfdir" in build_info:
+ DEFAULT_DIST_RULE_PATH.insert(
+ 0, os.path.join(build_info["sysconfdir"], "suricata/rules"))
+ if "datarootdir" in build_info:
+ DEFAULT_DIST_RULE_PATH.insert(
+ 0, os.path.join(build_info["datarootdir"], "suricata/rules"))
+
+ # Set the data-directory prefix to that of the --localstatedir
+ # found in the build-info.
+ if not DATA_DIRECTORY_KEY in _config and "localstatedir" in build_info:
+ data_directory = os.path.join(
+ build_info["localstatedir"], "lib/suricata")
+ logger.info("Using data-directory %s.", data_directory)
+ _config[DATA_DIRECTORY_KEY] = data_directory
+
+ # Fixup the default locations for Suricata-Update configuration files, but only if
+ # they exist, otherwise keep the defaults.
+ conf_search_path = ["/etc"]
+ if "sysconfdir" in build_info:
+ sysconfdir = build_info["sysconfdir"]
+ if not sysconfdir in conf_search_path:
+ conf_search_path.insert(0, sysconfdir)
+ configs = (
+ ("disable-conf", "disable.conf"),
+ ("enable-conf", "enable.conf"),
+ ("drop-conf", "drop.conf"),
+ ("modify-conf", "modify.conf"),
+ )
+ for key, filename in configs:
+ if getattr(args, key.replace("-", "_"), None) is not None:
+ continue
+ if _config.get(key) is not None:
+ continue
+ for conf_dir in conf_search_path:
+ config_path = os.path.join(conf_dir, "suricata", filename)
+ logger.debug("Looking for {}".format(config_path))
+ if os.path.exists(config_path):
+ logger.debug("Found {}".format(config_path))
+ logger.debug("Using {} for {}".format(config_path, key))
+ _config[key] = config_path
+ break
+
+ # If suricata-conf not provided on the command line or in the
+ # configuration file, look for it.
+ if not "suricata-conf" in _config:
+ for conf in DEFAULT_SURICATA_YAML_PATH:
+ if os.path.exists(conf):
+ logger.info("Using Suricata configuration %s" % (conf))
+ _config["suricata-conf"] = conf
+ break
+
+ if not DIST_RULE_DIRECTORY_KEY in _config:
+ for path in DEFAULT_DIST_RULE_PATH:
+ if os.path.exists(path):
+ logger.info("Using %s for Suricata provided rules.", path)
+ _config[DIST_RULE_DIRECTORY_KEY] = path
+ break