PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /opt/support/lib/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //opt/support/lib/firewall_tools.py |
from typing import Union, Literal from pathlib import Path import re import subprocess import netaddr from output import err_exit, print_listed, warn from run_cmd import is_exe, which from rads.color import yellow def fw_info() -> tuple[ Literal['APF', 'CSF', 'ipset+fail2ban'], Literal['/usr/local/sbin/apf', '/usr/sbin/csf', None], Union[list[dict[str, str]], str], ]: """Yields a tuple of fw_name, fw_command, fw_data. fw_name will be "APF", "CSF", or "ipset+fail2ban". If fw_name was "APF" or "CSF", fw_command will be the path to its exe. If fw_name was "APF" or "CSF", fw_data will be the contents of its deny file. Otherwise, fw_data will be a list of dicts containing "listname" and "ip". Returns: tuple[str, str | None, list[dict[str, str] | None]]: see above """ if is_exe('/usr/local/sbin/apf'): fw_cmd = '/usr/local/sbin/apf' deny_file = Path('/etc/apf/deny_hosts.rules') name = 'APF' elif is_exe('/usr/sbin/csf'): fw_cmd = '/usr/sbin/csf' deny_file = Path('/etc/csf/csf.deny') name = 'CSF' elif is_exe('/opt/imh-python/bin/fail2ban-client') and which('ipset'): name = 'ipset+fail2ban' deny_file = None fw_cmd = None else: err_exit('Cannot identify firewall') if deny_file is None: deny_data = list(read_ipset_save()) else: try: deny_data = deny_file.read_text(encoding='utf-8') except FileNotFoundError: err_exit(f'Cannot read {deny_file}. Firewall is misconfigured.') return name, fw_cmd, deny_data def read_ipset_save(): irgx = re.compile(r'add (?P<listname>[a-zA-Z0-9\-_]+) (?P<ip>[0-9\./]+)$') with subprocess.Popen( ['ipset', 'save'], encoding='utf-8', stdout=subprocess.PIPE, universal_newlines=True, ) as proc: for line in proc.stdout: if match := irgx.match(line.rstrip()): yield match.groupdict() def ipset_list_action( listname: str, ) -> Literal['ACCEPT', 'DROP', 'DENY', 'UNKNOWN']: """Check whether an ipset list is set to ACCEPT, DROP, or DENY""" try: iptables = subprocess.check_output( ['iptables', '-nL'], encoding='utf-8' ) except (OSError, subprocess.CalledProcessError): err_exit('Failed to execute iptables to determine list type') ipt_data = [x for x in iptables.splitlines() if x.find('match-set') > 0] for tline in ipt_data: if listname == tline.split()[6]: return tline.split()[0] return 'UNKNOWN' def ipset_fail2ban_check( fw_data: list[dict[str, str]], ipaddr: netaddr.IPAddress ) -> tuple[bool, Union[str, None]]: """Check deny_data ``fw_info()`` for an IP address. If found, return whether it's blocked and in what fail2ban list if it was automatically blocked Args: fw_data (list[dict[str, str]]): third arg returned by ``fw_info()`` ipaddr (netaddr.IPAddress): IP address to check Returns: tuple[bool, str | None]]: if blocked and in what fail2ban list if any """ list_name = None for tnet in fw_data: try: listed = ipaddr in netaddr.IPNetwork(tnet['ip']) if listed: list_name = tnet['listname'] break except netaddr.AddrFormatError: continue list_action = ipset_list_action(list_name) if not listed: print_listed(ipaddr, False, 'any ipset or fail2ban list') return False, None print_listed(ipaddr, True, f'the {list_name} {list_action} list') if list_action == 'ACCEPT': warn(f'{ipaddr} is NOT BLOCKED. It is whitelisted.', color=yellow) return False, None if list_name.startswith('f2b-'): warn( 'Automatically blocked by fail2ban in jail:', list_name.replace('f2b-', ''), color=yellow, ) return listed, list_name.replace('f2b-', '') return listed, None def check_iptables(ipaddr: netaddr.IPAddress) -> bool: """Search iptables -nL for a line containing an IP which does not start with ACCEPT""" try: fw_data = subprocess.check_output(['iptables', '-nL'], encoding='utf-8') except (OSError, subprocess.CalledProcessError): # stderr will print to tty err_exit('could not run iptables -nL') for line in fw_data.splitlines(): if not line.startswith('ACCEPT') and str(ipaddr) in line: return True return False