129 lines
4.6 KiB
Python
Executable File
129 lines
4.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import sys
|
|
import logging
|
|
from logger import logger
|
|
import log_statistics
|
|
import reader
|
|
import parser
|
|
import argparse
|
|
from enum import StrEnum
|
|
|
|
class Commands(StrEnum):
|
|
PARSE = "parse"
|
|
IPV4 = "ipv4",
|
|
USER = "user",
|
|
TYPE = "type",
|
|
RANDOM = "random",
|
|
DURATION = "duration",
|
|
FREQ = "freq"
|
|
|
|
def main(args):
|
|
stdout_handler = logging.StreamHandler(sys.stdout)
|
|
stdout_handler.addFilter(lambda log: log.levelno <= logging.WARNING)
|
|
stdout_handler.setLevel(logging.DEBUG)
|
|
stdout_handler.setFormatter(logging.Formatter('%(levelname)s - %(name)s - %(message)s'))
|
|
|
|
stderr_handler = logging.StreamHandler(sys.stderr)
|
|
stderr_handler.setLevel(logging.ERROR)
|
|
stderr_handler.setFormatter(logging.Formatter('%(levelname)s - %(name)s - %(message)s'))
|
|
|
|
logger.addHandler(stdout_handler)
|
|
logger.addHandler(stderr_handler)
|
|
|
|
if args.log_level == "NONE":
|
|
logger.disabled = True
|
|
else:
|
|
logger.setLevel(args.log_level)
|
|
|
|
try:
|
|
logs = reader.read_logs(args.filename)
|
|
except:
|
|
logger.critical(f"Could not open file {args.filename}")
|
|
exit(1)
|
|
|
|
if args.subcommand == Commands.PARSE:
|
|
for line in logs:
|
|
print(f"{line.timestamp.strftime('%d/%m:%H:%M:%S')};{line.hostname};{line.pid};{line.message}")
|
|
#1.1.2
|
|
if args.subcommand == Commands.IPV4:
|
|
for line in logs:
|
|
print(*parser.get_ipv4s_from_log(line), sep=", ")
|
|
#1.1.3
|
|
elif args.subcommand == Commands.USER:
|
|
for line in logs:
|
|
print(parser.get_user_from_log(line) or "")
|
|
#1.1.4
|
|
elif args.subcommand == Commands.TYPE:
|
|
for line in logs:
|
|
print(parser.get_message_type(line.message))
|
|
#1.3.1
|
|
elif args.subcommand == Commands.RANDOM:
|
|
random_logs = log_statistics.random_user_logs(list(logs), args.n)
|
|
for line in random_logs:
|
|
print(line.original_line)
|
|
#1.3.2
|
|
elif args.subcommand == Commands.DURATION:
|
|
log_list = list(logs)
|
|
if args.group_by_users:
|
|
durations_by_user = log_statistics.get_average_session_duration_by_user(log_list)
|
|
for (username, (avg_time, stdev)) in sorted(durations_by_user.items(), key=lambda x: x[1], reverse=True):
|
|
print(f"{username}: average={avg_time:.4f}s, stdev={stdev:.4f}s")
|
|
else:
|
|
(avg_time, stdev) = log_statistics.get_average_session_duration(log_list)
|
|
print(f"average={avg_time:.4f}s, stdev={stdev:.4f}s")
|
|
#1.3.3
|
|
elif args.subcommand == Commands.FREQ:
|
|
log_list = list(logs)
|
|
(most, least) = log_statistics.get_most_and_least_frequent_user(log_list)
|
|
if most and least:
|
|
print(f"most frequent user - {most[0]} - {most[1]} login(s)")
|
|
print(f"least frequent user - {least[0]} - {least[1]} login(s)")
|
|
else:
|
|
print("could not determine most and least frequent user")
|
|
|
|
|
|
def positive_int(arg):
|
|
try:
|
|
val = int(arg)
|
|
except ValueError:
|
|
raise argparse.ArgumentTypeError("Must be an integer")
|
|
if val < 0:
|
|
raise argparse.ArgumentTypeError("Must be greater than or equal to 0")
|
|
return val
|
|
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser(description="Script for analyzing sshd logs")
|
|
|
|
#1.4.1
|
|
parser.add_argument("filename", help="Path of the file to be read")
|
|
#1.4.2
|
|
parser.add_argument("--log-level", choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", "NONE"], default="INFO", help="Level of logging, default is info")
|
|
|
|
|
|
#1.4.3
|
|
subparsers = parser.add_subparsers(dest="subcommand", title="subcommands", required=True)
|
|
|
|
subparsers.add_parser(Commands.PARSE, help="Parse logs into semicolon separated structure")
|
|
|
|
subparsers.add_parser(Commands.IPV4, help="Get all IPv4 addresses from log messsages")
|
|
|
|
subparsers.add_parser(Commands.USER, help="Extract user from log messages")
|
|
|
|
subparsers.add_parser(Commands.TYPE, help="Get type of log message")
|
|
|
|
random_parser = subparsers.add_parser(Commands.RANDOM, help="Get specified amount (default is 3) of random logs from random user")
|
|
random_parser.add_argument("-n", type=positive_int, default=3, help="Amount of random logs to be returned")
|
|
|
|
duration_parser = subparsers.add_parser(Commands.DURATION, help="Get average session duration and standard deviation")
|
|
duration_parser.add_argument("--group-by-users", action="store_true", help="Whether session durations should be calculated for each user separately")
|
|
|
|
subparsers.add_parser(Commands.FREQ, help="Get most and least frequently logging users")
|
|
|
|
return parser.parse_args()
|
|
|
|
if __name__ == "__main__":
|
|
args = parse_args()
|
|
main(args) |