import argparse import sys import tomllib import utils import logging class Config: def __init__(self): self.logger = logging.getLogger("sshd-bruteforce-detector") parser = argparse.ArgumentParser( prog="sshd-bruteforce-detector", description="detects SSH bruteforce attacks by reading sshd's logs from systemd journal", ) parser.add_argument( "-c", "--config", nargs="?", help="provide a path for the config file" ) parser.add_argument( "-m", "--max-attempts", nargs="?", help="Maximum number of failed login attempts allowed within the time window before triggering an alert. (default: 5)", ) parser.add_argument( "-w", "--window", nargs="?", help="Time window used to group failed login attempts for detection (default: 5m)", ) self.args = parser.parse_args() self.config = {} if getattr(self.args, "config", None): self.__load_config(self.args.config) def __load_config(self, path: str): try: with open(path, "rb") as f: self.config = tomllib.load(f) except FileNotFoundError: self.logger.info("Config file not found. Stopping manually...") sys.exit(1) except tomllib.TOMLDecodeError: self.logger.info( "Config file not in valid TOML format. Stopping manually..." ) sys.exit(1) def __get_config_option(self, option): opt = getattr(self.args, option, None) opt_config = self.config.get(option, None) if opt is not None: return opt elif opt_config is not None: return opt_config else: return None def get_window(self): window = self.__get_config_option("window") return utils.parse_window(window) if window is not None else 300 def get_max_attempts(self): max_attempts = self.__get_config_option("max_attempts") return int(max_attempts) if max_attempts is not None else 5