update_hooks.py
| 6.5 KB | Satir:
0
| py
Geri
import logging import shutil from pathlib import Path from defence360agent.subsys import web_server from defence360agent.subsys.panels.base import ( ModsecVendorsError, PanelException, ) from defence360agent.utils import ( atomic_rewrite, check_run, CheckRunError, file_hash, log_error_and_ignore, ) from im360 import files from im360.contracts.config import Modsec from im360.subsys import modsec_app_version_detector, waf_rules_configurator from im360.subsys.int_config import generic_panel_uses_coraza from im360.subsys.panels.base import use_modsec_lock from imav.malwarelib.subsys.malware import HackerTrapHitsSaver from .hosting_panel import HostingPanel logger = logging.getLogger(__name__) async def reload_wafd(): if Path("/usr/bin/imunify360-wsctl").is_file(): args = ["imunify360-wsctl", "reload"] else: args = ["systemctl", "reload", "imunify360-wafd"] try: await check_run(args) except CheckRunError: logger.warning("Failed to reload 'imunify360-wafd'") WP_REDIRECT_CONF_PATTERN = "*_Disable_WP_Redirect.conf" DISABLED_REDIRECT_CONF_CONTENT = "SecRuleRemoveById 33355 33357" @use_modsec_lock async def update_vendors(_, is_updated): if is_updated: hp = HostingPanel() if hp.is_installed(): await hp.apply_modsec_files_update() # rules contains empty ip-record.db, so after # updating rules, we should also update ip-record.db await _update_iprecord(_, is_updated) await HackerTrapHitsSaver.init() # Skip the inline graceful_restart() — the unconditional # restart below already reloads. await _update_account_compromise_prevention_rule_state( skip_restart=True ) await _update_app_based_rules() # A restart may already have been scheduled before modsec-rules # were downloaded, consuming the coalesce throttle window and # getting later requests dropped, so use the throttle-bypassing # restart. graceful_restart_confirmed() confirms the reload and # recovers a failed one; fall back to the legacy sync restart when # running against an older core that lacks it. confirmed_restart = getattr( web_server, "graceful_restart_confirmed", None ) if confirmed_restart is not None: await confirmed_restart() else: web_server.graceful_restart_sync() @use_modsec_lock async def update_iprecord(_, is_updated): return await _update_iprecord(_, is_updated) async def _update_iprecord(_, is_updated): if not is_updated: return def _warn(e): logger.warning("Can't update ip-record.db, reason: %s" % str(e)) hp = HostingPanel() try: vendor = await hp.get_i360_vendor_name() ip_record = await hp.build_vendor_file_path(vendor, "ip-record.db") except (ModsecVendorsError, PanelException, ValueError) as e: _warn(e) return src = ( Path(files.Index.files_path(files.IP_RECORD)) / "ip-record" / "ip-record.db" ) if src.exists(): try: if not Path(ip_record).exists() or file_hash(src) != file_hash( ip_record ): shutil.copy(src, ip_record) await web_server.graceful_restart() # Sort of a workaround to avoid redundant imports which can # cause circular dependencies if ( generic_panel_uses_coraza() or hp.__class__.__name__ == "cPanelCoraza" ): logger.info( "Reloading 'imunify360-wafd' as coraza ruleset is in" " action" ) await reload_wafd() except Exception as e: _warn(e) return else: _warn("source file is missing") return def _get_account_prevention_state(path: Path): content = path.read_text().strip() if not content: return True elif content == DISABLED_REDIRECT_CONF_CONTENT: return False else: logger.warning("Invalid content in %s: %s", path, content) return None @use_modsec_lock async def update_account_compromise_prevention_rule_state(): return await _update_account_compromise_prevention_rule_state() @log_error_and_ignore() async def _update_account_compromise_prevention_rule_state( skip_restart: bool = False, ): is_prevention_enabled = Modsec.CMS_ACCOUNT_COMPROMISE_PREVENTION hp = HostingPanel() try: vendor = await hp.get_i360_vendor_name() except (ModsecVendorsError, PanelException) as e: logger.warning(str(e)) return try: vendor_path = await hp.build_vendor_file_path(vendor, "") wp_redirect_conf_path = next( vendor_path.glob(WP_REDIRECT_CONF_PATTERN) ) except (ModsecVendorsError, StopIteration): logger.exception("Can't get %s file", WP_REDIRECT_CONF_PATTERN) return current_state = _get_account_prevention_state(wp_redirect_conf_path) if current_state != is_prevention_enabled: content = ( "" if is_prevention_enabled else DISABLED_REDIRECT_CONF_CONTENT ) atomic_rewrite(str(wp_redirect_conf_path), content, backup=False) # When called from update_vendors, the caller issues its own # restart afterwards — skip the inline httpd restart to avoid a # double reload. if not skip_restart: await web_server.graceful_restart() # Coraza's wafd is a separate daemon — the httpd/nginx restart # does not touch it — so reload_wafd() must run independently of # skip_restart. # (Sort of a workaround to avoid redundant imports which can # cause circular dependencies.) if ( generic_panel_uses_coraza() or hp.__class__.__name__ == "cPanelCoraza" ): logger.info( "Reloading 'imunify360-wafd' as coraza ruleset is in action" ) await reload_wafd() async def _update_app_based_rules(): if Modsec.APP_SPECIFIC_RULESET: try: await waf_rules_configurator.update_waf_rules_config() except ( waf_rules_configurator.NotSupportedWebserverError, modsec_app_version_detector.DatabaseNotFoundError, ) as e: logger.warning("App based rules not updated: %s", e)
Kaydet
Ctrl+S ile kaydet