# 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. # This module contains functions for command line parsers for # suricata-update import argparse import sys from suricata.update import commands, config from suricata.update.version import version try: from suricata.update.revision import revision except: revision = None default_update_yaml = config.DEFAULT_UPDATE_YAML_PATH show_advanced = False if "-s" in sys.argv or "--show-advanced" in sys.argv: show_advanced = True # Global arguments - command line options for suricata-update global_arg = [ (("-v", "--verbose"), {'action': 'store_true', 'default': None, 'help': "Be more verbose"}), (("-q", "--quiet"), {'action': 'store_true', 'default': None, 'help': "Be quiet, warning and error messages only"}), (("-D", "--data-dir"), {'metavar': '', 'dest': 'data_dir', 'help': "Data directory (default: /var/lib/suricata)"}), (("-c", "--config"), {'metavar': '', 'help': "configuration file (default: %s)" % (default_update_yaml)}), (("--suricata-conf",), {'metavar': '', 'help': "configuration file (default: /etc/suricata/suricata.yaml)"}), (("--suricata",), {'metavar': '', 'help': "Path to Suricata program"}), (("--suricata-version",), {'metavar': '', 'help': "Override Suricata version"}), (("--user-agent",), {'metavar': '', 'help': "Set custom user-agent string" if show_advanced else argparse.SUPPRESS}), (("--no-check-certificate",), {'action': 'store_true', 'default': None, 'help': "Disable server SSL/TLS certificate verification" if show_advanced else argparse.SUPPRESS}), (("-V", "--version"), {'action': 'store_true', 'default': False, 'help': "Display version"}), (("-s","--show-advanced"), {'action': 'store_true', 'help': "Show advanced options"}), ] # Update arguments - command line options for suricata-update update_arg = [ (("-o", "--output"), {'metavar': '', 'dest': 'output', 'help': "Directory to write rules to"}), (("-f", "--force"), {'action': 'store_true', 'default': False, 'help': "Force operations that might otherwise be skipped"}), (("--yaml-fragment",), {'metavar': '', 'help': "Output YAML fragment for rule inclusion" if show_advanced else argparse.SUPPRESS}), (("--url",), {'metavar': '', 'action': 'append', 'default': [], 'help': "URL to use instead of auto-generating one " "(can be specified multiple times)" if show_advanced else argparse.SUPPRESS}), (("--local",), {'metavar': '', 'action': 'append', 'default': [], 'help': "Local rule files or directories " "(can be specified multiple times)" if show_advanced else argparse.SUPPRESS}), (("--sid-msg-map",), {'metavar': '', 'help': "Generate a sid-msg.map file" if show_advanced else argparse.SUPPRESS}), (("--sid-msg-map-2",), {'metavar': '', 'help': "Generate a v2 sid-msg.map file" if show_advanced else argparse.SUPPRESS}), (("--disable-conf",), {'metavar': '', 'help': "Filename of rule disable filters"}), (("--enable-conf",), {'metavar': '', 'help': "Filename of rule enable filters"}), (("--modify-conf",), {'metavar': '', 'help': "Filename of rule modification filters"}), (("--drop-conf",), {'metavar': '', 'help': "Filename of drop rule filters"}), (("--ignore",), {'metavar': '', 'action': 'append', 'default': None, 'help': "Filenames to ignore " "(can be specified multiple times; default: *deleted.rules)" if show_advanced else argparse.SUPPRESS}), (("--no-ignore",), {'action': 'store_true', 'default': False, 'help': "Disables the ignore option." if show_advanced else argparse.SUPPRESS}), (("--threshold-in",), {'metavar': '', 'help': "Filename of rule thresholding configuration" if show_advanced else argparse.SUPPRESS}), (("--threshold-out",), {'metavar': '', 'help': "Output of processed threshold configuration" if show_advanced else argparse.SUPPRESS}), (("--dump-sample-configs",), {'action': 'store_true', 'default': False, 'help': "Dump sample config files to current directory" if show_advanced else argparse.SUPPRESS}), (("--etopen",), {'action': 'store_true', 'help': "Use ET-Open rules (default)" if show_advanced else argparse.SUPPRESS}), (("--reload-command",), {'metavar': '', 'help': "Command to run after update if modified" if show_advanced else argparse.SUPPRESS}), (("--no-reload",), {'action': 'store_true', 'default': False, 'help': "Disable reload"}), (("-T", "--test-command"), {'metavar': '', 'help': "Command to test Suricata configuration" if show_advanced else argparse.SUPPRESS}), (("--no-test",), {'action': 'store_true', 'default': None, 'help': "Disable testing rules with Suricata"}), (("--no-merge",), {'action': 'store_true', 'default': False, 'help': "Do not merge the rules into a single file" if show_advanced else argparse.SUPPRESS}), (("--offline",), {'action': 'store_true', 'help': "Run offline using most recent cached rules"}), (("--fail",), {'action': 'store_true', 'help': "Strictly fail and exit in case of an error"}), # Hidden argument, --now to bypass the timebased bypass of # updating a ruleset. (("--now",), {'default': False, 'action': 'store_true', 'help': argparse.SUPPRESS}), # The Python 2.7 argparse module does prefix matching which can be # undesirable. Reserve some names here that would match existing # options to prevent prefix matching. (("--disable",), {'default': False, 'help': argparse.SUPPRESS}), (("--enable",), {'default': False, 'help': argparse.SUPPRESS}), (("--modify",), {'default': False, 'help': argparse.SUPPRESS}), (("--drop",), {'default': False, 'help': argparse.SUPPRESS}) ] def parse_global(): global_parser = argparse.ArgumentParser(add_help=False) for arg, opts in global_arg: global_parser.add_argument(*arg, **opts) return global_parser def parse_update(subparsers, global_parser): # The "update" (default) sub-command parser. update_parser = subparsers.add_parser( "update", add_help=True, parents=[global_parser], formatter_class=argparse.RawDescriptionHelpFormatter) for arg, opts in update_arg: update_parser.add_argument(*arg, **opts) return update_parser def parse_commands(subparsers, global_parser): commands.listsources.register(subparsers.add_parser( "list-sources", parents=[global_parser])) commands.listsources.register(subparsers.add_parser( "list-enabled-sources", parents=[global_parser])) commands.addsource.register(subparsers.add_parser( "add-source", parents=[global_parser])) commands.updatesources.register(subparsers.add_parser( "update-sources", parents=[global_parser])) commands.enablesource.register(subparsers.add_parser( "enable-source", parents=[global_parser])) commands.disablesource.register(subparsers.add_parser( "disable-source", parents=[global_parser])) commands.removesource.register(subparsers.add_parser( "remove-source", parents=[global_parser])) commands.checkversions.register(subparsers.add_parser( "check-versions", parents=[global_parser])) def parse_arg(): global_parser = parse_global() global_args, rem = global_parser.parse_known_args() if global_args.version: revision_string = " (rev: %s)" % (revision) if revision else "" print("suricata-update version {}{}".format(version, revision_string)) sys.exit(0) if not rem or rem[0].startswith("-"): rem.insert(0, "update") parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest="subcommand", metavar="") update_parser = parse_update(subparsers, global_parser) update_parser.epilog = r"""other commands: update-sources Update the source index list-sources List available sources enable-source Enable a source from the index disable-source Disable an enabled source remove-source Remove an enabled or disabled source add-source Add a new source by URL check-versions Check version of suricata-update """ parse_commands(subparsers, global_parser) args = parser.parse_args(rem) # Merge global args into args. for arg in vars(global_args): if not hasattr(args, arg): setattr(args, arg, getattr(global_args, arg)) elif hasattr(args, arg) and getattr(args, arg) is None: setattr(args, arg, getattr(global_args, arg)) return args