Mini Shell

Direktori : /opt/sharedrads/
Upload File :
Current File : //opt/sharedrads/blockip

#!/opt/imh-python/bin/python3
"""wrapper script for blocking/unblocking IPs
on shared via ipset

Also ensures that the IPs are safe to block by
importing the imh-whcheck module from imh-fail2ban"""


import sys
import subprocess
import syslog
from socket import AddressFamily  # pylint:disable=no-name-in-module
from argparse import ArgumentParser
import psutil
from netaddr import IPNetwork


def parse_cli():
    """
    Parse CLI arguments
    """
    parser = ArgumentParser(description="ipset wrapper for IMH shared firewall")

    mgroup = parser.add_mutually_exclusive_group(required=True)
    mgroup.add_argument(
        '--block',
        '-d',
        action='store',
        nargs=2,
        metavar=("IP/CIDR", "REASON"),
        help="IP Address or network to block + reason/comment",
    )
    mgroup.add_argument(
        '--unblock',
        '-u',
        action='store',
        metavar="IP/CIDR",
        help="IP Address or network to unblock",
    )

    return parser.parse_args()


def check_ignore(ip):
    """
    Check if @ip is safe block, or should be ignored
    This uses the imh-whcheck module from imh-fail2ban
    returns True if we should ignore, otherwise False
    """
    # pylint: disable=import-error,import-outside-toplevel
    try:
        sys.path.insert(0, '/opt/sharedrads/python')
        import imh_whcheck
    except Exception as exc:
        print("ERROR: Failed to load whcheck source:", exc)
        return False
    return imh_whcheck.check_ip(ip)


def check_local(ip):
    """
    Check if @ip is local
    """
    local_ips = [
        IPNetwork(x[0].address)
        for x in list(psutil.net_if_addrs().values())
        if x[0].family is AddressFamily.AF_INET
    ]
    for lip in local_ips:
        if ip == lip:
            return True
    return False


def write_syslog(msg):
    """
    Track actions via syslog and logging servers
    """
    syslog.openlog('blockip')
    syslog.syslog(msg)
    syslog.closelog()


def ipset(cmd: str, ip, setname='blacklist', comment=''):
    """
    Run ipset with specified @cmd for @ip on @setname
    """
    try:
        ret = subprocess.run(
            ['ipset', cmd, setname, str(ip)],
            encoding='utf-8',
            stderr=subprocess.PIPE,
            stdout=subprocess.DEVNULL,
            check=False,
        )
    except Exception as e:
        print("ERROR: Failed to execute ipset: %s" % (str(e)))
        return

    if ret.returncode == 0:
        write_syslog(f"{setname} {cmd} {ip} - {comment}")
        print(f"SUCCESS: {setname} {cmd} {ip} ({comment})")
    else:
        print(f"FAILED: {setname} {cmd} {ip}: {ret.stderr}")


def _main():
    """Entry point"""
    args = parse_cli()
    ip_list = args.block if args.block else [args.unblock]

    try:
        tip = IPNetwork(ip_list[0])
    except Exception as e:
        print("ERROR: %s" % (str(e)))
        sys.exit(1)

    if tip.size > 1024:
        print("ERROR: Using networks larger than /22 is not allowed!")
        sys.exit(2)
    elif check_local(tip):
        print(
            "ERROR: Unable to block local IP %s (what are you even doing?)"
            % (tip)
        )
        sys.exit(2)
    elif check_ignore(tip):
        print("ERROR: Unable to block IP %s in whitelist" % (tip))
        sys.exit(2)
    elif args.block:
        ipset('add', tip, comment=ip_list[1])
    elif args.unblock:
        ipset('del', tip)


if __name__ == '__main__':
    _main()

Zerion Mini Shell 1.0